Author: Bleep <tomh@inxpress.net>
authorBleep <twhelvey1@home.com>
Sat, 18 Mar 2000 05:20:30 +0000 (05:20 +0000)
committerBleep <twhelvey1@home.com>
Sat, 18 Mar 2000 05:20:30 +0000 (05:20 +0000)
Log message:
Update ircu2.10 to ircu2.10.10 level merge beta into main trunk

git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/trunk@27 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

212 files changed:
.patches [deleted file]
BUGS
ChangeLog
ChangeLog.07 [new file with mode: 0644]
ChangeLog.10 [new file with mode: 0644]
INSTALL
README [new file with mode: 0644]
RELEASE.NOTES [new file with mode: 0644]
TODO [new file with mode: 0644]
config/Configure.in
config/config-sh.in
config/configure
config/configure.in
config/setup.h.in
doc/Authors
doc/exaconf.2 [new file with mode: 0644]
doc/example.conf
doc/fda.txt [new file with mode: 0644]
doc/features.txt [new file with mode: 0644]
doc/p10.html [new file with mode: 0644]
doc/readme.who
doc/rfc1413.txt [new file with mode: 0644]
doc/rfc1459.unet [new file with mode: 0644]
doc/snomask.html [new file with mode: 0644]
doc/strings.txt [new file with mode: 0644]
include/IPcheck.h
include/bsd.h [deleted file]
include/channel.h
include/class.h
include/client.h [new file with mode: 0644]
include/common.h [deleted file]
include/crule.h
include/dbuf.h
include/fda.h [new file with mode: 0644]
include/fileio.h
include/gline.h [new file with mode: 0644]
include/h.h [deleted file]
include/handlers.h [new file with mode: 0644]
include/hash.h
include/ircd.h
include/ircd_alloc.h [new file with mode: 0644]
include/ircd_chattr.h [new file with mode: 0644]
include/ircd_defs.h [new file with mode: 0644]
include/ircd_handler.h [new file with mode: 0644]
include/ircd_log.h [new file with mode: 0644]
include/ircd_osdep.h [new file with mode: 0644]
include/ircd_relay.h [new file with mode: 0644]
include/ircd_reply.h [new file with mode: 0644]
include/ircd_signal.h [new file with mode: 0644]
include/ircd_string.h [new file with mode: 0644]
include/ircd_xopen.h [new file with mode: 0644]
include/list.h
include/listener.h [new file with mode: 0644]
include/map.h
include/match.h
include/msg.h
include/numeric.h
include/numnicks.h
include/opercmds.h
include/packet.h
include/parse.h
include/patchlevel.h
include/querycmds.h
include/random.h
include/res.h
include/runmalloc.h
include/s_auth.h
include/s_bsd.h
include/s_conf.h
include/s_debug.h
include/s_err.h [deleted file]
include/s_misc.h
include/s_numeric.h
include/s_ping.h [deleted file]
include/s_serv.h
include/s_user.h
include/send.h
include/sprintf_irc.h
include/struct.h
include/support.h
include/supported.h [new file with mode: 0644]
include/sys.h
include/uping.h [new file with mode: 0644]
include/userload.h
include/version.h
include/whocmds.h
include/whowas.h
ircd/.cvsignore
ircd/IPcheck.c
ircd/Makefile.in
ircd/bsd.c [deleted file]
ircd/channel.c
ircd/chkconf.c
ircd/class.c
ircd/common.c [deleted file]
ircd/crule.c
ircd/crypt/mkpasswd.c
ircd/dbuf.c
ircd/fda.c [new file with mode: 0644]
ircd/fda_t.c [new file with mode: 0644]
ircd/fileio.c
ircd/gline.c [new file with mode: 0644]
ircd/hash.c
ircd/ircd.c
ircd/ircd_alloc.c [new file with mode: 0644]
ircd/ircd_log.c [new file with mode: 0644]
ircd/ircd_relay.c [new file with mode: 0644]
ircd/ircd_reply.c [new file with mode: 0644]
ircd/ircd_signal.c [new file with mode: 0644]
ircd/ircd_string.c [new file with mode: 0644]
ircd/ircd_xopen.c [new file with mode: 0644]
ircd/list.c
ircd/listener.c [new file with mode: 0644]
ircd/m_admin.c [new file with mode: 0644]
ircd/m_away.c [new file with mode: 0644]
ircd/m_burst.c [new file with mode: 0644]
ircd/m_close.c [new file with mode: 0644]
ircd/m_connect.c [new file with mode: 0644]
ircd/m_cprivmsg.c [new file with mode: 0644]
ircd/m_create.c [new file with mode: 0644]
ircd/m_defaults.c [new file with mode: 0644]
ircd/m_destruct.c [new file with mode: 0644]
ircd/m_desynch.c [new file with mode: 0644]
ircd/m_die.c [new file with mode: 0644]
ircd/m_endburst.c [new file with mode: 0644]
ircd/m_error.c [new file with mode: 0644]
ircd/m_gline.c [new file with mode: 0644]
ircd/m_help.c [new file with mode: 0644]
ircd/m_info.c [new file with mode: 0644]
ircd/m_invite.c [new file with mode: 0644]
ircd/m_ison.c [new file with mode: 0644]
ircd/m_join.c [new file with mode: 0644]
ircd/m_kick.c [new file with mode: 0644]
ircd/m_kill.c [new file with mode: 0644]
ircd/m_links.c [new file with mode: 0644]
ircd/m_list.c [new file with mode: 0644]
ircd/m_lusers.c [new file with mode: 0644]
ircd/m_map.c [new file with mode: 0644]
ircd/m_mode.c [new file with mode: 0644]
ircd/m_motd.c [new file with mode: 0644]
ircd/m_names.c [new file with mode: 0644]
ircd/m_nick.c [new file with mode: 0644]
ircd/m_notice.c [new file with mode: 0644]
ircd/m_oper.c [new file with mode: 0644]
ircd/m_part.c [new file with mode: 0644]
ircd/m_pass.c [new file with mode: 0644]
ircd/m_ping.c [new file with mode: 0644]
ircd/m_pong.c [new file with mode: 0644]
ircd/m_privmsg.c [new file with mode: 0644]
ircd/m_proto.c [new file with mode: 0644]
ircd/m_quit.c [new file with mode: 0644]
ircd/m_rehash.c [new file with mode: 0644]
ircd/m_restart.c [new file with mode: 0644]
ircd/m_rping.c [new file with mode: 0644]
ircd/m_rpong.c [new file with mode: 0644]
ircd/m_server.c [new file with mode: 0644]
ircd/m_settime.c [new file with mode: 0644]
ircd/m_silence.c [new file with mode: 0644]
ircd/m_squit.c [new file with mode: 0644]
ircd/m_stats.c [new file with mode: 0644]
ircd/m_time.c [new file with mode: 0644]
ircd/m_tmpl.c [new file with mode: 0644]
ircd/m_topic.c [new file with mode: 0644]
ircd/m_trace.c [new file with mode: 0644]
ircd/m_user.c [new file with mode: 0644]
ircd/m_userhost.c [new file with mode: 0644]
ircd/m_userip.c [new file with mode: 0644]
ircd/m_version.c [new file with mode: 0644]
ircd/m_wallchops.c [new file with mode: 0644]
ircd/m_wallops.c [new file with mode: 0644]
ircd/m_who.c [new file with mode: 0644]
ircd/m_whois.c [new file with mode: 0644]
ircd/m_whowas.c [new file with mode: 0644]
ircd/map.c
ircd/match.c
ircd/numnicks.c
ircd/opercmds.c
ircd/os_bsd.c [new file with mode: 0644]
ircd/os_generic.c [new file with mode: 0644]
ircd/os_linux.c [new file with mode: 0644]
ircd/os_solaris.c [new file with mode: 0644]
ircd/packet.c
ircd/parse.c
ircd/querycmds.c
ircd/random.c
ircd/res.c
ircd/runmalloc.c
ircd/s_auth.c
ircd/s_bsd.c
ircd/s_conf.c
ircd/s_debug.c
ircd/s_err.c
ircd/s_misc.c
ircd/s_numeric.c
ircd/s_ping.c [deleted file]
ircd/s_serv.c
ircd/s_user.c
ircd/send.c
ircd/sprintf_irc.c
ircd/support.c
ircd/table_gen.c [new file with mode: 0644]
ircd/test/Makefile [new file with mode: 0644]
ircd/test/ircd_chattr.0.dat [new file with mode: 0644]
ircd/test/ircd_chattr_t.c [new file with mode: 0644]
ircd/test/ircd_string_t.c [new file with mode: 0644]
ircd/uping.c [new file with mode: 0644]
ircd/userload.c
ircd/version.c.SH
ircd/whocmds.c
ircd/whowas.c
tools/autodoc.py [new file with mode: 0644]
tools/untabify [new file with mode: 0644]

diff --git a/.patches b/.patches
deleted file mode 100644 (file)
index 915a87a..0000000
--- a/.patches
+++ /dev/null
@@ -1 +0,0 @@
-ircu2.10.07+.09
diff --git a/BUGS b/BUGS
index 2ca133755e40a24678e11c8a0e8ce42ed140d9d7..c5c9519fc0a168ea0679e255108f556068fdf1c1 100644 (file)
--- a/BUGS
+++ b/BUGS
@@ -1,8 +1,6 @@
 #
-# $Id: BUGS,v 1.2 1999-12-11 08:54:13 bleep Exp $
+# BUGS file for ircu2.10
 #
-# Undernet ircu BUGS File
-# Please put information about known bugs here, if the bug has been resolved
-# please comment the entry with "(fixed)"
+# $Id: BUGS,v 1.3 2000-03-18 05:20:27 bleep Exp $
 #
 
index 8753262bd50a5779b4296a7e9faaf5702d388862..158972721a50adc908fb7ec6538e15431e48b7c1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,32 +1,8 @@
 #
-# ChangeLog for Undernet ircu Servers
+# ChangeLog for ircu2.10.11
 #
-# $Id: ChangeLog,v 1.12 2000-03-18 01:59:56 bleep Exp $
+# $Id: ChangeLog,v 1.13 2000-03-18 05:20:27 bleep Exp $
 #
-# Please insert new entries on the top of the list, a one or two line comment
-# is sufficient. Please include your name on the entries we know who to blame.
-# Please keep lines < 80 chars.
-#-------------------------------------------------------------------------------
-* Added hostname hiding compatible with ircu2.10.10 to allow host hiding
-  for transitioning services, back out pline8 for now. --Bleep
-* Fixed default behavior for BADCHAN. supposed to DEFAULT yes, however
-  should not change each time a make config is done. -- WT
-* doc/readme.www: add Runs link update patch for linux info. --Bleep
-* channel.c, channel.h: add David M's fixup for local channel oper overrides.
-  --Bleep
-* s_misc.c (date): add Runs Y2K patch --Bleep
-* hash.c (hChangeClient): bug fix. If the client pointer matched the first
-  pointer in the bucket, the change was ignored (returned 0), leaving stale
-  values in the hash table, eventually causing the server to die for mysterious
-  reasons. Bug discovered by Quant and Isomer --Bleep
-* config-sh.in, channel.h, numeric.h, channel.c, s_debug.c, s_err.c:
-  add lchanmode patch by CaptJay, add symbols to incredibly long
-  feature string. Bump patchlevel to .03 --Bleep
-* list.h list.c s_conf.h s_conf.c opercmds.c:
-  badchan patch 2 seperate settings, allow global, and allow local.
-  currently allow_local is 'unapproved' for use on undernet. --WildThang
-* ircd.h, s_serv.h, s_debug.h, ircd.c, s_user.c, s_bsd.c:
-  removed STAT_MASTER/BOOT_OPER code, original patch by Isomer --Bleep
-* s_user.c (m_nick): removed redundant check for acptr --Bleep
-* ChangeLog (file): added ChangeLog, and BUGS files, import to ircu2.10 --Bleep
-
+# Insert new changes at beginning of the change list.
+#
+* new version tag
diff --git a/ChangeLog.07 b/ChangeLog.07
new file mode 100644 (file)
index 0000000..f5ceb2e
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# ChangeLog for Undernet ircu Servers
+#
+# $Id: ChangeLog.07,v 1.1 2000-03-18 05:20:28 bleep Exp $
+#
+# Please insert new entries on the top of the list, a one or two line comment
+# is sufficient. Please include your name on the entries we know who to blame.
+# Please keep lines < 80 chars.
+#-------------------------------------------------------------------------------
+* Added hostname hiding compatible with ircu2.10.10 to allow host hiding
+  for transitioning services, back out pline8 for now. --Bleep
+* Fixed default behavior for BADCHAN. supposed to DEFAULT yes, however
+  should not change each time a make config is done. -- WT
+* doc/readme.www: add Runs link update patch for linux info. --Bleep
+* channel.c, channel.h: add David M's fixup for local channel oper overrides.
+  --Bleep
+* s_misc.c (date): add Runs Y2K patch --Bleep
+* hash.c (hChangeClient): bug fix. If the client pointer matched the first
+  pointer in the bucket, the change was ignored (returned 0), leaving stale
+  values in the hash table, eventually causing the server to die for mysterious
+  reasons. Bug discovered by Quant and Isomer --Bleep
+* config-sh.in, channel.h, numeric.h, channel.c, s_debug.c, s_err.c:
+  add lchanmode patch by CaptJay, add symbols to incredibly long
+  feature string. Bump patchlevel to .03 --Bleep
+* list.h list.c s_conf.h s_conf.c opercmds.c:
+  badchan patch 2 seperate settings, allow global, and allow local.
+  currently allow_local is 'unapproved' for use on undernet. --WildThang
+* ircd.h, s_serv.h, s_debug.h, ircd.c, s_user.c, s_bsd.c:
+  removed STAT_MASTER/BOOT_OPER code, original patch by Isomer --Bleep
+* s_user.c (m_nick): removed redundant check for acptr --Bleep
+* ChangeLog (file): added ChangeLog, and BUGS files, import to ircu2.10 --Bleep
+
diff --git a/ChangeLog.10 b/ChangeLog.10
new file mode 100644 (file)
index 0000000..1059c7e
--- /dev/null
@@ -0,0 +1,548 @@
+#
+# ChangeLog for ircu2.10.10
+#
+# $Id: ChangeLog.10,v 1.1 2000-03-18 05:20:28 bleep Exp $
+#
+# Insert new changes at beginning of the change list.
+#
+* Don't bother doing hostname lookup or setting me.sockhost
+  since we never want to display it there is really no reason
+  to have the info. --Bleep
+* Bugfix broken N:line check in chkconf --Maniac
+* Bugfix, fix clients occasionally getting stuck in IPcheck
+  code. Add note to members in client struct that aren't used
+  for any remote client code, didn't want to actually move them
+  this close to release (paranoia) --Bleep
+* A few little cleanups in check_pings, removed yet another
+  address display. --Bleep
+* Bugfix, autoconnects displaying server IP address to opers.
+  --Bleep
+* Remove names from /stats p, since its always the server
+  name from the M:line anyhow, (redundant information)
+  --Bleep
+* Unborked throttling. --Bleep
+* Fix two stupid bugs, related to IP mismatch kills. --Bleep
+* Clean up configuration, make it a bit easier for admins to
+  turn off asserts and heap checking code. Moved host name dns
+  query for listener virtual host ports to dead code and use
+  me.name for the listener name (no sense in looking up the name
+  if we don't want to display it). Change direct bump of unknowns
+  in s_bsd.c to Count_newunknowns(UserStats) for consistency.
+  --Bleep
+* Added option to kill any connecting client with a forward and
+  reverse DNS mismatch. Fixed bug in s_auth that that caused
+  incorrect counts for unknown clients. Replaced missing server
+  notice for SNO_IPMISMATCH. --Bleep
+* Added a few more little name tweaks, no sense in looking up
+  the hostname in the conf if no one knows it. --Bleep
+* Moved to beta archive, bumped patchlevel, fixed message for
+  lost C:line in s_conf.c (I don't think I've ever seen this happen)
+  --Bleep
+* Finished host hiding changes, it should not be possible for any
+  online user to discover the real hostname or IP address of any
+  connected or unconnected server listed in the configuration. This
+  applies to opers and regular users. The name in the M:line is the
+  name used for connecting and all informational messages. --Bleep
+* Removed code in dbuf.c that flushes the dbufs if the server runs out
+  it looks like a fully loaded server may not be able to handle a net
+  break without shedding a few clients. --Bleep
+* Finish IP address cleanup, alpha should be clean for not displaying
+  server hosts or IP addresses to users now. This needs to be verified.
+  Changed version to u2.10.10 per Isomers suggestion. --Bleep
+* Remove server IP address from info line for connecting servers.  
+  This almost completes the IP address hiding changes for alpha, there
+  are still a few stats commands available to users that will show the
+  server addresses, but they can be easily disabled or only show '*'s
+  to non-opers.  --Bleep
+* Fix possible (but not likely) memory leak in debug allocator, couldn't
+  find the "meg a minute" problem, using the debug allocator on the
+  production network with more than 1000 clients on a server may cause
+  problems if you don't have a lot of memory. (This does not seem to
+  be a problem with non-debug builds) --Bleep
+* Captialisation fixes, just to keep certain ppl quiet. --Isomer
+* Removed +s channels from /list.  They were shown sometimes, but not
+  others, and the information that was shown about them was inconsistant.
+  list is not an effective way to gain information anyway. Reformatted
+  and touched up readme.who as well.  --Isomer
+* Added MAP to ISUPPORT, added doc/features.txt --Isomer
+* Added suggestions made by scripters. more info for ISUPPORT, and
+  added stuff to 'TODO' --Isomer
+* More TODO items 'done'.  P:'s now ignore '*'s.  ping shouldn't do funky
+  stuff with mirc anymore, needs discussion --Isomer
+* Typo fixed. Now I'm annoyed.  --Isomer
+* Right, Makefile's gonna work now or I'm going to get REALLY annoyed at it.
+  --Isomer
+* TODO, m_ping, ircd/Makefile.in: Added note to TODO, added info to
+  m_ping, and fixed Makefile bug using bsdmake. --Isomer
+* s_bsd.c, listener.c, s_user.c, s_serv.c, s_bsd.h:
+  Set receive and send buffers in correct order to enable flow
+  control for clients and support fat pipes better for servers.
+  Finally got it right :)
+  See Stevens "Unix Network Programming" v1 p 191-193
+  --Bleep
+* ircd.c (main): added idiot checking to make sure MAXCONNECTIONS
+  is sane. --Bleep
+* send.c: Don't let negative fd's break stuff, audit sentalong
+  usage for sillyness. --Bleep
+* send.c (sendto_common_channels): bug fix, code assumed client
+  local, file descriptor is only in local client struct
+  --Bleep
+* table_gen.c, channel.c: make FIXME changes, removed
+  FIXME code from table_gen, readd FIXME code to channel.c,
+  I hope I got this right. --Bleep
+* Makefile.in: Add purify def, fix so CFLAGS don't error
+  off when using Solaris compiler --Bleep
+* fda.c (fda_free): fix compile error on Solaris --Bleep
+* configure.in: add SunOS case to detect Solaris --Bleep
+* os_solaris.c (os_send_nonb): fix solaris compile error --Bleep
+* exaconf.2: add file from conf design to docs directory to
+  have it available for new conf parser development --Bleep
+* fda.c (fda_free): fix memory leak, doh!!! --Bleep
+* hash.c (addNickJupes): fix buffer overrun --Bleep
+* s_bsd.c (read_message(poll)): fix uninitialized memory read
+  bogosity in poll macros. --Bleep
+* channel.c (send_user_modes): change to send XXX:ov instead
+  of XXX:o:v doesn't send XXX: if no modes set. --Bleep
+* s_bsd.c (connect_server): bugfix for connect/rehash/connect
+  multiple outstanding dns query core. --Bleep
+* channel.c (send_user_modes): bugfix for burst not sending modes
+  when burst line is created. --Gte
+* m_gline.c: change NumServ(cptr) to NumServ(sptr) found by Gte
+  --Bleep
+* config-sh.in: add WildThangs BADCHAN config fix --Bleep
+* config-sh.in: add Runs restart bugfix --Bleep
+* Makefile.in: make sure version.c gets regenerated when checksums
+  change --Bleep
+* Makefile.in: remove hash.c/crypt/sums idiocy, all of the ridiculous
+  anti-hack stuff is already done in version.c anyhow.
+  "Shhh..., don't tell the admins ( .)( .) you're being watched"
+  --Bleep
+* hash.c (m_hash): fix count bugs --Bleep
+* m_squit.c (mo_squit): fix off by one, /quote SQUIT bug --Bleep
+* ircd_relay.c: oops, changed the wrong one.  Fixed previous fix. --Isomer
+* Makefile.in, ircd_relay.c: Fixed 'make depend', added dependancies, fixed
+  bug where server would core on sending a server notice --Isomer
+* m_kick.c (ms_kick): fix core on kick message coming from
+  server --Bleep
+* config.in: remove CRYPT_LINK_PASSWORD option --Bleep
+* doc/readme.www: Applied Runs' doc patch --Bleep
+* client.h: Add member to client struct to try to aggravate the
+  bug found by Jesus --Bleep
+* client.h: Remove IsListening macros and flags, add FLAGS_UPUNG
+  and IsUPing/GetUPing/SetUPing macros --Bleep
+* m_silence.c, m_create.c: check for IsServer(sptr) don't
+  allow X SILENCE X +*@*.com or X C #blah 947477407 core the
+  server. --Bleep
+* os_*.c, res.c: clean interface for os_recvfrom_nonb --Bleep
+* uping.c, uping.h: new files for UDP pings, these aren't hooked up yet, or
+  finished or tested.
+  --Bleep
+* channel.c: find_member_link(): Fail fast for Servers, prevents core when
+  servers set a channel mode. --Isomer
+* channel.c, channel.h, various.c: Changed find_member_link() to take
+  a chptr instead of the first member, and special case'd +k users
+  (see comment in code for more details) --Isomer
+* ircd/Makefile.in: Changed gnu specific $^ for $< in table_gen
+  rules --Bleep
+* INSTALL: Explained about CVS --Isomer
+* example.conf: Point to coder-com@ for help configuring the server. --Isomer
+* INSTALL: Make things a bit more plain.  --Isomer
+* s_bsd.c (read_message (poll)): removed local_cptr array using
+  this temp made possible a bug where if a client lower in the list
+  managed to exit a client higher in the list, a dangling reference
+  to the already exited client would be left in the local_cptr array.
+  Found by Quantum by loading 100's of clones with the same nick.
+  --Bleep
+* INSTALL: Added instructions for -lcrypt FAQ --Isomer
+* INSTALL: Added instructions for -lresolv FAQ --Isomer
+* INSTALL: Added instructions for making ./configure executable --Isomer
+* numeric.h: Merged in some more numerics that other ircds user --Isomer
+* IPcheck.c: Fix gramatical error to keep pedants happy. --Isomer
+* IPcheck.c: Allow -DNOTHROTTLE for debugging purposes.  --Isomer
+* m_stats.c: make stats c available to opers only, TEMP_HACK --Bleep
+* IPcheck.c: Fixed outdated comment.  Thanks Quantum --Isomer
+* ircd_reply.c: Fix the fix, silly typo.  thanks Bleep --Isomer
+* ircd_reply.c: added check for people without nicks.  --Isomer
+* doc/Authors, ircd/version.c.SH: updated /info and maintainer 
+  lists. --Isomer
+* channel.h, channel.c, m_join.c, m_mode.c: add David M's
+  lchanmode patch update --Bleep
+* s_auth.c: fix ident bug, comment code for rule. --Bleep
+* m_invite.c (m_invite): Fix syntax error, missing ')'. -- Isomer.
+* m_invite.c (m_invite): tokenize invites, change from accidental
+  broadcast to directed message (bug fix). --Bleep
+* m_time.c (m_time): send tokenized time messages --Bleep
+* s_user.c (set_user_mode): Send wallops to everyone by default
+  allow compile option WALLOPS_OPER_ONLY for networks that want
+  to disable wallops for users. --Bleep
+* s_misc.c (exit_one_client): tokenize client quit message to other servers.
+  --Gte
+* m_kick.c: you would have thought I'd fix all of them the first time, but
+  no... -- Isomer
+* m_kick.c: Fixed missing space after TOK_KICK -- Isomer
+* m_burst.c: Fixed netrider kick bugs -- Isomer
+* s_user.c: Bug fix --Bleep
+* s_user.c: only send wallops to opers --Bleep
+* s_user.c: enforced undernet policy. -- Isomer
+* s_user.c: replace user_modes with struct UserMode array
+  change code to use new struct. --Bleep
+* s_user.c (set_user_mode): clean up switch statement --Bleep
+* channel.c (set_mode): fixed -k foo bug, extra == 0 typo in
+  conditional. --Bleep
+* dbuf.c (dbuf_alloc): fixed count bug, we _have_ to count it in
+  the branches. --Bleep
+* dbuf.c, send.c, s_bsd.c, send.h: bahh finally did it right,
+  if a dbuf allocation fails, attempt to flush all send buffers except
+  for the one we are trying to build (we're twiddling with the list etc..)
+  if the allocation fails a second time, _then_ bail. --Bleep
+* s_bsd.c, send.c: if dbuf_put fails for send or receive buffers,
+  call flush connections to free up some buffers (safe here). --Bleep
+* dbuf.c (dbuf_put): back out previous change, afaict it would fail
+  spectacularly --Bleep
+* dbuf.c (dbuf_put): call flush_connections(0) if we can't allocate
+  a dbuf the first time, this may prevent the server from dropping
+  connections during netbursts. --Bleep
+* m_privmsg.c: fix IDLE_ON_MSG fix -- Isomer
+* m_privmsg.c, parse.c: fix IDLE_ON_MSG bug --Bleep
+* m_ison.c (m_ison): Temp hack to fix missing null terminator. --Bleep
+* m_nick.c (m_nick): fix null nick reply bug --Bleep
+* ircd_string.c, match.c: fix a couple possible issues with
+  the character attribute changes --Bleep
+* s_auth.c, ircd.c: turn off connection status messages for
+  connections to server ports. --Bleep
+* ircd.c, s_conf.c, m_server.c, ircd.h, s_conf.h:
+  removed portnum and server_port global variables, server port
+  in M:lines is ignored, server ports now need to be defined in
+  the P:lines. Add SERVER_PORT config option to allow:
+  '/connect server.net.dom' without specifying the port. --Bleep
+* config-sh.in: change PORTNUM to SERVER_PORT now used for
+  default server port for outgoing connections in m_connect.
+  --Bleep
+* example.conf: document changes to M:line for server port --Bleep
+* ircd_chattr.h, ircd_string.h, ircd_string.c, table_gen.c:
+  put Nemesi's table generation code and macros back in, the
+  tables are now automagically generated whenever the table_gen.c
+  file is modified, use a slightly different mechanism to get the
+  tables in the executable. Add reference data file to test dir
+  for character attributes. --Bleep
+* s_auth.c (check_ident_reply): add function that implements
+  auth reply undernet rules checking. --Bleep
+* s_misc.c (date): added Runs Y2K patch --Bleep
+* m_privmsg.c: work on server handlers, hookup new code to parser,
+  test, fixed a couple bugs, fixed username bug in server NICK
+  processing --Bleep
+* ircd_chattr.c, m_privmsg.c: Work on privmsg code a bit more,
+  commit for review, still a bit more to do --Bleep
+* os_bsd.c, configure.in: add os dependency file for bsd
+  --Bleep
+* m_privmsg.c, ircd_string.c: little cleanups for privmsg
+  work on prototype handler for new parser. --Bleep
+* m_connect.c, s_conf.c: clean up /connect handling code
+  --Bleep
+* m_away.c, m_admin.c, m_close.c, m_connect.c:
+  start cleaning up handlers --Bleep
+* whocmds.c, whowas.c, *.c: split out handlers from whocmds.c
+  and whowas.c --Bleep
+* s_serv.c, m_*.c: split out handlers from s_serv.c
+  --Bleep
+* querycmds.c, m_*.c: split out handlers from querycmds.c
+  --Bleep
+* opercmds.c, m_stats.c, m_connect.c, parse.c, handlers.h, *.c
+  add new command handlers --Bleep
+* channel.c, m_names.c: new file for names handler --Bleep
+* channel.c, m_list.c: new file for list handler --Bleep
+* channel.c, m_topic.c: new file for topic handler --Bleep
+* channel.c, m_burst.c: new file for burst handler --Bleep
+* channel.c, m_create.c: new file for create handler --Bleep
+* channel.c, m_destroy.c: new file for destroy handler --Bleep
+* channel.c, send.c, m_join.c: new file for join handler,
+  const fixups for send.c --Bleep
+* channel.c, m_mode.c: new file for mode command handler,
+  clean up file scope buffer mess. --Bleep
+* m_silence.c: split out SILENCE handler to a new file,
+  cleanup --Bleep
+* m_ison.c: split out ISON handler to a new file, cleanup --Bleep
+* m_userip.c: split out to new file, change userhost and userip
+  to use same algorithm with different formatting functions --Bleep
+* m_userhost.c: split out to new file --Bleep
+* send.c: add new function send_buffer, cleanup godemode ick a bit
+  --Bleep
+* m_wallchops.c: split out wallchops handler --Bleep
+* m_cprivmsg.c: split out m_cprivmsg and m_cnotice.
+* m_pass.c, s_user.c: split out m_pass, pass message handler
+  --Bleep
+* m_oper.c: split out m_oper.c from s_user.c, setup to use
+  new parser. --Bleep
+* m_pong.c, m_ping.c, parse.c, s_user.c, channel.c:
+  Add new file for pong messages, convert ping and pong to use
+  numerics. Test pings and pongs on testnet. Fix numeric
+  nick bug in channel.c. --Bleep
+* m_ping.c, s_serv.c, parse.c: new file for pings, fixed a 
+  minor bug in ping handling. --Bleep
+* m_nick.c, m_kill.c: clean up nick code for servers, still needs work
+  fix string formatting bug in m_kill --Bleep
+* m_nick.c, s_user.c, ircd_chattr.c: add new file for NICK command,
+  clean up local client registration for nicks. --Bleep
+* m_away.c, s_user.c, parse.c: split out m_away handlers for client,
+  add user_set_away function. --Bleep
+* m_kill.c, ircd_reply: Rework handling of kill from server, add new error
+  message formatter. --Bleep
+* m_kill.c (mo_kill): Rework handling for kill from operator on server
+  kill originated from --Bleep
+* m_kill.c: new message handler file for kill --Bleep
+* configure.in, ircd/Makefile.in: added automatic os checking to autoconf
+  checked --Gte
+* m_quit.c: new message handler file for quit --Bleep
+* m_privmsg.c: new message handler file for privmsg --Bleep
+* ircd_string.c, support.c, support.h, *.c: moved strtoken to ircd_string
+  and renamed ircd_strtok --Bleep
+* channel.c, s_user.c, s_debug.c, send.c, channel.h: finish membership code
+  --Bleep
+* channel.c, more cleanups of membership code and macros --Bleep
+* channel.c, s_misc.c: more cleanup in channel link code, most likely
+  still a bit broken yet, more to come. --Bleep
+* querycmds.h (Count_remoteclientquits): fix minor bug --Bleep
+* ircd.h, querycmds.h, struct.h, channel.c, list.c, map.c, opercmds.c,
+  s_err.c, s_serv.c, s_user.c, s_misc.c: Add Isomers passivelag0-1.patch
+  fixed minor bug in macros --Bleep
+* channel.h, channel.c, s_user.c, s_debug.c, s_user.c:
+  added Membership struct for channel associations, change user/channel
+  lookups to use new struct. --Bleep
+* channel.c, channel.h, s_user.c: cleanup channel and user code
+  a bit, new function find_no_nickchange_channel --Bleep
+* parse.c, m_defaults.c: added default handlers and hooked up new
+  message handlers --Bleep
+* *.c, struct.h: added Isomer's passivelag patch and, the second
+  p10 patch --Bleep
+* ircd_reply.[ch]: new files for commonly used replies --Bleep
+* m_proto.[ch]: new file for protocol command support, needed for zip
+  links --Bleep
+* client.h, parse.c, msg.h: add code to support multiple message handlers
+  depending on client status. --Bleep
+* s_bsd.c, packet.c: code cleanup prep for zip links --Bleep
+* channel.c, opercmds.c, ircd.c, s_serv.c, s_user.c, querycmds.c, 
+  whocmds.c, whowas.c: Add Isomers p10ify patch, tokenize server to
+  server commands --Bleep
+* s_user.c (m_nick): killed goto --Bleep
+* client.h, *.c: moved client stuff to client.h --Bleep
+* version.c.SH, patchlevel.h, .patches: change version string
+  generation, patch level is now set in patchlevel.h by simply
+  bumping the number in the PATCHLEVEL string. --Bleep
+* ircd_alloc.c, channel.c: fixup warnings in release build (NDEBUG)
+  --Bleep
+* fda.h, ircd_alloc.h, fda.c, ircd_alloc.c, fda_t.c: new files,
+  runmalloc was core dumping on squits and unable to handle or
+  detect double frees, the memory debug code can be disabled by
+  compiling with NDEBUG defined --Bleep
+* channel.c (remove_user_from_channel): refactor function --Bleep
+* channel.c (m_kick): refactor function a bit, put all checks at top
+  move code out to new function (make_zombie) --Bleep
+* s_bsd.c (completed_connection): fixed stupid
+  "Write error to blah: Socket not connected" bug --Bleep
+* struct.h, send.h, send.c, s_bsd.c, IPcheck.c, s_user.c, *:
+  More socket code cleanup, move file descriptor to local part of
+  client struct, use cptr->error to handle the errno of any socket
+  error, fix bug in IPcheck that ends up only disallowing every
+  256th clone, Add more ipcheck forgiveness to s_user.c (needs work).
+  Changed IPcheck_local_connect and IPcheck_connect_fail interfaces to
+  use struct in_addrs instead of client structs to allow delaying the
+  allocation of the client struct till after the check was done.
+  Added can_send function to send.c (should be called before work is done
+  but right now it's called just before trying to send (needs work))
+* channel.c: Added Isomers netride2.patch, still needs a config option
+  to turn it on (NO_INVITE_NETRIDE) --Bleep
+* parse.c, msg.h: Added silent ignores for notices so connect progress
+  messages do not cause connecting server to spew ERR_REGISTER_FIRST
+  messages at the server it's connecting to. --Bleep
+* s_serv.c, s_user.c, channel.c, send.c: Tokenised BURST, NICK,
+  END_OF_BURST, EOB_ACK, PRIVMSG and NOTICE Server to Server.
+  About 8-10% Bandwidth saving on BURSTS. --Gte
+* channel.c (m_join): servjoin patch --Isomer
+* ircd_osdep.h, os_*.c, s_bsd.c, send.c: more cleanups in socket code,
+  use enumeration for IO results. --Bleep
+* s_bsd.c: clean up select and poll code a bit more, fixed message pacing bug
+  in poll. --Bleep
+* supported.h, numeric.h, s_user.c, s_err.c: Added Isomers features
+  patch. Use numeric 005 RPL_ISSUPPORT to convey server features to
+  clients. --Bleep
+* s_user.c (m_nick): IP differ patch, use IP address instead of host
+  name to determine different user@host for nick collides. --Isomer
+* hash.c (hChangeClient): Bug fix. Fixed bug that caused stale entries
+  to be left in client hash table after a name change. Discovered by
+  Quant and Isomer. --Bleep
+* hash.c (hSeekClient): fixed bug I introduced when reversing my hash
+  table code changes, thanks Quant and Isomer --Bleep
+* opercmds.c (m_lusers): send limited luser info to remote
+  clients --Isomer
+* numeric.h, channel.c, s_err.c: Changed invite list numerics
+  from 283/284 to 346/347 to match IRCnet numerics --Bleep
+* config-sh.in, gline.h, numeric.h, gline.c, opercmds.c, s_debug.c, s_err.c:
+  Add badchan patch by WildThang --Bleep
+* config-sh.in, channel.h, numeric.h, channel.c, s_debug.c, s_err.c:
+  Add lchanmode patch by David M --Bleep
+* channel.c (cancel_mode): removed incorrect assert --Bleep
+* *.c: removed P9 support, not everything is completely gone but most
+  of it is, the server builds and connects to other servers, but thats
+  as far as it's been tested so far. --Bleep
+* ircd.h, ircd.c, s_bsd.c:
+  removed BOOT_INETD/BOOT_CONSOLE code, unused non-functional --Bleep
+* struct.h, ircd.h, ircd.c, s_user.c, s_bsd.c:
+  removed BOOT_OPER/STAT_MASTER code, original patch by Isomer --Bleep
+* s_user.c (m_nick): removed redundant check for acptr
+* hash.c (hSeekClient, hSeekChannel): roll back some of hash.c changes
+* hash.c (hSeekClient, hSeekChannel): removed unused variable from previous
+   changes.
+* hash.c (hSeekClient, hSeekChannel): fix compile error from status changes,
+   fix logic bug that caused the first client that matched the mask to be
+   returned regardless of whether or not it's name matched, this can result
+   in wierd problems where the wrong server/client could be returned from the
+   hash table lookup. Removed code that moved client to head of hash table
+   chain for it's bucket when it's looked up, if the hash table is working
+   reasonably well this just wastes cpu.
+* hash.c, list.c: added code to zero out cptr->hnext when client removed
+   from hash table, added assert for hnext == 0 in list.c to make sure that
+   client was actually removed from the hash table before freeing it's memory.
+* various: misc cleanups
+* support.c: removed dead code
+* configure.in: remove unneeded checks for minix, aix, ansi/posix headers
+   these things are handled by porting layer code.
+* res.c: remove calls to add_local_domain, these were causing incorrect
+   behavior
+* opercmds.c: cleanups in gline code
+* s_bsd.c: increase socket buffers to 65535 for server connections
+* crypt/mkpasswd.c: mutter correct runes to get file to compile without warnings
+* gline.c, gline.h: add new files to attempt to encapsulate glines a bit,
+   some code from opercmds.c needs to be moved here still
+* opercmds.c (m_gline): fix local gline bug
+* s_conf.c (initconf): add password change on rehash fix
+* s_conf.c (rehash): fix rehash freeing and reloading the motd/rmotd files for
+   every client connected.
+* ircd_log.c: use 2K fixed buffer instead of vsnprintf, nothing we write to
+   the log should ever exceed 512 bytes, but it doesn't hurt to be paranoid.
+* res.c: change resolver timeouts to 5 seconds, per RFC1123
+* channel.c: more little cleanups, no code changes
+* channel.c: a) stops iterating over /invite list
+    b) adds /invite to list the channels you're currently invited to.
+    c) adds lotsa new numerics --Isomer
+* ircd_signal.c, ircd.c: fix bug in signals
+* channel.c (can_send) add Isomer's changes
+* channel.c: add send_ban_list, cleanup a few names, reformat some parts to make
+    more readable, fix bug introduced by name changes
+* ircd_chattr.[ch]: add new macro for checking K:line time chars vs comments
+* listener.c (show_ports): add code to show client/server and hidden status
+* s_conf.c: bug fixes, cleanups, add code to set server port and hidden
+    status for listeners (P:lines)
+* s_conf.c (initconf): add interface selection code to P:lines so ports can
+    be set on a single interface or multiple interfaces (multi-homed hosts)
+* s_conf.c: rewrote C/N line code, removed N:lines entirely, clean up server
+    conf line code.
+* s_conf.c (check_server): move ip checks out of resolved or not so they can
+    be checked for worse case situations on server connects
+* res.c (resolver_read): add Isomer's debug info for failed resolver queries
+* opercmds.c (m_stats): remove call to time(0) for each local client in 
+    stats l command, use CurrentTime instead
+* s_conf.c (initconf): only do lookups on C:lines instead of both C/N lines
+* res.c: fix resolver hang bugs
+* s_conf.c (rehash): remove extra semicolin that was causing c/n lines to
+    accumulate
+* s_conf.c (rehash): add portnum back to the listener list so we don't loose
+    the server port on a rehash
+* s_auth.c, listener.c: remove warnings for normal errors
+* s_auth.c, listener.c: use osdep non-blocking calls instead of locals
+* s_auth.c, listener.c: add code for non-blocking recovery for listeners and
+    auth queries
+* s_auth.c (auth_error): call IPcheck_connect_fail if the client socket dies
+    during the auth check so the reference count doesn't get borked in the
+    IPcheck code.
+* numnicks.c: yet another extended numerics bug fix... sheesh
+* s_bsd.c, s_conf.c: move conf line code from s_bsd.c to s_conf.c, cleanup
+    cleanup check_server, check_client (still not completely tested, may be
+    a bit buggy yet).
+* parse.h, parse.c, s_debug.c: remove privmsg logging code
+* numnicks.c (FindXNServer): fix off by one bug
+* common.h, common.c: removed unused files
+* s_bsd.c (net_connect_completed): new function, called after connection
+    establishment for servers and clients, release reference count for
+    the dns reply and set the socket buffer size to IRCD_READBUF_SIZE 
+    for servers and 2K for clients.
+* channel.c, crule.c: cleanup bogus casts
+* listener.h (add_listener): fix bug that caused server a server port listener
+    to think it was a client port listener.
+* s_user.c, s_serv.c: release reference to dns_reply when connection is
+    established.
+* s_bsd.c (completed_connection): removed call to start_auth for connects
+    the auth module expects connections not to be linked anywhere and owns
+    the client struct until it's done.
+* listener.c (release_listener): fix inverted assert client exit bug
+* ircd_chattr.c: fix signed/unsigned warnings with Sun Workshop (+w)
+* ircd_chattr.c, ircd_chattr.h: new files for character attributes and case
+    translation, hopefully they will be a bit easier to maintain.
+* s_conf.c (rehash): fixed logic bug that caused and infinite loop, 
+    fix port update bug (needed to call mark_listeners_closing before initconf)
+* *.c, runmalloc.[ch]: change the way the server deals with out of memory
+    conditions. On server startup a no-memory handler is installed which
+    calls server_restart if an allocation fails. Allocations are now checked
+    in the memory allocation functions. Added asserts after every allocation
+    to verify for debug.
+* *.c *.h: move authentication and dns to authentication module rename a few
+    globals, const correctness fixes, add ircd_string code, rework network
+    code, use dns callbacks, removed a lot of redundant code 
+* s_bsd.c: finish this stage of net code work
+* *.c, *.h: rewrite select and poll code, add listener.[ch] net.code overhaul
+    in progress, prepare for adding auth module
+* s_bsd.h, struct.h: moved client struct macros back into struct.h for now,
+    the last place they belonged was in the network code... feh
+* ircd.c (open_debugfile): removed client for debug file
+* ircd_string.h, ircd_string.c: new files for string processing, add
+    ircd_strncpy function
+* *.c, *.h: rename ircstp to ServerStats
+* *.c, *.h: rename now to CurrentTime
+* listener.h, listener.c: new files for listener ports
+* include/ircd_defs.h: new file for global definitions (HOSTLEN, USERLEN)
+* struct.h: add local_flag to client struct, to make local/remote detection simpler
+* s_bsd.c (read_message): split out separate versions for select and poll
+* s_bsd.h, various source files: remove the rest of the unix domain socket 
+    support this removes a number of comparisons that were unneeded in 
+    code that should run reasonably fast.
+* os_*.c, res.c, ircd_osdep.h: add os_recvfrom_nonb for resolver
+* os_*.c, s_bsd.c, s_auth.c, ircd_osdep.h: add os_get_sockname, os_get_peername
+* bsd.h, bsd.c: merge into s_bsd
+* ircd_osdep.h, os_generic.c, os_linux.c, ircd_osdep.h: move os variable stuff
+    to separate compilation units, os generic contains the original code
+    (start here). 
+* s_bsd.c, send.c, struct.h: remove pyr (pyramid) finally
+* res.h, res.c, s_misc.c: cleanup headers/dependencies in res.h
+* match.h: include sys/types.h before netinet/in.h, broken BSD system headers
+* ircd/Makefile.in: remove CFLAGS from link line, use LDFLAGS instead
+* ircd.c: add missing include for sys/socket.h
+* common.h (strChattr, strCasediff): remove pointless non-portable inline
+    decls. The functions are complex enough that inlining just bloats the code
+* ircd_xopen.h, ircd_xopen.c, s_user.c, s_serv.c: porting layer for crypt and
+    other xopen library calls, moved crypt to ircd_xopen.
+* s_uping.c, s_uping.h, s_bsd.c, s_misc.c, s_bsd.h, ircd.c, s_debug.c:
+    Removed s_ping. There are much better tools available that actually work
+    correctly. The s_ping code was a waste of resources, and has historically
+    given incorrect results (it never worked correctly).
+* ircd/s_bsd.c, res.c, s_user.c, s_serv.c: little fixups to allow code to
+    build on Solaris, still have some warnings there.
+    TODO: wrap crypt and things that depend on _XOPEN_SOURCE in their own
+    file so it doesn't bother the network code.
+* ircd/s_bsd.c: cast option arg to const char* for setsockopt (solaris)
+* ircd/Makefile.in: removed hard coded dependencies for hash.o chkconfig.o,
+    let the automatic stuff take care of it, it does it better than humans.
+* *.c *.h: remove register keywords, attribute macro junk, cleanup
+    dependencies, rename MIN and MAX to IRCD_MIN IRCD_MAX all headers in
+    C files are sorted, removed as many duplicate includes as I could find
+    (dozens) general cleanups. Mutter the correct runes to get the protoype
+    for crypt included where it was needed.
+* *.c *.h: dependency cleanups up to querycmds.c
+* ircd.c, bsd.c, s_bsd.c: move signal handling code to ircd_signal.c
+* ircd_signal.c, ircd_signal.h: new files, use only POSIX signals remove
+    support for unreliable signals.
+* *.h *.c: include guards, dependency cleanups
+* Configure.in, setup-sh.in: include guards, config.h includes setup.h
+    add config dir to include path
+* sys.h: include guards, remove hard coded path to config.h
+* s_user.c (hunt_server): fix logic bug
+* numnicks.c (SetServerYXX): fix off by one error
+* multiple files (n2k patch): add code to handle extended numerics
diff --git a/INSTALL b/INSTALL
index 2336cb86f1dee621c96807021afd3b6f910f7f15..01ebc043eacf8c6acc44bb83349476f64d0ee333 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,39 +1,84 @@
-                           INSTALL file        by Run <carlo@runaway.xs4all.nl>
-
+INSTALL file        by Run <carlo@runaway.xs4all.nl>
+            Updated by Isomer <isomer@coders.net>
 
 This is the UnderNet IRC daemon.
 
 The installation of the IRC daemon (ircd) exists of the following steps:
 
-1) Untar the package.
+1) Retrieve the package.
 2) cd into the base directory.
-3 )`./configure'
+3`./configure'
 4) `make config'
 5) `make'
 6) `make install'
 
-1) Untar the package
+1) Retrieve the package.
 ====================
 
-The name of the package is something like `ircu2.x.y.z.tgz', where
-"x.y.z" is the current release (at the time of writing we have
-ircu2.10.00.beta3.tgz).
+The recommended way to get the ircu package now is to use CVS.  CVS makes
+upgrades a lot less painful and lets you get the latest package.
+
+1.1) The first thing you need to do is 'authenticate' yourself against the
+server.  
+
+This is done with:
+
+cvs -d :pserver:anoncvs@coder.com.undernet.org:/home/coder-com/cvs login
+
+(we recommend that you cut and paste the above line to use it :)
+When it prompts you for a password enter 'anoncvs'.
+
+1.2) Then you have to decide which of the trees you want to use:
+
+irc2.10 - This is the *STABLE* tree.  If in doubt use this one!
 
-You need `gzip', the GNU unzip command, to uncompress this package.
-You can download this from every GNU ftp site for almost any Operating system.
+beta - This tree is undergoing testing before being promoted to ircu2.10
+       It may be buggy.  Use on the undernet production network is prohibited,
+       except for certain authorised servers.
 
-If you have GNU tar, type:
+alpha - This is the development tree, if you are planning on making patches
+       to be submitted to the main source tree we recommend you use this
+       tree.  However this tree is *not* guaranteed to compile, and should
+       be concidered HIGHLY unstable.  It is not intended for production
+       use.
 
-tar xzf ircu2.x.y.z.tgz
+to check out the tree, type:
 
-where "ircu2.x.y.z.tgz" is the name of the package.
+cvs -d :pserver:anoncvs@coder-com.undernet.org:/home/coder-com/cvs checkout
+   -P irc2.10
 
-If your tar doesn't support the 'z' flag, you can type alternatively:
+The above two lines shouldn't have an enter between them.  if you want to
+use another tree, replace 'irc2.10' with the tree you want to use.  This
+will create a directory irc2.10, and put all the files in there.
 
-gzip -dc ircu2.x.y.z.tgz | tar xf -
+to get the latest version, from within the tree type "cvs update -dP".
 
-Both methods result in a directory "ircu2.x.y.z" in your current directory.
+For more information see the coder-com website at
+http://coder-com.undernet.org/
 
+The old (tried and true) method that works even when the website isn't being
+DoS'd (sigh) is included below.  Using the method below means you /cant/
+just type 'cvs update -dP' to get the latest version.
+
+ The name of the package is something like `ircu2.x.y.z.tgz', where
+ "x.y.z" is the current release (at the time of writing we have
+ ircu2.10.00.beta3.tgz).
+
+ You need `gzip', the GNU unzip command, to uncompress this package.
+ You can download this from every GNU ftp site for almost any Operating system.
+ If you have GNU tar, type:
+ tar xzf ircu2.x.y.z.tgz
+ where "ircu2.x.y.z.tgz" is the name of the package.
+ If your tar doesn't support the 'z' flag, you can type alternatively:
+ gzip -dc ircu2.x.y.z.tgz | tar xf -
+ Both methods result in a directory "ircu2.x.y.z" in your current directory.
 2) cd into the base directory
 =============================
 
@@ -41,6 +86,8 @@ Make this directory your current directory by typing:
 
 cd ircu2.x.y.z
 
+or ircu2.10 if you used cvs.
+
 where "ircu2.x.y.z" is the name of the unpacked directory.
 
 3) `./configure'
@@ -49,6 +96,9 @@ where "ircu2.x.y.z" is the name of the unpacked directory.
 This will generate 'config/setup.h', your Operating System dependend
 configuration.
 
+If this produces a 'Permission Denied' error message, then try typing
+`chmod a+x ./configure` first to give yourself permission to run the file.
+
 4) `make config'
 ================
 
@@ -71,6 +121,14 @@ you did everything the right way.  If you want your Operating System
 to be supported in future releases, you best make a patch that
 actually fixes the problem.
 
+If you have problems here with it complaining about unresolved symbols in
+res.o, try "make config" again and add -lresolv to LDFLAGS. Note, there is
+no 'e' on the end of resolv.  It's not a typo, it's supposed to be like
+that.
+
+If you have problems here with it complaining about unresolved symbols
+possibly in s_user.c for 'crypt', add -lcrypt to LDFLAGS.
+
 6) `make install'
 =================
 
@@ -102,3 +160,5 @@ This will write debug output to your screen, probably showing why it
 doesn't start.
 
 Don't use a server with DEBUGMODE defined on a production net.
+
+If things still don't work, try emailing coder-com@undernet.org
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..cd9cea9
--- /dev/null
+++ b/README
@@ -0,0 +1,97 @@
+
+README for ircu2.10.10.beta
+Please read this completely before running the server
+
+* If you run ircu2.10.10 on the production network and expect
+  more than 1000 local clients to connect you will want to make
+  sure you add -DNDEBUG to the extra CFLAGS setting when you do
+  a make config.
+* Ircu now uses asserts in a lot of places to insure referential
+  integrity and that impossible situations do not occur. Also
+  memory integrity checking is defaulted to on as well. The asserts
+  and memory checking both use cpu and in the case of memory checking
+  extra memory. We have not had an assert trigger in quite some time
+  but would prefer to leave the checks enabled for beta testing.
+  The asserts insure that if the server is going to core it will do
+  so in well defined places where the problem will be easy to trace,
+  without them the server could core in not so well defined places.
+  If you want to disable the checks, add -DNDEBUG in the extra CFLAGS 
+  when you do a make config.
+
+* Ircu no longer uses separate C/N lines, the functionality of both
+  has been combined in C:lines, see the example.conf for more information.
+
+* Ircu has an different mechanism for defining ports than the previous
+  versions. Please see the example.conf for information on configuring
+  them. Ircu also ignores the port specified on the M:line, you MUST define
+  a server port with a P:line if you want servers to connect to you.
+
+* For beta releases, please understand that there may be bugs we haven't
+  found yet, (that's why you're beta testing it in the first place :)).
+  Please report any bugs found in the server to bugs@undernet.org or
+  coder-com@undernet.org with as much information as you can provide
+  about how to reproduce the problem. Stack traces for coredumps are
+  usually helpful, however we aren't expecting any of those ;-).
+
+* Ircu 2.10.08 is a P10 only server, and cannot be used to host P9 
+  links. On a mostly P10 network this is not a major issue, it does
+  mean that you cannot connect services directly to a 2.10.08 server,
+  but does not preclude it's use as a leaf or a hub. For now, services
+  need to continue to be hosted by 2.10.07 servers.
+
+* EXTENDED_NUMERICS is not defined by default, we need to get everyone
+  using 2.10.07 before we can allow it to be turned on anywhere. If you
+  are using 2.10.08 on a network where everyone is up to at least 2.10.07
+  it is safe to turn them on. We have tested them on testnet and they do
+  work. :)
+
+* The masked notices using #*.mask has changed to use $@*.mask instead.
+  Since most of the servers on the net will not understand the new masking
+  mechanism, this probably won't work for a while. The server notice mask
+  ($*.us.undernet.org) still functions properly. This was a trade off
+  between backwards compatibility and the improved protocol, we chose to
+  not maintain backwards compatibility for this command. The #*.mask
+  functionality is easily circumvented, and the command is rarely used
+  it is not considered to be a major issue.
+* The server no longer sends notices for errors on connections that are
+  suddenly dropped during connection setup. If you really want to see
+  them, we suggest you get a life. :)
+
+* Removed: unix domain sockets, uping, m4 preprocessor spawning,
+  dozens of bugs.
+
+* New stuff:
+   Added ISUPPORT code to match dalnets.
+   Added connection progress notices.
+   Cleaned up operating system checks.
+   /invite with no arguments lists the channels you're invited to.
+   Many speedups, ipdiffer, faster strncpy, faster inetntoa.
+   Passive lag and numerics now displayed by map command.
+   Server to server tokenization.
+   Much larger TCP windows/kernel buffers for server connections,
+    smaller for clients.
+   Removed BOOT_OPER security hole.
+   Complete listener port specifications including per port virtual
+    hosting and hidden listeners.
+   Default server port for connects (config option).
+   Speed up some channel ops using new Membership struct.
+   Hash table performance stats are available now (basic).
+   Much of the socket code has been rewritten, we now only make one
+    pass through the local client array.
+   Added initial support for PROTOCOL command.
+   Many functions have been made reentrant.
+   Resolver now uses callbacks for all queries.
+   Almost every command that is sent to a server uses full P10 numerics
+    and tokenization, this reduces netburst sizes by at least 10% and
+    many server to server message sizes by 10-50%.
+   Major source code reorginization to support engine model.
+   Parser now uses an indexed table for commands, which elminates
+    the need to do IsServer IsUser IsOper checks and allows much more
+    efficient implementation of user/server/oper command handlers.
+
+* For a much longer winded explanation of all this stuff, see the
+  ChangeLog in this directory, or the cvs log at the coder-com
+  web site at http://coder-com.undernet.org/
+
+
diff --git a/RELEASE.NOTES b/RELEASE.NOTES
new file mode 100644 (file)
index 0000000..2f0ea56
--- /dev/null
@@ -0,0 +1,123 @@
+Release Notes for ircu2.10.10
+
+This is a brief description of the changes we have made to the server
+since the release of ircu2.10.07.
+
+This is the first Undernet server that is fully P10, it is no longer
+compatible with older P9 only servers. The server has been verified
+to be compatible with Undernet server versions 2.10.06 and above.
+
+Enhancements:
+All server to server communications use tokenization and numeric id's,
+this reduces the bandwidth requirements approximately 10-20%.
+
+Much of the network code has been rewritten and many old bugs relating
+to the networking core of the server have been fixed.
+
+The port handling code has been rewritten to allow much better control
+over listeners.
+
+The server supports extended numerics which theoretically would allow
+the entire population of the planet to participate on a network without
+running out of unique values.
+
+Added ISUPPORT messages on client connects to allow client coders to
+detect network specific enhancements to the client protocol.
+
+Server aliasing and virtual hosting (port forwarding) are available for
+larger DoS attack prone networks. This will be improved in the next
+release.
+
+Status messages are sent to connecting clients so connections don't
+seem to hang during client registration.
+
+The server now uses a bit less memory and cpu under full load, we
+estimate around a 10% improvement in resource usage over the previous
+version.
+
+Configuration Changes:
+Please read example.conf in the doc directory for detailed information
+on various configuration options.
+Virtual host IP addresses are now in the password field of the server M:line,
+there is no longer a command line option for specifying them. This is the
+address the server will bind to for all outgoing server to server connections.
+The port field of the server M:line is no longer used and is ignored when
+the server reads the configuration file, server ports are now specified
+only on P:lines.
+The server ignores N:lines, C:lines are used for all connect server
+information now. This means that the passwords for both sides of the
+connection must match, this change does not degrade server connection
+security of the existing protocol.
+There are several new configuration options for P:lines (listener ports).
+
+Compile Time Options:
+If you are planning on hosting more than 1000 clients on your server
+we recommend that you do not turn on asserts and heap checking or
+debug messages. This is known to cause problems.
+There are several new compile time options that you will automatically
+be prompted for when you configure the server which should be self
+explanitory.
+
+Undocumented Features:
+Every Undernet server released has had at least one undocumented
+feature ;-) Here are a few of the ones available in ircu2.10.10.
+I'm sure there are a few more we are unaware of, these are the ones
+we know about.
+To enable these you need to add them to the extra CFLAGS when you
+run make config.
+-DEXTENDED_NUMERICS This option configures the server to send
+extended numerics as well as parse them. This option should only
+be used on networks that run ircu2.10.07 and above only.
+-DFERGUSON_FLUSHER If you have a server with a lot of resources
+available this option will cause the server to attempt to flush
+it's internal buffers before dropping clients during a netbreak.
+Don't define this if you don't know, if you're not careful this
+can end up rebooting FreeBSD boxes.
+-DWALLOPS_OPER_ONLY Setting this option removes the ability for
+clients that are not opered to see wallops messages.
+
+Operating System and Kernel Requirements:
+If you plan allowing more than 1000 clients on your server, you
+may need to adjust your kernel resource limits for networking
+and I/O. There are two things you will need to pay particular
+attention to, the number of file descriptors available and the
+number of buffers the kernel has available to read and write
+data to the file descriptors.
+
+To calculate kernel buffer requirements a good place to start
+is to multipy the expected number connections expected on the machine
+by the amount of data we buffer for each connection.
+Doubling the result of the above calculation and dividing it by the
+size of the buffers the kernel uses for I/O should give you a starting
+place.
+
+The server uses 2K kernel buffers for clients, and 64K kernel
+buffers for servers (actual use may be somewhat higher).
+
+c_count - number of clients expected
+c_q     - number of bytes buffered for each client
+s_count - number of servers expected
+s_q     - number of bytes buffered for each server
+
+buffer count = (2 * (c_count * c_q + s_count * s_q)) / kernel buffer size
+
+If the client count is 2000 and the server count is 1 (normal leaf)
+and your server uses 2K as an I/O buffer size:
+
+You need (2 * (2000 * 2048 + 1 * 65536)) / 2048 or a minimum
+of 4064 buffers available, if the kernel uses 512 byte buffers you
+will need a minimum of 16256 kernel buffers.
+
+These settings may be a bit light for netbreaks under full client load
+you will need to experiment a bit to find the right settings for your
+server.
+
+FreeBSD
+You may want to increase your kernel resources if you want to put
+a lot of clients on your machine here are a few values to start with:
+CHILD_MAX=4096
+OPEN_MAX=4096
+FD_SETSIZE=4096
+NMBCLUSTERS=8096
+
+
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..9de3e18
--- /dev/null
+++ b/TODO
@@ -0,0 +1,40 @@
+
+Undernet Server TODO List
+This list contains things that still need to be done.
+
+Remember:
+Premature optimisation is the root of all evil - Knuth
+Debugging is at least twice as difficult as programming.  So if you
+write a program that uses all of your ability, you'll never be able
+to debug it all.
+
+High Priority:
+
+* something is leaking "a meg a minute" with heap debugging on
+  with 1300+ clients
+  (No idea)
+
+Medium Priority:
+* why do the allocation counts change the first time you rehash
+  after a server boot without changing the conf file:
+  *** Allocations:  416(41848)
+  *** ircd.conf : Rehashing
+  *** Allocations:  424(42006)
+  *** ircd.conf : Rehashing
+  *** Allocations:  424(42006)
+
+* Use numeric nicks for numeric replies to remote clients
+* Finish message handlers.
+* Clean up ircd.conf processing, lots of sub issues.
+* Implement PROTOCOL handshaking
+  http://www.xs4all.nl/~carlo17/irc/prot.html
+* Prepare network code to handle even more connections:
+  http://www.kegel.com/c10k.html
+* Implement zlib compression for server links.
+* Cleanups, lots of them.
+* Document undernet protocol as it is used in
+  doc/rfc1459.unet
+* Finish tokenization.
+* Allow for /WHO by IP address. (for finding who's port scanning you
+  for example).  Suggested by Nuke
+
index 32177070557531a8c9d70416db1603853abb75b0..ff9df950781ce131095ffa1c6399eae8419be273 100644 (file)
@@ -477,6 +477,11 @@ echo "#" >> $CONFIG
 echo "/*" > $CONFIG_H
 echo " * Automatically generated C config: don't edit" >> $CONFIG_H
 echo " */" >> $CONFIG_H
+echo "#ifndef INCLUDED_config_h" >> $CONFIG_H
+echo "#define INCLUDED_config_h" >> $CONFIG_H
+echo "#ifndef INCLUDED_setup_h" >> $CONFIG_H
+echo "#include \"setup.h\"">> $CONFIG_H
+echo "#endif" >> $CONFIG_H
 echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
 
 CONFIG_IN=./config-sh
@@ -510,6 +515,8 @@ fi
 
 . $CONFIG_IN
 
+echo "#endif /* INCLUDED_config_h */" >> $CONFIG_H
+
 mv $CONFIG_H config.h
 $RM -f .config.old
 if [ -f .config ]; then
index b2033a65015201740f2ad53e38aafbd39ff55d33..9d27eb6fb2e1e1ff23efdd716d0a755b3a45e7c3 100644 (file)
@@ -57,6 +57,21 @@ mainmenu_option next_comment
   fi
 endmenu
 
+mainmenu_option next_comment
+comment 'Debugging (do not define this on production servers)'
+  bool 'Do you want to enable debugging output' DEBUGMODE
+  bool 'Do you want to enable asserts and memory allocation checking' CONFIG_NDEBUG
+  EXTRA_CPPFLAGS=""
+  if [ "$CONFIG_NDEBUG" = "n" ]; then
+    if [ -z "$EXTRA_CPPFLAGS" ]; then
+      EXTRA_CPPFLAGS="-DNDEBUG"
+    else
+      EXTRA_CPPFLAGS="-DNDEBUG $EXTRA_CPPFLAGS"
+    fi
+  fi
+  bool 'Are you testing on a host without DNS' NODNS
+endmenu
+
 mainmenu_option next_comment
 comment 'Compile stuff'
   if [ "$prefix" = "NONE" ]; then
@@ -111,7 +126,6 @@ comment 'Compile stuff'
   if [ "$IRCDLIBS" = "none" ]; then
     IRCDLIBS=""
   fi
-  EXTRA_CPPFLAGS=""
   if [ -n "$EXTRA_INCLUDEDIRS" ]; then
     for i in $EXTRA_INCLUDEDIRS; do
       if [ -z "$EXTRA_CPPFLAGS" ]; then
@@ -122,9 +136,9 @@ comment 'Compile stuff'
     done
   fi
   if [ -z "$EXTRA_CPPFLAGS" ]; then
-    CPPFLAGS=-I../include
+    CPPFLAGS="-I../include -I../config"
   else
-    CPPFLAGS="-I../include $EXTRA_CPPFLAGS"
+    CPPFLAGS="-I../include -I../config $EXTRA_CPPFLAGS"
   fi
   echo "EXTRA_CPPFLAGS=\"$EXTRA_CPPFLAGS\"" >>$CONFIG
   echo "CPPFLAGS=\"$CPPFLAGS\"" >>$CONFIG
@@ -170,7 +184,6 @@ comment 'General defines'
       echo "   SECURITY: Then don't install the daemon SUID or SGID !"
     fi
   fi
-  bool 'Set up a Unix domain socket to connect clients/servers' UNIXPORT
   bool 'Do you need virtual hosting' VIRTUAL_HOST
   PREV_HUB=$HUB
   bool 'Will you connect to more then one server at a time' HUB
@@ -179,36 +192,12 @@ comment 'General defines'
   fi
 endmenu
 
-mainmenu_option next_comment
-comment 'Debugging (do not define this on production servers)'
-  bool 'Do you want to enable debugging output' DEBUGMODE
-  bool 'Do you want memory- allocation and/or leak checking' DEBUGMALLOC
-  if [ "$DEBUGMALLOC" = "y" ]; then
-    bool 'Do you want to have boundary checking' MEMMAGICNUMS
-    bool 'Do you want memory leak testing (stats M)' MEMLEAKSTATS y
-    if [ "$MEMLEAKSTATS" = "y" ]; then
-      if [ "$MEMMAGICNUMS" = "y" ]; then
-       echo "You will have extra info on allocated sizes too (MEMSIZESTATS)"
-       define_bool MEMSIZESTATS $MEMSIZESTATS
-      else
-        bool 'Do you want extra info on allocated sizes' MEMSIZESTATS y
-      fi
-      bool 'Do you want support for a time interval with /stats M' MEMTIMESTATS y
-    fi
-  else
-    define_bool MEMMAGICNUMS $MEMMAGICNUMS
-    define_bool MEMLEAKSTATS $MEMLEAKSTATS
-    define_bool MEMSIZESTATS $MEMSIZESTATS
-    define_bool MEMTIMESTATS $MEMTIMESTATS
-  fi
-  bool 'Are you testing on a host without DNS' NODNS
-endmenu
 
 mainmenu_option next_comment
 comment 'Paths and files'
   eval DPATH_DEFAULT="${prefix}/lib/ircd"
   string 'Directory where all ircd stuff resides' DPATH $DPATH_DEFAULT
-  define_string SPATH "$BINDIR/ircd"
+  define_string SPATH "$BINDIR/$SYMLINK"
   echo "The following filenames are either full paths or files within DPATH"
   string 'Server configuration file' CPATH 'ircd.conf'
   string 'Server MOTD file' MPATH 'ircd.motd'
@@ -228,7 +217,8 @@ comment 'Logging (filenames are either full paths or files within DPATH)'
       string '   Give the path and(or) filename of this log file' WPATH 'whox.log'
     fi
 
- comment 'Bad Channel G-Lines allow operators to add channel masks to a list which prohibits local clients from being able joining channels which match the mask.  Remote BadChan Glines allow Uworld to add or remove channels from the servers internal list of badchans'
+comment 'Bad Channel G-Lines allow operators to add channel masks to a list which prohibits local clients from being able joining channels which match the mask.  Remote BadChan Glines allow Uworld to add or remove channels from the servers internal list of badchans'
+  BADCHAN=y
   bool 'Do you want to enable Bad Channel G-lines' BADCHAN y
     if [ "$BADCHAN" = "y" ]; then
       echo " "
@@ -294,7 +284,6 @@ endmenu
 
 mainmenu_option next_comment
 comment 'Configuration'
-  bool 'Use crypted passwords for N: lines' CRYPT_LINK_PASSWORD y
   bool 'Use crypted passwords for operators' CRYPT_OPER_PASSWORD y
   DUMMY=`echo "$BUFFERPOOL" | sed -e 's/[0-9]//g'`
   if [ "$DUMMY" != "" ]; then
@@ -307,7 +296,7 @@ comment 'Configuration'
   fi
   int 'Max receive queue for clients (bytes)' CLIENT_FLOOD 1024
   int 'Maximum number of network connections (23 - (FD_SETSIZE-4))' MAXCONNECTIONS 252
-  int 'Default client listen port' PORTNUM 6667
+  int 'Default port for connections to other servers' SERVER_PORT 4400
   int 'Nickname history length' NICKNAMEHISTORYLENGTH 800
   bool 'Allow Opers to see (dis)connects of local clients' ALLOW_SNO_CONNEXIT
   if [ "$ALLOW_SNO_CONNEXIT" = "y" ]; then
@@ -323,6 +312,7 @@ comment 'Configuration'
   fi
   bool 'Do you want support for the old I:*:ONE:*:: construct (read help text!)' USEONE n
   bool 'Send a short message instead of the MOTD to connecting clients' NODEFAULTMOTD y
+  bool 'Kill connecting clients when forward and reverse DNS mismatch' KILL_IPMISMATCH n
 endmenu
 
 mainmenu_option next_comment
@@ -350,6 +340,7 @@ comment 'Oper commands'
   bool 'Allow local/global opers to set modes on local channels' OPER_MODE_LCHAN y
   bool 'Allow local/global opers to walk through local channels modes' OPER_WALK_THROUGH_LMODES n
   bool 'Prevent local/global opers from being kicked or deoped on local channels' NO_OPER_DEOP_LCHAN n
+
 endmenu
 
 mainmenu_option next_comment
@@ -369,11 +360,6 @@ endmenu
 mainmenu_option next_comment
 comment 'Mandatory defines (you should leave these untouched)'
   int 'Max auto connects per class (1!)' MAXIMUM_LINKS 1
-  echo '* Never define this on a production server:'
-  bool 'Enable message logging' MSGLOG_ENABLED
-  if [ "$MSGLOG_ENABLED" = "y" ]; then
-    int 'Message log size' MSGLOG_SIZE 128
-  fi
   if [ "$OPER_KILL" = "y" ]; then
     bool 'Only allow KILLs of local clients' LOCAL_KILL_ONLY
   else
index 62f94007ca688809769f14285d1c1007876a4245..94fe6ff4562febc6338ead18efbf61530928e36c 100644 (file)
@@ -769,185 +769,11 @@ else
 fi
 
 
-echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:774: checking how to run the C preprocessor" >&5
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
-  CPP=
-fi
-if test -z "$CPP"; then
-if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-    # This must be in double quotes, not single quotes, because CPP may get
-  # substituted into the Makefile and "${CC-cc}" will confuse make.
-  CPP="${CC-cc} -E"
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp.
-  cat > conftest.$ac_ext <<EOF
-#line 789 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:795: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  :
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  CPP="${CC-cc} -E -traditional-cpp"
-  cat > conftest.$ac_ext <<EOF
-#line 806 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:812: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  :
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  CPP="${CC-cc} -nologo -E"
-  cat > conftest.$ac_ext <<EOF
-#line 823 "configure"
-#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:829: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  :
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  CPP=/lib/cpp
-fi
-rm -f conftest*
-fi
-rm -f conftest*
-fi
-rm -f conftest*
-  ac_cv_prog_CPP="$CPP"
-fi
-  CPP="$ac_cv_prog_CPP"
-else
-  ac_cv_prog_CPP="$CPP"
-fi
-echo "$ac_t""$CPP" 1>&6
-
-echo $ac_n "checking for AIX""... $ac_c" 1>&6
-echo "configure:854: checking for AIX" >&5
-cat > conftest.$ac_ext <<EOF
-#line 856 "configure"
-#include "confdefs.h"
-#ifdef _AIX
-  yes
-#endif
-
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "yes" >/dev/null 2>&1; then
-  rm -rf conftest*
-  echo "$ac_t""yes" 1>&6; cat >> confdefs.h <<\EOF
-#define _ALL_SOURCE 1
-EOF
-
-else
-  rm -rf conftest*
-  echo "$ac_t""no" 1>&6
-fi
-rm -f conftest*
-
-
-echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6
-echo "configure:878: checking for POSIXized ISC" >&5
-if test -d /etc/conf/kconfig.d &&
-  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
-then
-  echo "$ac_t""yes" 1>&6
-  ISC=yes # If later tests want to check for ISC.
-  cat >> confdefs.h <<\EOF
-#define _POSIX_SOURCE 1
-EOF
-
-  if test "$GCC" = yes; then
-    CC="$CC -posix"
-  else
-    CC="$CC -Xp"
-  fi
-else
-  echo "$ac_t""no" 1>&6
-  ISC=
-fi
-
-ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6
-echo "configure:900: checking for minix/config.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 905 "configure"
-#include "confdefs.h"
-#include <minix/config.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:910: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-  MINIX=yes
-else
-  echo "$ac_t""no" 1>&6
-MINIX=
-fi
-
-if test "$MINIX" = yes; then
-  cat >> confdefs.h <<\EOF
-#define _POSIX_SOURCE 1
-EOF
-
-  cat >> confdefs.h <<\EOF
-#define _POSIX_1_SOURCE 2
-EOF
-
-  cat >> confdefs.h <<\EOF
-#define _MINIX 1
-EOF
-
-fi
-
 
 
 
 echo $ac_n "checking for ${CC-cc} option to accept ANSI C""... $ac_c" 1>&6
-echo "configure:951: checking for ${CC-cc} option to accept ANSI C" >&5
+echo "configure:777: checking for ${CC-cc} option to accept ANSI C" >&5
 if eval "test \"`echo '$''{'am_cv_prog_cc_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -963,7 +789,7 @@ for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__
 do
   CC="$ac_save_CC $ac_arg"
   cat > conftest.$ac_ext <<EOF
-#line 967 "configure"
+#line 793 "configure"
 #include "confdefs.h"
 #include <stdarg.h>
 #include <stdio.h>
@@ -1000,7 +826,7 @@ return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
 
 ; return 0; }
 EOF
-if { (eval echo configure:1004: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   am_cv_prog_cc_stdc="$ac_arg"; break
 else
@@ -1031,7 +857,7 @@ if test "$CFLAGS" != "" ; then
 fi
 
 echo $ac_n "checking for crypt in -lc""... $ac_c" 1>&6
-echo "configure:1035: checking for crypt in -lc" >&5
+echo "configure:861: checking for crypt in -lc" >&5
 ac_lib_var=`echo c'_'crypt | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1039,7 +865,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lc  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1043 "configure"
+#line 869 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1050,7 +876,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:1054: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:880: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1069,7 +895,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for crypt in -ldescrypt""... $ac_c" 1>&6
-echo "configure:1073: checking for crypt in -ldescrypt" >&5
+echo "configure:899: checking for crypt in -ldescrypt" >&5
 ac_lib_var=`echo descrypt'_'crypt | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1077,7 +903,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-ldescrypt  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1081 "configure"
+#line 907 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1088,7 +914,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:1092: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:918: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1107,7 +933,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
-echo "configure:1111: checking for crypt in -lcrypt" >&5
+echo "configure:937: checking for crypt in -lcrypt" >&5
 ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1115,7 +941,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lcrypt  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1119 "configure"
+#line 945 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1126,7 +952,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:1130: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:956: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1158,7 +984,7 @@ fi
 fi
 
 echo $ac_n "checking for gethostbyname in -lc""... $ac_c" 1>&6
-echo "configure:1162: checking for gethostbyname in -lc" >&5
+echo "configure:988: checking for gethostbyname in -lc" >&5
 ac_lib_var=`echo c'_'gethostbyname | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1166,7 +992,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lc  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1170 "configure"
+#line 996 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1177,7 +1003,7 @@ int main() {
 gethostbyname()
 ; return 0; }
 EOF
-if { (eval echo configure:1181: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1007: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1196,7 +1022,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for gethostbyaddr in -lnsl""... $ac_c" 1>&6
-echo "configure:1200: checking for gethostbyaddr in -lnsl" >&5
+echo "configure:1026: checking for gethostbyaddr in -lnsl" >&5
 ac_lib_var=`echo nsl'_'gethostbyaddr | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1204,7 +1030,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lnsl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1208 "configure"
+#line 1034 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1215,7 +1041,7 @@ int main() {
 gethostbyaddr()
 ; return 0; }
 EOF
-if { (eval echo configure:1219: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1045: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1238,7 +1064,7 @@ fi
 fi
 
 echo $ac_n "checking for socket in -lc""... $ac_c" 1>&6
-echo "configure:1242: checking for socket in -lc" >&5
+echo "configure:1068: checking for socket in -lc" >&5
 ac_lib_var=`echo c'_'socket | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1246,7 +1072,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lc  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1250 "configure"
+#line 1076 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1257,7 +1083,7 @@ int main() {
 socket()
 ; return 0; }
 EOF
-if { (eval echo configure:1261: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1087: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1276,7 +1102,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
 else
   echo "$ac_t""no" 1>&6
 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
-echo "configure:1280: checking for socket in -lsocket" >&5
+echo "configure:1106: checking for socket in -lsocket" >&5
 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1284,7 +1110,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1288 "configure"
+#line 1114 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1295,7 +1121,7 @@ int main() {
 socket()
 ; return 0; }
 EOF
-if { (eval echo configure:1299: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1125: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1318,12 +1144,12 @@ fi
 fi
 
 echo $ac_n "checking for res_mkquery in -lresolv""... $ac_c" 1>&6
-echo "configure:1322: checking for res_mkquery in -lresolv" >&5
+echo "configure:1148: checking for res_mkquery in -lresolv" >&5
 if eval "test \"`echo '$''{'unet_cv_lib_resolv'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1327 "configure"
+#line 1153 "configure"
 #include "confdefs.h"
 struct rrec;
 extern int res_mkquery(int, const char *, int, int, const char *,
@@ -1340,7 +1166,7 @@ int buflen;
 res_mkquery(op,dname,class,type,data,datalen,newrr,buf,buflen)
 ; return 0; }
 EOF
-if { (eval echo configure:1344: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1170: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   unet_cv_lib_resolv=no
 else
@@ -1350,14 +1176,14 @@ else
   OLD_LIBS="$LIBS"
 LIBS="$LIBS -lresolv"
 cat > conftest.$ac_ext <<EOF
-#line 1354 "configure"
+#line 1180 "configure"
 #include "confdefs.h"
 extern char *_res;
 int main() {
 *_res=0
 ; return 0; }
 EOF
-if { (eval echo configure:1361: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1187: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   unet_cv_lib_resolv=yes
 else
@@ -1381,13 +1207,93 @@ EOF
   LIBS="$LIBS -lresolv"
 fi
 
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1212: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+    # This must be in double quotes, not single quotes, because CPP may get
+  # substituted into the Makefile and "${CC-cc}" will confuse make.
+  CPP="${CC-cc} -E"
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp.
+  cat > conftest.$ac_ext <<EOF
+#line 1227 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1233: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -E -traditional-cpp"
+  cat > conftest.$ac_ext <<EOF
+#line 1244 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1250: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP="${CC-cc} -nologo -E"
+  cat > conftest.$ac_ext <<EOF
+#line 1261 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1267: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  :
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+  ac_cv_prog_CPP="$CPP"
+fi
+  CPP="$ac_cv_prog_CPP"
+else
+  ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1386: checking for ANSI C header files" >&5
+echo "configure:1292: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1391 "configure"
+#line 1297 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1395,7 +1301,7 @@ else
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1399: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1305: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1412,7 +1318,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1416 "configure"
+#line 1322 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1430,7 +1336,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1434 "configure"
+#line 1340 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1451,7 +1357,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1455 "configure"
+#line 1361 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1462,7 +1368,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 exit (0); }
 
 EOF
-if { (eval echo configure:1466: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1372: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -1485,219 +1391,62 @@ EOF
 
 fi
 
-echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6
-echo "configure:1490: checking for sys/wait.h that is POSIX.1 compatible" >&5
-if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then
+
+echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
+echo "configure:1397: checking whether byte ordering is bigendian" >&5
+if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
-  cat > conftest.$ac_ext <<EOF
-#line 1495 "configure"
+  ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat > conftest.$ac_ext <<EOF
+#line 1404 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
-#include <sys/wait.h>
-#ifndef WEXITSTATUS
-#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#include <sys/param.h>
+int main() {
+
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
 #endif
+; return 0; }
+EOF
+if { (eval echo configure:1415: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+  rm -rf conftest*
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+cat > conftest.$ac_ext <<EOF
+#line 1419 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
 int main() {
-int s;
-wait (&s);
-s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
 ; return 0; }
 EOF
-if { (eval echo configure:1511: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1430: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
-  ac_cv_header_sys_wait_h=yes
+  ac_cv_c_bigendian=yes
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
   rm -rf conftest*
-  ac_cv_header_sys_wait_h=no
+  ac_cv_c_bigendian=no
 fi
 rm -f conftest*
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
 fi
-
-echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6
-if test $ac_cv_header_sys_wait_h = yes; then
-  cat >> confdefs.h <<\EOF
-#define HAVE_SYS_WAIT_H 1
-EOF
-
-fi
-
-for ac_hdr in malloc.h sys/malloc.h fcntl.h string.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h memory.h errno.h net/errno.h sys/cdefs.h
-do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1535: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
+rm -f conftest*
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1540 "configure"
-#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1545: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=yes"
-else
-  echo "$ac_err" >&5
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
-else
-  echo "$ac_t""no" 1>&6
-fi
-done
-
-
-echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1573: checking for working const" >&5
-if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 1578 "configure"
-#include "confdefs.h"
-
-int main() {
-
-/* Ultrix mips cc rejects this.  */
-typedef int charset[2]; const charset x;
-/* SunOS 4.1.1 cc rejects this.  */
-char const *const *ccp;
-char **p;
-/* NEC SVR4.0.2 mips cc rejects this.  */
-struct point {int x, y;};
-static struct point const zero = {0,0};
-/* AIX XL C 1.02.0.0 rejects this.
-   It does not let you subtract one const X* pointer from another in an arm
-   of an if-expression whose if-part is not a constant expression */
-const char *g = "string";
-ccp = &g + (g ? g-g : 0);
-/* HPUX 7.0 cc rejects these. */
-++ccp;
-p = (char**) ccp;
-ccp = (char const *const *) p;
-{ /* SCO 3.2v4 cc rejects this.  */
-  char *t;
-  char const *s = 0 ? (char *) 0 : (char const *) 0;
-
-  *t++ = 0;
-}
-{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
-  int x[] = {25, 17};
-  const int *foo = &x[0];
-  ++foo;
-}
-{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
-  typedef const int *iptr;
-  iptr p = 0;
-  ++p;
-}
-{ /* AIX XL C 1.02.0.0 rejects this saying
-     "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
-  struct s { int j; const int *ap[3]; };
-  struct s *b; b->j = 5;
-}
-{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
-  const int foo = 10;
-}
-
-; return 0; }
-EOF
-if { (eval echo configure:1627: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  ac_cv_c_const=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_c_const=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_c_const" 1>&6
-if test $ac_cv_c_const = no; then
-  cat >> confdefs.h <<\EOF
-#define const 
-EOF
-
-fi
-
-echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1648: checking whether byte ordering is bigendian" >&5
-if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_cv_c_bigendian=unknown
-# See if sys/param.h defines the BYTE_ORDER macro.
-cat > conftest.$ac_ext <<EOF
-#line 1655 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <sys/param.h>
-int main() {
-
-#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
- bogus endian macros
-#endif
-; return 0; }
-EOF
-if { (eval echo configure:1666: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  # It does; now see whether it defined to BIG_ENDIAN or not.
-cat > conftest.$ac_ext <<EOF
-#line 1670 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <sys/param.h>
-int main() {
-
-#if BYTE_ORDER != BIG_ENDIAN
- not big endian
-#endif
-; return 0; }
-EOF
-if { (eval echo configure:1681: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  ac_cv_c_bigendian=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_c_bigendian=no
-fi
-rm -f conftest*
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-fi
-rm -f conftest*
-if test $ac_cv_c_bigendian = unknown; then
-if test "$cross_compiling" = yes; then
-    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
-else
-  cat > conftest.$ac_ext <<EOF
-#line 1701 "configure"
+#line 1450 "configure"
 #include "confdefs.h"
 main () {
   /* Are we little or big endian?  From Harbison&Steele.  */
@@ -1710,7 +1459,7 @@ main () {
   exit (u.c[sizeof (long) - 1] == 1);
 }
 EOF
-if { (eval echo configure:1714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1463: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_bigendian=no
 else
@@ -1734,12 +1483,12 @@ EOF
 fi
 
 echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1738: checking for size_t" >&5
+echo "configure:1487: checking for size_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1743 "configure"
+#line 1492 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1767,12 +1516,12 @@ EOF
 fi
 
 echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:1771: checking whether time.h and sys/time.h may both be included" >&5
+echo "configure:1520: checking whether time.h and sys/time.h may both be included" >&5
 if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1776 "configure"
+#line 1525 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/time.h>
@@ -1781,7 +1530,7 @@ int main() {
 struct tm *tp;
 ; return 0; }
 EOF
-if { (eval echo configure:1785: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1534: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_header_time=yes
 else
@@ -1802,12 +1551,12 @@ EOF
 fi
 
 echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6
-echo "configure:1806: checking whether struct tm is in sys/time.h or time.h" >&5
+echo "configure:1555: checking whether struct tm is in sys/time.h or time.h" >&5
 if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1811 "configure"
+#line 1560 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <time.h>
@@ -1815,7 +1564,7 @@ int main() {
 struct tm *tp; tp->tm_sec;
 ; return 0; }
 EOF
-if { (eval echo configure:1819: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1568: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_struct_tm=time.h
 else
@@ -1836,12 +1585,12 @@ EOF
 fi
 
 echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
-echo "configure:1840: checking for uid_t in sys/types.h" >&5
+echo "configure:1589: checking for uid_t in sys/types.h" >&5
 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1845 "configure"
+#line 1594 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 EOF
@@ -1870,7 +1619,7 @@ EOF
 fi
 
 echo $ac_n "checking size of short""... $ac_c" 1>&6
-echo "configure:1874: checking size of short" >&5
+echo "configure:1623: checking size of short" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_short'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1878,7 +1627,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1882 "configure"
+#line 1631 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1889,7 +1638,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1893: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1642: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_short=`cat conftestval`
 else
@@ -1909,7 +1658,7 @@ EOF
 
 
 echo $ac_n "checking size of int""... $ac_c" 1>&6
-echo "configure:1913: checking size of int" >&5
+echo "configure:1662: checking size of int" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1917,7 +1666,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1921 "configure"
+#line 1670 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1928,7 +1677,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1932: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1681: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_int=`cat conftestval`
 else
@@ -1948,7 +1697,7 @@ EOF
 
 
 echo $ac_n "checking size of long""... $ac_c" 1>&6
-echo "configure:1952: checking size of long" >&5
+echo "configure:1701: checking size of long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1956,7 +1705,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1960 "configure"
+#line 1709 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1967,7 +1716,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1971: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1720: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_long=`cat conftestval`
 else
@@ -1988,12 +1737,12 @@ EOF
 
 if test "$ac_cv_sizeof_int" = 2 ; then
   echo $ac_n "checking for int16_t""... $ac_c" 1>&6
-echo "configure:1992: checking for int16_t" >&5
+echo "configure:1741: checking for int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1997 "configure"
+#line 1746 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2021,12 +1770,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6
-echo "configure:2025: checking for u_int16_t" >&5
+echo "configure:1774: checking for u_int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2030 "configure"
+#line 1779 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2055,12 +1804,12 @@ fi
 
 elif test "$ac_cv_sizeof_short" = 2 ; then
   echo $ac_n "checking for int16_t""... $ac_c" 1>&6
-echo "configure:2059: checking for int16_t" >&5
+echo "configure:1808: checking for int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2064 "configure"
+#line 1813 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2088,12 +1837,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6
-echo "configure:2092: checking for u_int16_t" >&5
+echo "configure:1841: checking for u_int16_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int16_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2097 "configure"
+#line 1846 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2125,12 +1874,12 @@ else
 fi
 if test "$ac_cv_sizeof_int" = 4 ; then
   echo $ac_n "checking for int32_t""... $ac_c" 1>&6
-echo "configure:2129: checking for int32_t" >&5
+echo "configure:1878: checking for int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2134 "configure"
+#line 1883 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2158,12 +1907,12 @@ EOF
 fi
 
   echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
-echo "configure:2162: checking for u_int32_t" >&5
+echo "configure:1911: checking for u_int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2167 "configure"
+#line 1916 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2192,79 +1941,12 @@ fi
 
 elif test "$ac_cv_sizeof_short" = 4 ; then
   echo $ac_n "checking for int32_t""... $ac_c" 1>&6
-echo "configure:2196: checking for int32_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2201 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "(^|[^a-zA-Z_0-9])int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_type_int32_t=yes
-else
-  rm -rf conftest*
-  ac_cv_type_int32_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_int32_t" 1>&6
-if test $ac_cv_type_int32_t = no; then
-  cat >> confdefs.h <<\EOF
-#define int32_t short
-EOF
-
-fi
-
-  echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
-echo "configure:2229: checking for u_int32_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2234 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_type_u_int32_t=yes
-else
-  rm -rf conftest*
-  ac_cv_type_u_int32_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6
-if test $ac_cv_type_u_int32_t = no; then
-  cat >> confdefs.h <<\EOF
-#define u_int32_t unsigned short
-EOF
-
-fi
-
-elif test "$ac_cv_sizeof_long" = 4 ; then
-  echo $ac_n "checking for int32_t""... $ac_c" 1>&6
-echo "configure:2263: checking for int32_t" >&5
+echo "configure:1945: checking for int32_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2268 "configure"
+#line 1950 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -2272,698 +1954,270 @@ else
 #include <stddef.h>
 #endif
 EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "(^|[^a-zA-Z_0-9])int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_type_int32_t=yes
-else
-  rm -rf conftest*
-  ac_cv_type_int32_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_int32_t" 1>&6
-if test $ac_cv_type_int32_t = no; then
-  cat >> confdefs.h <<\EOF
-#define int32_t long
-EOF
-
-fi
-
-  echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
-echo "configure:2296: checking for u_int32_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2301 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_type_u_int32_t=yes
-else
-  rm -rf conftest*
-  ac_cv_type_u_int32_t=no
-fi
-rm -f conftest*
-
-fi
-echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6
-if test $ac_cv_type_u_int32_t = no; then
-  cat >> confdefs.h <<\EOF
-#define u_int32_t unsigned long
-EOF
-
-fi
-
-else
-  { echo "configure: error: Cannot find a type with size of 32 bits" 1>&2; exit 1; }
-fi
-
-echo $ac_n "checking size of size_t""... $ac_c" 1>&6
-echo "configure:2333: checking size of size_t" >&5
-if eval "test \"`echo '$''{'ac_cv_sizeof_size_t'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2341 "configure"
-#include "confdefs.h"
-#include <stdio.h>
-main()
-{
-  FILE *f=fopen("conftestval", "w");
-  if (!f) exit(1);
-  fprintf(f, "%d\n", sizeof(size_t));
-  exit(0);
-}
-EOF
-if { (eval echo configure:2352: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ac_cv_sizeof_size_t=`cat conftestval`
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_sizeof_size_t=0
-fi
-rm -fr conftest*
-fi
-
-fi
-echo "$ac_t""$ac_cv_sizeof_size_t" 1>&6
-cat >> confdefs.h <<EOF
-#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
-EOF
-
-echo $ac_n "checking printf format of size_t""... $ac_c" 1>&6
-echo "configure:2371: checking printf format of size_t" >&5
-if test "$ac_cv_sizeof_size_t" = 4 ; then
-  echo "$ac_t"""%u"" 1>&6
-  cat >> confdefs.h <<\EOF
-#define SIZE_T_FMT "%u"
-EOF
-
-else
-  echo "$ac_t"""%lu"" 1>&6
-  cat >> confdefs.h <<\EOF
-#define SIZE_T_FMT "%lu"
-EOF
-
-fi
-echo $ac_n "checking size of time_t""... $ac_c" 1>&6
-echo "configure:2386: checking size of time_t" >&5
-if eval "test \"`echo '$''{'unet_cv_sizeof_time_t'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-  unet_cv_sizeof_time_t=0
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2394 "configure"
-#include "confdefs.h"
-#include <stdio.h>
-#include <sys/types.h>
-main()
-{
-  FILE *f=fopen("conftestval", "w");
-  if (!f) exit(1);
-  fprintf(f, "%d\n", sizeof(time_t));
-  exit(0);
-}
-EOF
-if { (eval echo configure:2406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  unet_cv_sizeof_time_t=`cat conftestval`
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  unet_cv_sizeof_time_t=0
-fi
-rm -fr conftest*
-fi
-
-fi
-
-if test "$unet_cv_sizeof_time_t" = 0 ; then
-  echo "$ac_t""unknown" 1>&6
-  cat >> confdefs.h <<\EOF
-#define TIME_T_FMT "%lu"
-EOF
-
-  cat >> confdefs.h <<\EOF
-#define STIME_T_FMT "%ld"
-EOF
-
-else
-  echo "$ac_t""$unet_cv_sizeof_time_t" 1>&6
-  echo $ac_n "checking printf format of time_t""... $ac_c" 1>&6
-echo "configure:2433: checking printf format of time_t" >&5
-  if test "$unet_cv_sizeof_time_t" = "$ac_cv_sizeof_long" ; then
-    echo "$ac_t"""%lu"" 1>&6
-    cat >> confdefs.h <<\EOF
-#define TIME_T_FMT "%lu"
-EOF
-
-    cat >> confdefs.h <<\EOF
-#define STIME_T_FMT "%ld"
-EOF
-
-  else
-    echo "$ac_t"""%u"" 1>&6
-    cat >> confdefs.h <<\EOF
-#define TIME_T_FMT "%u"
-EOF
-
-    cat >> confdefs.h <<\EOF
-#define STIME_T_FMT "%d"
-EOF
-
-  fi
-fi
-
-if test $ac_cv_prog_gcc = yes; then
-    echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
-echo "configure:2459: checking whether ${CC-cc} needs -traditional" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-    ac_pattern="Autoconf.*'x'"
-  cat > conftest.$ac_ext <<EOF
-#line 2465 "configure"
-#include "confdefs.h"
-#include <sgtty.h>
-Autoconf TIOCGETP
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "$ac_pattern" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_prog_gcc_traditional=yes
-else
-  rm -rf conftest*
-  ac_cv_prog_gcc_traditional=no
-fi
-rm -f conftest*
-
-
-  if test $ac_cv_prog_gcc_traditional = no; then
-    cat > conftest.$ac_ext <<EOF
-#line 2483 "configure"
-#include "confdefs.h"
-#include <termio.h>
-Autoconf TCGETA
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  egrep "$ac_pattern" >/dev/null 2>&1; then
-  rm -rf conftest*
-  ac_cv_prog_gcc_traditional=yes
-fi
-rm -f conftest*
-
-  fi
-fi
-
-echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
-  if test $ac_cv_prog_gcc_traditional = yes; then
-    CC="$CC -traditional"
-  fi
-fi
-
-echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6
-echo "configure:2505: checking for 8-bit clean memcmp" >&5
-if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-  ac_cv_func_memcmp_clean=no
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2513 "configure"
-#include "confdefs.h"
-
-main()
-{
-  char c0 = 0x40, c1 = 0x80, c2 = 0x81;
-  exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1);
-}
-
-EOF
-if { (eval echo configure:2523: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ac_cv_func_memcmp_clean=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_func_memcmp_clean=no
-fi
-rm -fr conftest*
-fi
-
-fi
-
-echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6
-test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
-
-echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6
-echo "configure:2541: checking whether setvbuf arguments are reversed" >&5
-if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  if test "$cross_compiling" = yes; then
-    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2549 "configure"
-#include "confdefs.h"
-#include <stdio.h>
-/* If setvbuf has the reversed format, exit 0. */
-main () {
-  /* This call has the arguments reversed.
-     A reversed system may check and see that the address of main
-     is not _IOLBF, _IONBF, or _IOFBF, and return nonzero.  */
-  if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0)
-    exit(1);
-  putc('\r', stdout);
-  exit(0);                     /* Non-reversed systems segv here.  */
-}
-EOF
-if { (eval echo configure:2563: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
-  ac_cv_func_setvbuf_reversed=yes
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -fr conftest*
-  ac_cv_func_setvbuf_reversed=no
-fi
-rm -fr conftest*
-fi
-
-rm -f core core.* *.core
-fi
-
-echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6
-if test $ac_cv_func_setvbuf_reversed = yes; then
-  cat >> confdefs.h <<\EOF
-#define SETVBUF_REVERSED 1
-EOF
-
-fi
-
-echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:2587: checking return type of signal handlers" >&5
-if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2592 "configure"
-#include "confdefs.h"
-#include <sys/types.h>
-#include <signal.h>
-#ifdef signal
-#undef signal
-#endif
-#ifdef __cplusplus
-extern "C" void (*signal (int, void (*)(int)))(int);
-#else
-void (*signal ()) ();
-#endif
-
-int main() {
-int i;
-; return 0; }
-EOF
-if { (eval echo configure:2609: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
-  rm -rf conftest*
-  ac_cv_type_signal=void
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  ac_cv_type_signal=int
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_type_signal" 1>&6
-cat >> confdefs.h <<EOF
-#define RETSIGTYPE $ac_cv_type_signal
-EOF
-
-
-echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:2628: checking for vprintf" >&5
-if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  cat > conftest.$ac_ext <<EOF
-#line 2633 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char vprintf(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char vprintf();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_vprintf) || defined (__stub___vprintf)
-choke me
-#else
-vprintf();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:2656: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
   rm -rf conftest*
-  eval "ac_cv_func_vprintf=yes"
+  ac_cv_type_int32_t=yes
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
   rm -rf conftest*
-  eval "ac_cv_func_vprintf=no"
+  ac_cv_type_int32_t=no
 fi
 rm -f conftest*
-fi
 
-if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
+fi
+echo "$ac_t""$ac_cv_type_int32_t" 1>&6
+if test $ac_cv_type_int32_t = no; then
   cat >> confdefs.h <<\EOF
-#define HAVE_VPRINTF 1
+#define int32_t short
 EOF
 
-else
-  echo "$ac_t""no" 1>&6
 fi
 
-if test "$ac_cv_func_vprintf" != yes; then
-echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:2680: checking for _doprnt" >&5
-if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+  echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
+echo "configure:1978: checking for u_int32_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2685 "configure"
+#line 1983 "configure"
 #include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char _doprnt(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char _doprnt();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub__doprnt) || defined (__stub____doprnt)
-choke me
-#else
-_doprnt();
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
 #endif
-
-; return 0; }
 EOF
-if { (eval echo configure:2708: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
   rm -rf conftest*
-  eval "ac_cv_func__doprnt=yes"
+  ac_cv_type_u_int32_t=yes
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
   rm -rf conftest*
-  eval "ac_cv_func__doprnt=no"
+  ac_cv_type_u_int32_t=no
 fi
 rm -f conftest*
-fi
 
-if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
+fi
+echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6
+if test $ac_cv_type_u_int32_t = no; then
   cat >> confdefs.h <<\EOF
-#define HAVE_DOPRNT 1
+#define u_int32_t unsigned short
 EOF
 
-else
-  echo "$ac_t""no" 1>&6
-fi
-
 fi
 
-for ac_func in strchr memcpy memmove
-do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2735: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+elif test "$ac_cv_sizeof_long" = 4 ; then
+  echo $ac_n "checking for int32_t""... $ac_c" 1>&6
+echo "configure:2012: checking for int32_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2740 "configure"
+#line 2017 "configure"
 #include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
 #endif
-
-; return 0; }
 EOF
-if { (eval echo configure:2763: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
   rm -rf conftest*
-  eval "ac_cv_func_$ac_func=yes"
+  ac_cv_type_int32_t=yes
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
   rm -rf conftest*
-  eval "ac_cv_func_$ac_func=no"
+  ac_cv_type_int32_t=no
 fi
 rm -f conftest*
-fi
 
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
+fi
+echo "$ac_t""$ac_cv_type_int32_t" 1>&6
+if test $ac_cv_type_int32_t = no; then
+  cat >> confdefs.h <<\EOF
+#define int32_t long
 EOF
-else
-  echo "$ac_t""no" 1>&6
+
 fi
-done
 
-for ac_func in gethostname gettimeofday mkdir strerror strtoken
-do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2790: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+  echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6
+echo "configure:2045: checking for u_int32_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2795 "configure"
+#line 2050 "configure"
 #include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
 #endif
-
-; return 0; }
 EOF
-if { (eval echo configure:2818: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  egrep "(^|[^a-zA-Z_0-9])u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
   rm -rf conftest*
-  eval "ac_cv_func_$ac_func=yes"
+  ac_cv_type_u_int32_t=yes
 else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
   rm -rf conftest*
-  eval "ac_cv_func_$ac_func=no"
+  ac_cv_type_u_int32_t=no
 fi
 rm -f conftest*
-fi
 
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
+fi
+echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6
+if test $ac_cv_type_u_int32_t = no; then
+  cat >> confdefs.h <<\EOF
+#define u_int32_t unsigned long
 EOF
+
+fi
+
 else
-  echo "$ac_t""no" 1>&6
+  { echo "configure: error: Cannot find a type with size of 32 bits" 1>&2; exit 1; }
 fi
-done
 
-for ac_func in select socket uname
-do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2845: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+echo $ac_n "checking size of size_t""... $ac_c" 1>&6
+echo "configure:2082: checking size of size_t" >&5
+if eval "test \"`echo '$''{'ac_cv_sizeof_size_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+    { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 2850 "configure"
+#line 2090 "configure"
 #include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
-#endif
-
-; return 0; }
+#include <stdio.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(size_t));
+  exit(0);
+}
 EOF
-if { (eval echo configure:2873: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=yes"
+if { (eval echo configure:2101: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  ac_cv_sizeof_size_t=`cat conftestval`
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=no"
+  rm -fr conftest*
+  ac_cv_sizeof_size_t=0
 fi
-rm -f conftest*
+rm -fr conftest*
 fi
 
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
+fi
+echo "$ac_t""$ac_cv_sizeof_size_t" 1>&6
+cat >> confdefs.h <<EOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
 EOF
+
+echo $ac_n "checking printf format of size_t""... $ac_c" 1>&6
+echo "configure:2120: checking printf format of size_t" >&5
+if test "$ac_cv_sizeof_size_t" = 4 ; then
+  echo "$ac_t"""%u"" 1>&6
+  cat >> confdefs.h <<\EOF
+#define SIZE_T_FMT "%u"
+EOF
+
 else
-  echo "$ac_t""no" 1>&6
-fi
-done
+  echo "$ac_t"""%lu"" 1>&6
+  cat >> confdefs.h <<\EOF
+#define SIZE_T_FMT "%lu"
+EOF
 
-for ac_func in setrlimit inet_netof getrusage times res_init
-do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2900: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+fi
+echo $ac_n "checking size of time_t""... $ac_c" 1>&6
+echo "configure:2135: checking size of time_t" >&5
+if eval "test \"`echo '$''{'unet_cv_sizeof_time_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
+else
+  if test "$cross_compiling" = yes; then
+  unet_cv_sizeof_time_t=0
 else
   cat > conftest.$ac_ext <<EOF
-#line 2905 "configure"
+#line 2143 "configure"
 #include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $ac_func(); below.  */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
-    to always fail with ENOSYS.  Some functions are actually named
-    something starting with __ and the normal name is an alias.  */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
-#endif
-
-; return 0; }
+#include <stdio.h>
+#include <sys/types.h>
+main()
+{
+  FILE *f=fopen("conftestval", "w");
+  if (!f) exit(1);
+  fprintf(f, "%d\n", sizeof(time_t));
+  exit(0);
+}
 EOF
-if { (eval echo configure:2928: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=yes"
+if { (eval echo configure:2155: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+then
+  unet_cv_sizeof_time_t=`cat conftestval`
 else
   echo "configure: failed program was:" >&5
   cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_func_$ac_func=no"
+  rm -fr conftest*
+  unet_cv_sizeof_time_t=0
 fi
-rm -f conftest*
+rm -fr conftest*
 fi
 
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
+fi
+
+if test "$unet_cv_sizeof_time_t" = 0 ; then
+  echo "$ac_t""unknown" 1>&6
+  cat >> confdefs.h <<\EOF
+#define TIME_T_FMT "%lu"
 EOF
+
+  cat >> confdefs.h <<\EOF
+#define STIME_T_FMT "%ld"
+EOF
+
 else
-  echo "$ac_t""no" 1>&6
+  echo "$ac_t""$unet_cv_sizeof_time_t" 1>&6
+  echo $ac_n "checking printf format of time_t""... $ac_c" 1>&6
+echo "configure:2182: checking printf format of time_t" >&5
+  if test "$unet_cv_sizeof_time_t" = "$ac_cv_sizeof_long" ; then
+    echo "$ac_t"""%lu"" 1>&6
+    cat >> confdefs.h <<\EOF
+#define TIME_T_FMT "%lu"
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define STIME_T_FMT "%ld"
+EOF
+
+  else
+    echo "$ac_t"""%u"" 1>&6
+    cat >> confdefs.h <<\EOF
+#define TIME_T_FMT "%u"
+EOF
+
+    cat >> confdefs.h <<\EOF
+#define STIME_T_FMT "%d"
+EOF
+
+  fi
 fi
-done
 
 
 for ac_hdr in poll.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:2957: checking for $ac_hdr" >&5
+echo "configure:2211: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2962 "configure"
+#line 2216 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2967: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2221: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -2990,10 +2244,10 @@ fi
 done
 if test -z "$unet_cv_func_poll_syscall" ; then
   echo $ac_n "checking if poll is a system call (please wait)""... $ac_c" 1>&6
-echo "configure:2994: checking if poll is a system call (please wait)" >&5
+echo "configure:2248: checking if poll is a system call (please wait)" >&5
 else
   echo $ac_n "checking if poll is a system call""... $ac_c" 1>&6
-echo "configure:2997: checking if poll is a system call" >&5
+echo "configure:2251: checking if poll is a system call" >&5
 fi
 if eval "test \"`echo '$''{'unet_cv_func_poll_syscall'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -3029,7 +2283,7 @@ echo "$ac_t""$unet_cv_func_poll_syscall" 1>&6
 
 
 echo $ac_n "checking for restartable system calls""... $ac_c" 1>&6
-echo "configure:3033: checking for restartable system calls" >&5
+echo "configure:2287: checking for restartable system calls" >&5
 if eval "test \"`echo '$''{'ac_cv_sys_restartable_syscalls'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3037,7 +2291,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 3041 "configure"
+#line 2295 "configure"
 #include "confdefs.h"
 /* Exit 0 (true) if wait returns something other than -1,
    i.e. the pid of the child, which means that wait was restarted
@@ -3055,7 +2309,7 @@ main () {
 }
 
 EOF
-if { (eval echo configure:3059: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2313: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sys_restartable_syscalls=yes
 else
@@ -3078,12 +2332,12 @@ EOF
 fi
 
 
-for ac_prog in mawk gawk nawk awk
+for ac_prog in gawk mawk nawk awk
 do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:3087: checking for $ac_word" >&5
+echo "configure:2341: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3113,7 +2367,7 @@ test -n "$AWK" && break
 done
 
 echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:3117: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:2371: checking whether ${MAKE-make} sets \${MAKE}" >&5
 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -3151,7 +2405,7 @@ fi
 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 # ./install, which can be erroneously created by make from ./install.sh.
 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:3155: checking for a BSD compatible install" >&5
+echo "configure:2409: checking for a BSD compatible install" >&5
 if test -z "$INSTALL"; then
 if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -3204,7 +2458,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
 test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:3208: checking whether ln -s works" >&5
+echo "configure:2462: checking whether ln -s works" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3229,7 +2483,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:3233: checking for $ac_word" >&5
+echo "configure:2487: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_RMPROG'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3270,7 +2524,7 @@ do
 # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:3274: checking for $ac_word" >&5
+echo "configure:2528: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_path_SHPROG'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3308,7 +2562,7 @@ test -n "$SHPROG" || SHPROG="/bin/sh"
 
 
 echo $ac_n "checking for set -h""... $ac_c" 1>&6
-echo "configure:3312: checking for set -h" >&5
+echo "configure:2566: checking for set -h" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_set_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3327,7 +2581,7 @@ echo "$ac_t""$unet_cv_sys_set_h" 1>&6
 
 
 echo $ac_n "checking for posix non-blocking""... $ac_c" 1>&6
-echo "configure:3331: checking for posix non-blocking" >&5
+echo "configure:2585: checking for posix non-blocking" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_nonblocking_posix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3335,7 +2589,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 3339 "configure"
+#line 2593 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -3361,7 +2615,7 @@ int main(void)
   exit(1);
 }
 EOF
-if { (eval echo configure:3365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2619: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_nonblocking_posix=yes
 else
@@ -3383,7 +2637,7 @@ EOF
 
 else
 echo $ac_n "checking for bsd non-blocking""... $ac_c" 1>&6
-echo "configure:3387: checking for bsd non-blocking" >&5
+echo "configure:2641: checking for bsd non-blocking" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_nonblocking_bsd'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3391,7 +2645,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 3395 "configure"
+#line 2649 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -3417,7 +2671,7 @@ int main(void)
   exit(1);
 }
 EOF
-if { (eval echo configure:3421: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2675: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_nonblocking_bsd=yes
 else
@@ -3445,19 +2699,19 @@ EOF
 fi
 fi
 echo $ac_n "checking for posix signals""... $ac_c" 1>&6
-echo "configure:3449: checking for posix signals" >&5
+echo "configure:2703: checking for posix signals" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_signal_posix'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 3454 "configure"
+#line 2708 "configure"
 #include "confdefs.h"
 #include <signal.h>
 int main() {
 sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L)
 ; return 0; }
 EOF
-if { (eval echo configure:3461: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2715: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   unet_cv_sys_signal_posix=yes
 else
@@ -3477,7 +2731,7 @@ EOF
 
 else
 echo $ac_n "checking for bsd reliable signals""... $ac_c" 1>&6
-echo "configure:3481: checking for bsd reliable signals" >&5
+echo "configure:2735: checking for bsd reliable signals" >&5
 if eval "test \"`echo '$''{'unet_cv_sys_signal_bsd'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -3485,7 +2739,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 3489 "configure"
+#line 2743 "configure"
 #include "confdefs.h"
 #include <signal.h>
 int calls = 0;
@@ -3503,7 +2757,7 @@ int main(void)
   exit (0);
 }
 EOF
-if { (eval echo configure:3507: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2761: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   unet_cv_sys_signal_bsd=yes
 else
@@ -3532,20 +2786,20 @@ fi
 fi
 
 echo $ac_n "checking if the compiler understands -pipe""... $ac_c" 1>&6
-echo "configure:3536: checking if the compiler understands -pipe" >&5
+echo "configure:2790: checking if the compiler understands -pipe" >&5
 unet_cv_pipe_flags="$ac_cv_prog_gcc"
 if test "$ac_cv_prog_gcc" = no; then
   OLDCFLAGS="$CFLAGS"
   CFLAGS="$CFLAGS -pipe"
   cat > conftest.$ac_ext <<EOF
-#line 3542 "configure"
+#line 2796 "configure"
 #include "confdefs.h"
 
 int main() {
 
 ; return 0; }
 EOF
-if { (eval echo configure:3549: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2803: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   unet_cv_pipe_flags=yes
 else
@@ -3568,6 +2822,33 @@ fi
 
 
 
+uname=`uname`
+echo $ac_n "checking for OS type""... $ac_c" 1>&6
+echo "configure:2828: checking for OS type" >&5
+case "$uname" in
+  *inux*)
+    echo "$ac_t""$uname found." 1>&6
+    OSDEP_C="os_linux.c"
+  ;;
+  *olaris*)
+    echo "$ac_t""$uname found." 1>&6
+    OSDEP_C="os_solaris.c"
+  ;;
+  *SunOS*)
+    echo "$ac_t""$uname found." 1>&6
+    OSDEP_C="os_solaris.c"
+  ;;
+  *BSD*)
+    echo "$ac_t""$uname found." 1>&6
+    OSDEP_C="os_bsd.c"
+  ;;
+  *)
+    echo "$ac_t""Unknown OS. Using generic routines." 1>&6
+    OSDEP_C="os_generic.c"
+  ;;
+esac
+
+
 trap '' 1 2 15
 cat > confcache <<\EOF
 # This file is a shell script that caches the results of configure
@@ -3703,7 +2984,6 @@ s%@infodir@%$infodir%g
 s%@mandir@%$mandir%g
 s%@CC@%$CC%g
 s%@CPP@%$CPP%g
-s%@LIBOBJS@%$LIBOBJS%g
 s%@AWK@%$AWK%g
 s%@SET_MAKE@%$SET_MAKE%g
 s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
@@ -3716,6 +2996,7 @@ s%@unet_cv_sys_set_h@%$unet_cv_sys_set_h%g
 s%@ac_cv_header_poll_h@%$ac_cv_header_poll_h%g
 s%@ac_cv_header_syslog_h@%$ac_cv_header_syslog_h%g
 s%@unet_cv_func_poll_syscall@%$unet_cv_func_poll_syscall%g
+s%@OSDEP_C@%$OSDEP_C%g
 
 CEOF
 EOF
index 24596355bfa22eba9f1ccb14b91b72053f182774..5c2e776033b26709a8aac98631199d5e1a01bf31 100644 (file)
@@ -22,10 +22,9 @@ AC_PROG_CC
 
 dnl UNIX Variants
 dnl Allow the use of BSD functions on AIX.
-AC_AIX
+dnl AC_AIX
 dnl Allow the use of POSIX functions on several OS.
-AC_ISC_POSIX
-AC_MINIX
+dnl AC_ISC_POSIX
 dnl ANSIfy the C compiler whenever possible.
 AM_PROG_CC_STDC
 dnl Use -O3 instead of -O2.
@@ -50,11 +49,9 @@ unet_CHECK_LIB_RESOLV
 
 dnl Checks for header files.
 AC_HEADER_STDC
-AC_HEADER_SYS_WAIT
-AC_CHECK_HEADERS(malloc.h sys/malloc.h fcntl.h string.h strings.h sys/file.h sys/ioctl.h sys/time.h syslog.h unistd.h memory.h errno.h net/errno.h sys/cdefs.h)
 
 dnl Checks for typedefs, structures, and compiler characteristics.
-AC_C_CONST
+dnl AC_C_CONST
 AC_C_BIGENDIAN
 AC_TYPE_SIZE_T
 AC_HEADER_TIME
@@ -68,15 +65,9 @@ unet_DEFINE_SIZE_T_FMT
 unet_DEFINE_TIME_T_FMT
 
 dnl Checks for library functions.
-AC_PROG_GCC_TRADITIONAL
-AC_FUNC_MEMCMP
-AC_FUNC_SETVBUF_REVERSED
-AC_TYPE_SIGNAL
-AC_FUNC_VPRINTF
-AC_CHECK_FUNCS(strchr memcpy memmove)
-AC_CHECK_FUNCS(gethostname gettimeofday mkdir strerror strtoken)
-AC_CHECK_FUNCS(select socket uname)
-AC_CHECK_FUNCS(setrlimit inet_netof getrusage times res_init)
+dnl AC_PROG_GCC_TRADITIONAL
+dnl AC_FUNC_MEMCMP
+dnl AC_FUNC_VPRINTF
 
 dnl Do we have a system call poll?
 unet_FUNC_POLL_SYSCALL
@@ -117,5 +108,32 @@ AC_SUBST(ac_cv_header_poll_h)
 AC_SUBST(ac_cv_header_syslog_h)
 AC_SUBST(unet_cv_func_poll_syscall)
 
+dnl Check OS for os_dep files.
+uname=`uname`
+AC_MSG_CHECKING(for OS type)
+case "$uname" in
+  *inux*)
+    AC_MSG_RESULT($uname found.)
+    OSDEP_C="os_linux.c"
+  ;;
+  *olaris*)
+    AC_MSG_RESULT($uname found.)
+    OSDEP_C="os_solaris.c"
+  ;;
+  *SunOS*)
+    AC_MSG_RESULT($uname found.)
+    OSDEP_C="os_solaris.c"
+  ;;
+  *BSD*)
+    AC_MSG_RESULT($uname found.)
+    OSDEP_C="os_bsd.c"
+  ;;
+  *)
+    AC_MSG_RESULT(Unknown OS. Using generic routines.)
+    OSDEP_C="os_generic.c"
+  ;;
+esac
+AC_SUBST(OSDEP_C)
+
 dnl Finally really generate all output files:
 AC_OUTPUT(config-sh Configure ../Makefile ../ircd/Makefile ../doc/Makefile Makefile, [echo timestamp > stamp-h;],)
index 84e336e00d4718cc2514eddc6c9418f88184628b..c1a3a39edc8f5b2479ce16cb2b625a960e11f393 100644 (file)
  * 02111-1307, USA.
  */
 
-/* Define if on AIX 3.
-   System headers sometimes define this.
-   We just want to avoid a redefinition error message.  */
-#ifndef _ALL_SOURCE
-#undef _ALL_SOURCE
-#endif
-
-/* Define to empty if the keyword does not work.  */
-#undef const
-
 /* Define to `int' if <sys/types.h> doesn't define.  */
 #undef gid_t
 
-/* Define if you don't have vprintf but do have _doprnt.  */
-#undef HAVE_DOPRNT
-
 /* Define if system calls automatically restart after interruption
    by a signal.  */
 #undef HAVE_RESTARTABLE_SYSCALLS
 
-/* Define if you have <sys/wait.h> that is POSIX.1 compatible.  */
-#undef HAVE_SYS_WAIT_H
-
-/* Define if you have the vprintf function.  */
-#undef HAVE_VPRINTF
-
-/* Define if on MINIX.  */
-#undef _MINIX
-
-/* Define if the system does not provide POSIX.1 features except
-   with this defined.  */
-#undef _POSIX_1_SOURCE
-
-/* Define if you need to in order for stat and other things to work.  */
-#undef _POSIX_SOURCE
-
-/* Define as the return type of signal handlers (int or void).  */
-#undef RETSIGTYPE
-
-/* Define if the setvbuf function takes the buffering type as its second
-   argument and the buffer pointer as the third, as on System V
-   before release 3.  */
-#undef SETVBUF_REVERSED
-
 /* Define to `unsigned' if <sys/types.h> doesn't define.  */
 #undef size_t
 
 /* The number of bytes in a size_t.  */
 #undef SIZEOF_SIZE_T
 
-/* Define if you have the gethostname function.  */
-#undef HAVE_GETHOSTNAME
-
-/* Define if you have the getrusage function.  */
-#undef HAVE_GETRUSAGE
-
-/* Define if you have the gettimeofday function.  */
-#undef HAVE_GETTIMEOFDAY
-
-/* Define if you have the inet_netof function.  */
-#undef HAVE_INET_NETOF
-
-/* Define if you have the memcpy function.  */
-#undef HAVE_MEMCPY
-
-/* Define if you have the memmove function.  */
-#undef HAVE_MEMMOVE
-
-/* Define if you have the mkdir function.  */
-#undef HAVE_MKDIR
-
-/* Define if you have the res_init function.  */
-#undef HAVE_RES_INIT
-
-/* Define if you have the select function.  */
-#undef HAVE_SELECT
-
-/* Define if you have the setrlimit function.  */
-#undef HAVE_SETRLIMIT
-
-/* Define if you have the socket function.  */
-#undef HAVE_SOCKET
-
-/* Define if you have the strchr function.  */
-#undef HAVE_STRCHR
-
-/* Define if you have the strerror function.  */
-#undef HAVE_STRERROR
-
-/* Define if you have the strtoken function.  */
-#undef HAVE_STRTOKEN
-
-/* Define if you have the times function.  */
-#undef HAVE_TIMES
-
-/* Define if you have the uname function.  */
-#undef HAVE_UNAME
-
-/* Define if you have the <errno.h> header file.  */
-#undef HAVE_ERRNO_H
-
-/* Define if you have the <fcntl.h> header file.  */
-#undef HAVE_FCNTL_H
-
-/* Define if you have the <malloc.h> header file.  */
-#undef HAVE_MALLOC_H
-
-/* Define if you have the <memory.h> header file.  */
-#undef HAVE_MEMORY_H
-
-/* Define if you have the <net/errno.h> header file.  */
-#undef HAVE_NET_ERRNO_H
-
 /* Define if you have the <poll.h> header file.  */
 #undef HAVE_POLL_H
 
-/* Define if you have the <string.h> header file.  */
-#undef HAVE_STRING_H
-
-/* Define if you have the <strings.h> header file.  */
-#undef HAVE_STRINGS_H
-
-/* Define if you have the <sys/cdefs.h> header file.  */
-#undef HAVE_SYS_CDEFS_H
-
-/* Define if you have the <sys/file.h> header file.  */
-#undef HAVE_SYS_FILE_H
-
-/* Define if you have the <sys/ioctl.h> header file.  */
-#undef HAVE_SYS_IOCTL_H
-
-/* Define if you have the <sys/malloc.h> header file.  */
-#undef HAVE_SYS_MALLOC_H
-
-/* Define if you have the <sys/time.h> header file.  */
-#undef HAVE_SYS_TIME_H
-
-/* Define if you have the <syslog.h> header file.  */
-#undef HAVE_SYSLOG_H
-
-/* Define if you have the <unistd.h> header file.  */
-#undef HAVE_UNISTD_H
-
 /* Define if you have the crypt library (-lcrypt).  */
 #undef HAVE_LIBCRYPT
index 31076f5e355ec013b6b10e020d6b9d8bc7fdfc10..2d85f303a272d6207b8a55f4f4148deb66b1f655 100644 (file)
@@ -142,13 +142,19 @@ UNDERNET (1991 - 1999)
 
 The Undernet versions (TSpre8, u2.9 and u2.10) are based on ircd-2.8.10 and
 contain thousands of hours of work by Carlo Wood <carlo@runaway.xs4all.nl>
-(Run on IRC). The number of protocol enhancements, changes and additions that
-have been added are too many to summarize.  All patches are kept in the patch
-repository at http://www.xs4all.nl/~carlo17/ircd-dev/
+(Run on IRC). The number of protocol enhancements, changes and additions
+that have been added are too many to summarize.  All patches are kept in the
+cvs repository at http://coder-com.undernet.org/.  Discussions on this
+server code are currently on the mailing list coder-com@undernet.org, or in
+#coder-com on undernet.
+
+The current maintainer is Bleep.
 
 Various additions and bugfixes have been contributed by:
 
 Aaron <agifford@sci.dixie.edu>
+Bleep <tomh@inxpress.net>
+CaptJay <captjay@superlink.net>
 CapVideo <majdi@puck.nether.net>
 Chaos <simon@troll.elec.uow.edu.au>
 Cym <cym@acrux.net>
@@ -156,11 +162,14 @@ Derrick <dirk@servtech.com>
 Ensor <dholmes@rahul.net>
 flux <cmlambertus@ucdavis.edu>
 Ghostwolf <foxxe@wolfspirit.org>
+Gte- <gte@atomicrevs.demon.co.uk>
+Isomer <isomer@coders.net>
 Jamey <woodjr@durrance.Colorado.EDU>
 Jarle <jarlel@II.UIB.NO>
 Kev <klmitch@mit.edu>
 Nemesi <cocito@tin.it>
 Niels <niels@holding.pi.net>
+Run <carlo@alinoe.com>
 record <jegelhof@cloud9.net>
 smg <smg@lm.com>
 SeKs <intru@step.polymtl.ca>
diff --git a/doc/exaconf.2 b/doc/exaconf.2
new file mode 100644 (file)
index 0000000..6e8ece2
--- /dev/null
@@ -0,0 +1,211 @@
+# Set the name of the server, its numeric, and the server info field
+serverinfo {
+       name "test.server.undernet.org";
+       capacity 6124;
+       numeric 18;
+       description "A test server for the next generation";
+
+       # this is an optional parameter to specify where outbound
+       # connections should originate from
+       addr "18.177.0.118";
+}
+
+# Select a seed from /dev/random or the appropriate local alternative.
+# If /dev/random doesn't exist, use a seed
+# Note: on Linux, /dev/urandom should probably be used--it won't block.
+seedfile "/dev/random";
+
+# Let's set up some logging
+logging {
+       syslog daemon; # set the syslog facility to daemon
+
+       logpath "/home/irc/logs" # path prepended to log file names
+
+       log kill syslog notice; # log kills to syslog at priority "notice"
+       log squit syslog notice;
+       log connect syslog debug;
+
+       log oper file "opers.log"; # log /opers to file "opers.log"
+       log gline file "gline.log";
+
+       nolog users; # turn off logging for users (default, but illustrative)
+
+       pid "ircd.pid";
+}
+
+binpath "/home/irc/bin/ircd"; # binary to exec() when we /restart
+libpath "/home/irc/lib"; # directory to chdir() to on start-up
+
+# Here's an authorization record--defines who is permitted on the server
+# and what special information needs to be remembered about them.
+auth everyone {
+       host "*@*";     # hosts this auth record matches
+       maxusers 1200;  # Max users for this auth record
+       perhost 2;      # Maximum of 2 users per host on this server
+       global 3;       # Maximum of 2 users per host on the entire network
+       ping 120;       # ping them once every 120 seconds if link inactive
+       sendq 270000;   # max sendq for everyone in the auth record
+}
+
+# Here's another one for miters people
+auth miters {
+       host "*@*.mit.edu";
+       host "*@18.*";
+       maxusers 1200;
+       perhost 1;
+       global 1;
+       ping 300;
+       sendq 120000;
+}
+
+# And here's a back door for my operators--perhaps to be used in an emergency
+auth opers {
+       host "*@*";
+       unset ident;    # no identd
+       unset banable;  # no denial rules
+       unset limit;    # ignore any limits
+       set ipspoof;    # hostname is spoofed to protect the guilty
+       password "MybacKd004!"; # password-only access
+       motd "opers.motd";      # a special MOTD for opers
+}
+
+port {
+       accept opers; # auth records are tried in order listed
+       accept miters;
+       accept everyone;
+
+       port 6660-6669 "18.177.0.118"; # ports to open
+       port 6660-6669 "18.177.0.119";
+}
+
+port {
+       set hide;
+
+       accept opers;
+
+       port 7000; # IP is optional and defaults to 0.0.0.0
+}
+
+port {
+       set hide;
+       set serveronly;
+
+       port 4400 "18.177.0.118";
+}
+
+# allow channel hacks and glines
+server uworld.undernet.org {
+       set channelhack;
+       set gline;
+}
+
+server uworld2.undernet.org {
+       set channelhack;
+       set gline;
+}
+
+server uworld.eu.undernet.org {
+       set channelhack;
+       set gline;
+}
+
+# allow channel hacks only
+server channels.undernet.org {
+       set channelhack;
+}
+
+server channels2.undernet.org {
+       set channelhack;
+}
+
+# here's some link class definitions for servers (only)
+class hubs {
+       limit 2;        # Max connection attempts per class
+       freq 600;       # Connect frequency
+       ping 300;       # how often to ping them
+       sendq 2700000;  # sendq
+}
+
+# Here's a hub link
+server santaclara.ca.us.undernet.org {
+       class hubs;                     # this is in the hubs link class
+
+       link 4400 "205.158.23.3";       # link address
+       password "toysrus";             # link password
+       set auto;                       # we'll auto to it
+       set hub;                        # it's a hub
+}
+
+server dallas-r.tx.us.undernet.org {
+       class hubs;
+
+       link 4400 "204.178.73.175";
+       password "areyouready?";
+       set auto;
+       set hub;
+
+       deny "linked(santaclara.ca.us.undernet.org)"; # a d-line
+}
+
+# here's a leaf
+server vancouver.bc.ca.undernet.org {
+       link 4400 "199.60.228.129";
+       password "toylink";
+       set auto;
+
+       denyoper "linked(santaclara.ca.us.undernet.org)"; # a D-line
+}
+
+# here's a set of default flags for opers
+#
+# the part before the '.' specifies the namespace the flags are from--
+# not necessary inside the user record itself, but we don't otherwise
+# know the namespace here.  The part after the '.' is a label.
+flagset user.oper {
+       set kill;       # allow kills...
+       set kline;      # allow kline/unkline
+       set gline;      # allow local glines
+       set rehash;     # can use /rehash
+       set restart;    # can use /restart
+       set die;        # can use /die
+       set wallops;    # can use /wallops
+       set connect;    # can use /connect and /squit
+       set stats;      # can use /stats
+       set info;       # can use /info
+       set opernotice; # can see oper-only notices
+       set massmsg;    # can use mass messages
+}
+
+# here's an operator
+user Kev {
+       default oper;                   # a set of flags for the user
+       cryptpass "J/7oDe78NhQ+/";      # password must be given to activate
+       host "*.mit.edu";               # must be from the listed hosts
+       host "*.ne.mediaone.net";
+       host "18.*";
+       host "168.159.*";
+}
+
+# nick jupes
+user Uworld {
+       set juped;
+}
+
+user Uworld2 {
+       set juped;
+}
+
+user EUworld {
+       set juped;
+}
+
+user X {
+       set juped;
+}
+
+user W {
+       set juped;
+}
+
+# File deny records are kept in; this can be modified from online
+denyfile "klines.conf";
index 8d8d023027c998b2e58d882917a10f707142797e..77da1d5036d9f4fe37e1a124077c91542db9d321 100644 (file)
 
 #
 # First some information about the server.
-# M:<server name>:<virtual ip>:<description>:<server port>:<server numeric>
+# M:<server name>:<virtual host>:<description>:<server port>:<server numeric>
 #
-# The <virtual ip> must be either be empty, contain a "*", or contain
-# the IP address of an interface on your system. If it contains an address,
-# the address will be bound to if you have specified virtual hosting.
+# <virtual host> must contain either a * or a valid IPv4 address in
+# dotted quad notation. (127.0.0.1) The address MUST be the address
+# of a physical interface on the host. This address is used for outgoing
+# connections only, see P:lines for listener virtual hosting.
+# If in doubt put a * or the IP of your primary interface here.
+# The server must be compiled with virtual hosting turned on to get this
+# to work correctly.
 #
-# The <server port> is the port that other servers can connect to.
-# Client ports need to be specified with a P: line, see below.
+# The <server port> is no longer used.
+# Ports need to be specified with a P: line, see below.
+# At some point in the future we may want to use the port value for
+# server capacity. --Bleep
 #
 # Note that <server numeric> has to be unique on the network your server
 # is running on, must be between 1 and 64, and is not updated on a rehash.
 
-# M:London.UK.Eu.UnderNet.org:127.0.0.1:University of London, England:4400:1
-M:London.UK.Eu.UnderNet.org:*:University of London, England:4400:1
+M:London.UK.Eu.UnderNet.org:*:University of London, England:0:1
 
 #
 # This sets information that can be retrieved with the /ADMIN command.
@@ -225,16 +230,6 @@ K:unixbox.flooder.co.uk:!kline/youflooded.txt:*luser
 # even if an IP address has a properly resolving host name.
 k:192.168.*:!klines/martians:*
 
-#
-# A more flexible way of restricting access to your server is the use
-# of "restriction lines". These tell the server to start up an (external)
-# program, upon whose output is decided whether the client is allowed
-# access. The program should print "Y" or "N <reason>" on its stdout.
-# Note that the use of R: lines is discouraged and deprecated, needs a
-# compile-time define, eats CPU cycles and may well be taken out in
-# future releases of ircd.
-# R:<host/IP mask>:<program name>:<username mask>
-
 #
 # You probably want your server connected to other servers, so your users
 # have other users to chat with.
@@ -247,28 +242,16 @@ k:192.168.*:!klines/martians:*
 # server links is provided for ircd to decide what links to allow, what
 # to let humans do themselves, and what links to (forcefully) disallow.
 #
-# The Connection and Allowing connection lines (also known as C/N lines)
+# The Connection lines (also known as C lines)
 # define what servers the server connect to, and which servers are
-# allowed to connect. Note that they come in pairs; they do not work if
-# one if present and the other is absent.
+# allowed to connect.
 # C:<remote hostname or IP>:<password>:<remote server name>:<port>:<class>
-# N:<remote hostname or IP>:<password>:<remote server name>:<hostmask>:<class>
 #
-# If you wish to use ident, prepend "username@" to the hostname or IP
-# address (the first field).
 # If the "port" field is omitted, the server will not attempt to
 # establish a link with that server ("not autoconnecting").
-# The (optional) "host mask" field tells the server to represent itself
-# with "hostmask" dot-seperateed fields stripped from its servername
-# and replace it with "*.".
-# For example, if hostmask == 2 and the local server name is
-# "irc.sub.domain.com" it would be sent as "*.domain.com". This allows
-# for easier routing and linking of new servers.
-# This feature is not used on Undernet.
 
 # Our primary uplink.
 C:1.2.3.4:passwd:Amsterdam.NL.Eu.UnderNet.org:4400:90
-N:1.2.3.4:passwd:Amsterdam.NL.Eu.UnderNet.org::90
 
 #
 # If your server starts on a bit larger network, you'll probably get
@@ -289,11 +272,11 @@ H:*.*::Amsterdam.NL.Eu.UnderNet.org
 # you can use Disallow lines. For more information, see doc/readme.crules.
 # D:<server mask that ircd will refuse to connect to>::<rule>
 # d:<server mask that ircd will not autoconnect to>::<rule>
-D:*.US.UnderNet.org::connected(*.US.UnderNet.org)
-d:*.EU.UnderNet.org::connected(Amsterdam.NL.EU.*)
+D:*.US.UnderNet.org::connected(*.US.UnderNet.org)
+d:*.EU.UnderNet.org::connected(Amsterdam.NL.EU.*)
 
 # The following line is recommended for leaf servers:
-d:*::directcon(*)
+d:*::directcon(*)
 
 #
 # Inevitably, you have reached the part about "IRC Operators". Oper status
@@ -323,31 +306,48 @@ O:*@*.cs.vu.nl:VRKLKuGKn0jLs:Niels::10
 # then use a connection class that allows more then one connection,
 # for example (using class 10 as in the example above):
 # Y:10:90:0:100:160000
-#
+
+# [P:lines]
 # When your server gets fuller, you will notice delays when trying to
 # connect to your server's primary listening port. Via the Port lines
-# it is possible to specify additional ports (both AF_UNIX and AF_INET)
-# for ircd to listen to.
+# it is possible to specify additional ports for ircd to listen to.
 # De facto ports are: 6667 - standard; 6660-6669 - additional client
 # ports;
-#
+# Undernet uses 4400 for server listener ports.
 # These are just hints, they are in no way official IANA or IETF policies.
 #
-# On a side note, the /UPING command uses port 7007/udp. If your server
-# is located behind a firewall, you may want to make another hole in it
-# for this port.
+# The interface setting allows multiply homed hosts to specify which
+# interface to use on a port by port basis, if an interface is not specified
+# the default interface will be used. The interface MUST be the complete
+# IP address for a real hardware interface on the machine running ircd.
+#
+# The [CS][H] field is an optional field to specify that a port is a
+# server port or a client port and whether it's hidden or not.
+# If used the first character MUST be either a C or S.
+# If you want to hide a port from /stats p from non-opers follow the C
+# or S with an H
 #
-# P:<hostmask, or path>:::<client port number>
+# P:<hostmask>:<interface>:<[CS][H]>:<client port number>
+#
+# This is a normal server port, you need to have at least one server
+# port defined if you want to connect your server to other servers.
+P:::S:4400
+# This is a Server port that is Hidden
+#P:::SH:4401
 
-P::::6667
+# The following are normal client ports
+P:::C:6667
 P::::6668
 P:*.nl:::6666
-P:/tmp/.ircd:::6667
+
+# This is a hidden client port, listening on the interface associated
+# with the IP address 168.8.21.107
+#P:*:168.8.21.107:CH:7000
 
 #
 # Well, you have now reached the end of this sample configuration file
 # If you have any questions, feel free to mail <doco-com@undernet.org>
-# or <wastelanders@undernet.org>.
+# or <coder-com@undernet.org>.
 # If you are interested in linking your server to the Undernet IRC network
 # visit http://www.routing-com.undernet.org/, and if there are any problems
 # then contact <routing-com@undernet.org> asking for information.
diff --git a/doc/fda.txt b/doc/fda.txt
new file mode 100644 (file)
index 0000000..d993ae5
--- /dev/null
@@ -0,0 +1,151 @@
+fdaman.txt - brief usage information for FDA (Free Debug Allocator)
+
+Copyright (C) 1998 Thomas Helvey <tomh@inxpress.net>
+
+1. Base Functionality
+Basic use of the fda tools is as simple as including the header
+and source file with your source defining DEBUG and using capitalized
+versions of malloc(), calloc(), realloc(), and free().
+The fda allocation functions verify all your arguments and will call
+assert() if something is wrong. FDA trashes all allocated memory
+in a predictable manner and applies prefix and postfix bounds checking
+signatures to every allocation. When a pointer is freed it's validated,
+and checked for overflows and underflows. The fda Realloc function
+does not allow malloc or free through realloc and forces reallocation
+if the required memory is larger than the current allocation.
+
+In both the DEBUG and non-debug versions of fda, if a memory allocation
+fails once, a low memory callback function is called to allow you to
+release some memory and allow malloc to succeed, the default version
+prints a warning message to stderr. If the low memory callback returns
+the allocation is attempted again, if the second allocation fails a
+no memory callback function is called to allow you to clean up before
+terminating the application, if you allow the no memory callback to
+return the results are undefined. (a NULL ptr will be returned from the
+allocation call) The default no memory handler prints an error message
+to stderr and calls abort(). The DEBUG version will assert if you allow
+the no memory function to return.
+Both the low memory and no memory callbacks have the signature of:
+void handler(void)
+
+The debug version of fda will not allow you to do the following:
+Allocate a zero length chunk of memory.
+Free a non-allocated pointer.
+Free a pointer twice.
+Free a pointer at the wrong offset.
+Use realloc to free memory. (realloc(p, 0))
+Use realloc to malloc memory. (realloc(0, s))
+Overwrite the bounds of the memory you allocated. (checked on free)
+
+The base functions for fda are:
+void* malloc(size_t)
+void* realloc(void*, size_t)
+void* calloc(size_t, size_t)
+void  free(void*)
+char* strdup(const char*)
+void  set_lowmem_handler(void (*fn)(void))
+void  set_nomem_handler(void (*fn)(void))
+
+FDA uses a hash table to lookup pointers. The size of the hash table can
+be changed at compile time by using -DFDA_HASH_TABLE_SIZE <prime>
+where prime is a prime number somewhere around the number of allocations
+expected. The default hash table size is 16339 which should be large enough
+to hold most medium sized applications. FDA allocates memory for it's
+debugging records so if your application uses a lot of memory you
+may want to make sure you have enough memory available to use the debug
+version. FDA allocates 20 bytes to store each allocation and 20 bytes
+to store location information (file and line info). This overhead only
+applies if you have DEBUG or _DEBUG defined.
+
+2. Extended functionality
+FDA provides a few handy functions for validating pointers and
+checking for overruns before they occur when debugging.
+The first function fda_sizeof(ptr) returns the size of the buffer
+pointed to by ptr, this allows you to verify that your pointer
+is what it says it is. fda_sizeof() will call assert() if the
+pointer you pass it is not at the start of an allocation.
+
+The second function valid_ptr(ptr, size) verifies that ptr lies within
+allocated memory and there are at least size bytes available in the buffer.
+You can pass valid_ptr() a pointer to any location in allocated memory.
+valid_ptr() calls assert if the pointer points outside of allocated memory
+or the remaining size is less than the size specified.
+valid_ptr() is more efficient if the pointer argument is the value
+returned from malloc because it's a simple hash table lookup, a more
+exhaustive algorithm is used if it's not found in the hash table.
+
+FDA extended functions:
+size_t fda_sizeof(const void*)
+int    valid_ptr(const void*, size_t)
+
+Typical usage for the fda extended functions:
+Note: the assert macro compiles to nothing if NDEBUG is defined.
+Verify a foo_ptr:
+assert(sizeof(struct foo) == fda_sizeof(foo_ptr));
+assert(valid_ptr(foo_ptr, sizeof(struct foo)));
+Check for room to write:
+assert(valid_ptr(buf, len));
+
+3. Leak checking and block validation
+FDA has several functions for leak checking, and reference marking.
+fda_clear_refs() iterates through all of the allocated blocks of
+memory and clears the referenced flag.
+fda_set_ref() marks a single allocation(block) as being referenced or
+in use by somebody.
+fda_assert_refs() iterates through all the allocated blocks of
+memory and calls assert() if it finds one that's not referenced.
+
+Typical usage of the block validation functions:
+fda_clear_refs();   /* clear all block references */
+
+for each allocation do
+fda_set_ref(allocation);  /* mark allocation in use */
+done
+
+fda_assert_refs();  /* this will assert if a leak is found */
+
+4. Reporting functions:
+FDA has 4 functions for reporting various aspects of allocation
+status.
+fda_get_byte_count() tells you the current total number of bytes
+your application has allocated. (this does not include debugging records)
+This will give you an idea of how much memory your application is
+using at any given time.
+
+fda_get_block_count() returns the total count of current allocations.
+
+fda_enum_locations() calls a user supplied enumeration function with
+file, line, count information, this allows you to see your file by
+file allocation density. ;) fda_enum_locations() returns the total
+number of locations that have memory allocated.
+
+fda_enum_leaks() calls a user supplied enumeration function with
+file, line, size, and ptr for every block not marked as referenced.
+One use for fda_enum_leaks() is checking for leaks when your program
+exits:
+void enum_fn(const char* file, int line, size_t size, void* ptr)
+{
+  printf("Memory leak: %s: %d - %d bytes at (%p)\n", file, line, size, ptr);
+}
+
+int main(void)
+{
+  ...
+#if defined(DEBUG)
+  /* check for memory leaks before exiting */
+  fda_clear_refs();
+  fda_enum_leaks(enum_fn);
+#endif
+  return 0;  /* return from main */
+}
+
+The test file fdatest.c gives examples of usage for most of the functions
+available with FDA.
+
+Please let me know if you encounter any problems with FDA.
+So far FDA has been built and tested on linux and Windows NT.
+If you find that it works with or without change on other platforms
+please let me know so I can make the appropriate changes to the
+code and add it to the list of tested platforms.
+
+
diff --git a/doc/features.txt b/doc/features.txt
new file mode 100644 (file)
index 0000000..9b486ea
--- /dev/null
@@ -0,0 +1,208 @@
+Undernet server features.
+-------------------------
+
+This document is supposed to list the features that undernet supports and
+provides to clients, and which version of ircu this was added.  Additional
+numeric replies should be added here too.
+
+Extended Who information: (WHOX)
+ Version: unknown, but at least 2.10.07+
+
+ This is described in the file 'readme.who'
+
+USERIP:
+ Version: unknown, but at least 2.10.07+
+
+ This works the same as userhost, but returns the IP instead, useful for
+ setting a ban on someones IP address instead of their nick.
+ usage:
+  USERIP nick[,nick...]
+ returns:
+  RPL_USERIP (307)
+  :server.name 307 target nick[*]=[+|-]user@host...
+
+RPL_ISUPPORT:
+ version: 2.10.08+
+  
+ This sends a numeric during client signon that lists various features that
+ ircu supports.  This allows client and script writers to know what features
+ they can use, and various parameters about the irc server.  The numeric
+ used is '005' to try and maintain some semblance of compatibility with
+ dalnet which has a similar feature.  The 005 numeric may be split across
+ multiple lines if the length exceeds 512 characters.
+
+ The format is:
+  :servername 005 target feature1 feature2... :are supported by this server.
+  :servername 005 target feature200... :are supported by this server.
+
+ features are either a word describing the feature eg: 'SILENCE', or a word
+ describing the feature and an equals and a list of parameters.  
+ eg: SILENCE=15 (says that we support silence, and we support up to 15 of
+ them per user), or FOO=12,3 (says we support FOO with parameters 12 and 3)
+ for example 2.10.08 lists:
+
+ :test.undernet.org 005 test SILENCE=15 WHOX WALLCHOPS USERIP CPRIVMSG 
+   CNOTICE MODES=6 MAXCHANNELS=10 MAXBANS=30 NICKLEN=9 TOPICLEN=160
+   KICKLEN=160
+ NOTE: Versions prior to 2.10.08+ use numeric 005 as part of 'MAP', so
+ 005 should be /not/ be used after the server registration has occured.
+ (ie: after END_OF_MOTD has arrived).
+
+MAP:
+ Version: unknown, but since 2.9.30 at least, updated in 2.10.08
+ /map shows the servers as the server percieves them, who's connected
+ to who in a pretty display.  In version 2.10.08 it also lists the
+ amount time time it takes a message to get /from/ a server to the local
+ server - this measures the one way lag only, in 2.10.08 it also lists
+ the number of clients that are currently on that server.
+ The lag estimation is very approximate and depends on people changing nick
+ and joining channels, so the less clients on a server the less reliable the
+ lag estimation is.
+
+ Map prior to 2.10.08 uses:
+  RPL_MAP     005
+  RPL_MAPMORE 006
+  RPL_MAPEND  007
+ Map changed in 2.10.08 to allow for ISUPPORT on numeric 005, the new
+  numerics are:
+  RPL_MAP     015
+  RPL_MAPMORE 016
+  RPL_MAPEND  017
+WALLCHOPS:
+ Version: unknown, but since 2.10.07
+ WALLCHOPS sends a message to all channel operators (@)'s on a channel.
+ It does /not/ require you to be op'd (@'d) to do so.  This is a feature.
+ syntax:
+  WALLCHOPS #channel :message
+ or:
+  NOTICE @#channel :message
+
+ this sends:
+  :user NOTICE @#channel :message
+ to clients that are @'d on the channel.
+
+CPRIVMSG/CNOTICE:
+ Version: unknown, but since 2.10.07
+
+ CPRIVMSG/CNOTICE are a way around target limiting in recent undernet
+ servers.  Undernet servers prevent you from sending messages to too many
+ people at once in an attempt to help cut down the amount of spam that
+ occurs on the network.  Because there are several situations where you want
+ to send messages to lots of people that are on the same channel as you
+ (autogreet's and gamebots for example) an 'escape' was made in the form
+ of CPRIVMSG/CNOTICE.  These allow you to send a privmsg/notice to a person
+ on a common channel if you are op'd (@'d) without incuring a target
+ penalty.  If you see 'Target changed too fast' messages, you should
+ probably be using these commands.
+
+ Syntax:
+  CPRIVMSG #channel nick :Message
+  CNOTICE #channel nick :Message
+ Results are the same as for 'PRIVMSG' and 'NOTICE' respectively.
+
+SILENCE:
+ Version: unknown, 2.9.32 at least.
+
+ Silence is a server side ignore.  You can /silence +hostmask or
+ /silence +nick, to add someone to your silence list, or use /silence
+ -hostmask to remove it.  /silence will list your 'silence list'.
+ you can /silence nick, to see someone elses silence list (useful for
+ helping someone).  Silence is preferably used as a last resort as it
+ tends to use server CPU time.  Undernet typically only allows 15 silences
+ per user.  in 2.10.08+ this information is available in the RPL_ISUPPORT
+ line.
+
+ Syntax:
+  SILENCE +hostmask
+  SILENCE +nick
+  SILENCE -hostmask
+  SILENCE -nick
+  SILENCE nick
+
+ reply:
+  RPL_SILELIST      217
+  RPL_ENDOFSILELIST 218
+User modes:
+ Version: various
+
+ Undernet supports these additional user modes:
+  +d: Deaf & Dumb.  This user will not get any channel traffic.  Used for
+      bots.
+  +k: This user cannot be kicked, deop'd or /kill'd.  This usermode may only
+      be set by a server, it may not be set by a user.  This is used by
+      undernet service bots (X/W/UWorld etc)
+  +g: List channel HACK:'s
+  +s: Server messages - takes a parameter of which masks to send, see
+      'snomask.html' for more details. (2.10.0+)
+
+LIST:
+ Version: Unknown
+
+ List now takes various parameters to allow you to quickly and efficiently
+ find interesting channels.  These are:
+
+ >n or <n   show channels with less than or greater than 'n' users
+            respectively
+ C>n or C<n show channels that have existed for less than or greater than
+            'n' minutes.
+ T>n or C<n show channels that have had their topic changed in less than or 
+            greater than 'n' minutes.
+
+ Additional Numerics:
+  RPL_LISTHELP 334
+
+Additional Topic Numerics:
+ Version: Since the dawn of time.
+
+ Topic also lists who set it and when they set it.
+
+ Additional Numerics:
+  RPL_TOPICWHOTIME 333
+ Straight after the topic:
+  :server.name 333 #channel Isomer 923423442
+ where the number is seconds past 00:00 1970-01-01 that the topic was set.
+
+
+INVITE list:
+ Version: 2.10.08+
+
+ /invite without any parameters lists which channels you have an outstanding
+ invite to (ie: an invite to a channel which you haven't joined)
+ Additional Numerics:
+  RPL_INVITELIST      346
+  RPL_ENDOFINVITELIST 347
+
+NICK change:
+ Version: Since the dawn of time.
+
+ Undernet prevents you from changing nick on a channel while your banned.
+ Undernet prevents you changing nicks more than once per 30 seconds, you
+ get one 'free' nick change if you haven't changed nick recently.
+
+ Additional Numerics:
+  RPL_BANNICKCHANGE 347
+  RPL_NICKTOOFAST   349
+
+Target limiting:
+ Version: Recent 2.10.07ish at least.
+
+ Undernet prevents you from changing 20 targets per 2 minutes.  A target
+ is a 'Nick' or 'channel'.  This is to prevent spam.  If you message more
+ than 20 people or join more than 20 channels in two minutes then you'll
+ start getting 'Target change too fast' and will have to wait before you
+ can start talking.  See CPRIVMSG/CNOTICE above for information on how to
+ avoid this.
+
+ Additional Numerics:
+  ERR_TARGETTOOFAST 349
+
+
diff --git a/doc/p10.html b/doc/p10.html
new file mode 100644 (file)
index 0000000..83eca58
--- /dev/null
@@ -0,0 +1,897 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+   <META NAME="GENERATOR" CONTENT="Mozilla/4.07 [en] (X11; I; Linux 2.2.13 i586) [Netscape]">
+   <TITLE>Undernet P10 Protocol and Interface Specification</TITLE>
+</HEAD>
+<BODY>
+
+<H2>
+<A NAME="top"></A><FONT SIZE=+3>Undernet P10 Protocol and Interface Specification</FONT></H2>
+<I>(As of ircu 2.10.10)</I>
+<H2>
+Undernet Coder-com, <TT>coder-com@undernet.org</TT></H2>
+v0.10, 2nd March 2000.
+<P>
+<HR ALIGN=CENTER WIDTH=100% SIZE=2><I>This document aims to be a practical
+guide for implementing and maintaining the protocol, not just a reference
+manual.</I>
+<P>This document is "work in progress" and being continually updated :)
+<HR 
+  ALIGN=CENTER WIDTH=100% SIZE=2>
+<BR><FONT SIZE=+2>1. <B><A HREF="#chap1">Introduction</A></B></FONT>
+<P><FONT SIZE=+2>2. <B><A HREF="#chap2">General concepts and background</A></B></FONT>
+<BLOCKQUOTE><FONT SIZE=+0>2.1 <A HREF="#chap2.1">Concepts</A>.</FONT>
+<BR><FONT SIZE=+0>2.2 <A HREF="#chap2.2">Token Table</A>.</FONT></BLOCKQUOTE>
+
+<H2>
+3. <A HREF="#chap3">Registration and syncronisation</A></H2>
+
+<UL>
+<LI>
+<FONT SIZE=+0>3.1 <A HREF="#chap3.1">Server registration and authentication</A>.</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>3.2 <A HREF="#chap3.2">Network database resyncronisation</A>.</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>3.3 <A HREF="#chap3.3">Summary</A>.</FONT></LI>
+</UL>
+
+<H2>
+4. <A HREF="#chap4">Continous operation</A></H2>
+
+<UL>
+<LI>
+4.1 Channel operations.</LI>
+
+<LI>
+4.2 Messaging.</LI>
+
+<LI>
+4.3 Setting G-Lines.</LI>
+
+<LI>
+4.4 ...</LI>
+</UL>
+
+<H2>
+4. Programmers reference: Function headers</H2>
+
+<UL>
+<LI>
+<FONT SIZE=+0>4.1 ms_nick</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>4.2 m_burst</FONT></LI>
+
+<LI>
+<FONT SIZE=+0>4.3 ..etc</FONT></LI>
+</UL>
+
+<H2>
+5. <A HREF="#chap5">Programmers reference: Client/Server Structures</A></H2>
+
+<H2>
+6. <A HREF="#chap7">FAQ</A></H2>
+
+<H2>
+7. Acknowledgements and disclaimer</H2>
+
+<H2>
+8. <A HREF="#chap8">Update History</A></H2>
+
+<BLOCKQUOTE>
+<LI>
+<A HREF="#chap8.1">TODO List</A></LI>
+</BLOCKQUOTE>
+
+<CENTER>
+<HR ALIGN=CENTER WIDTH=100% SIZE=2></CENTER>
+
+<P><A NAME="chap1"></A><B><FONT SIZE=+2>1. Introduction</FONT></B>
+<P><FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<P><A NAME="chap2"></A><B><FONT SIZE=+2>2. General concepts and background</FONT></B>
+<P><A NAME="chap2.1"></A><B><FONT SIZE=+1>2.1 Concepts</FONT></B>
+<P>The undernet P10 protocol uses a scheme of "Numerics" to uniquenly identify
+a client or server within the network. Each server has its own unique numeric
+(0 -> 4095) and each client has its own numeric within that server (0->262,143).
+<P>The numerics are encoded into a Base64 stream to maintain human readable
+data flow and reduce the size of the messages. The Base64 character set
+used in ircu is included below, this defines all valid characters allowed
+in a Base64 numeric with "A" representing 0 and "]" representing 63.
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789[]</FONT></TT></PRE>
+</BLOCKQUOTE>
+Server numerics consist of 2 characters, with the minimum, 0, being represented
+by "AA", and the maximum, 4095, being represented by "]]". Client numerics
+are 3 characters long, with the minimum, 0, being represented by "AAA",
+and the maximum, 262,143, being represented by "]]]". The unique identifier
+of a client on the network consists of a combination of both the server
+and client numeric in the format SSCCC.
+<P>As an example, consider a server "irc.undernet.org" which has a numeric
+of 2, translating to "AC" in Base64. On this server exists a client, whom
+has been allocated the numeric 63 (which translates to "AA]" in Base64).
+Therefore, the unique identifier of this client on the network is "ACAA]".
+From this, we can determine which server the message came from, aswell
+as the client who sent it.
+<P>These numerics are used to prefix every message issued on the stream
+except for the initial "PASS" or "SERVER" message, which are not prefixed.
+Therefore, every message that can be recieved from a server will consist
+of the format:
+<BLOCKQUOTE>
+<PRE><FONT COLOR="#00007F">[NUMERIC PREFIX] [TOKEN] [DATA]</FONT></PRE>
+</BLOCKQUOTE>
+For Example:
+<BLOCKQUOTE>
+<PRE><FONT COLOR="#00007F">A[A5j P ABAAA :Foo.</FONT></PRE>
+</BLOCKQUOTE>
+<A NAME="chap2.2"></A><B><FONT SIZE=+1>2.2 Token Table</FONT></B>
+<P>The following table lists all the acceptable messages, along with their
+relevant "Token", which is used in the server&lt;>server protocol. The
+aim of tokenisation is to reduce the bandwidth used during network communication
+by reducing the length of common message identifiers.
+<BR>&nbsp;
+<CENTER><TABLE BORDER COLS=2 WIDTH="40%" >
+<TR>
+<TD><B>Message</B></TD>
+
+<TD><B>Token</B></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PRIVMSG</FONT></TD>
+
+<TD><FONT SIZE=-1>P</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WHO</FONT></TD>
+
+<TD><FONT SIZE=-1>H</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WHOIS</FONT></TD>
+
+<TD><FONT SIZE=-1>W</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WHOWAS</FONT></TD>
+
+<TD><FONT SIZE=-1>X</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>USER</FONT></TD>
+
+<TD><FONT SIZE=-1>USER</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>NICK</FONT></TD>
+
+<TD><FONT SIZE=-1>N</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SERVER</FONT></TD>
+
+<TD><FONT SIZE=-1>S</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>LIST</FONT></TD>
+
+<TD><FONT SIZE=-1>LIST</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>TOPIC</FONT></TD>
+
+<TD><FONT SIZE=-1>T</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>INVITE</FONT></TD>
+
+<TD><FONT SIZE=-1>I</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>VERSION</FONT></TD>
+
+<TD><FONT SIZE=-1>V</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>QUIT</FONT></TD>
+
+<TD><FONT SIZE=-1>Q</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SQUIT</FONT></TD>
+
+<TD><FONT SIZE=-1>SQ</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>KILL</FONT></TD>
+
+<TD><FONT SIZE=-1>D</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>INFO</FONT></TD>
+
+<TD><FONT SIZE=-1>F</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>LINKS</FONT></TD>
+
+<TD><FONT SIZE=-1>LI</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>STATS</FONT></TD>
+
+<TD><FONT SIZE=-1>R</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>HELP</FONT></TD>
+
+<TD><FONT SIZE=-1>HELP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ERROR</FONT></TD>
+
+<TD><FONT SIZE=-1>Y</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>AWAY</FONT></TD>
+
+<TD><FONT SIZE=-1>A</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CONNECT</FONT></TD>
+
+<TD><FONT SIZE=-1>CO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>MAP</FONT></TD>
+
+<TD><FONT SIZE=-1>MAP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PING</FONT></TD>
+
+<TD><FONT SIZE=-1>G</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PONG</FONT></TD>
+
+<TD><FONT SIZE=-1>Z</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>OPER</FONT></TD>
+
+<TD><FONT SIZE=-1>OPER</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PASS</FONT></TD>
+
+<TD><FONT SIZE=-1>PA</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WALLOPS</FONT></TD>
+
+<TD><FONT SIZE=-1>WA</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DESYNCH</FONT></TD>
+
+<TD><FONT SIZE=-1>DS</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>TIME</FONT></TD>
+
+<TD><FONT SIZE=-1>TI</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SETTIME</FONT></TD>
+
+<TD><FONT SIZE=-1>SE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>RPING</FONT></TD>
+
+<TD><FONT SIZE=-1>RI</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>RPONG</FONT></TD>
+
+<TD><FONT SIZE=-1>RO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>NAMES</FONT></TD>
+
+<TD><FONT SIZE=-1>E</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ADMIN</FONT></TD>
+
+<TD><FONT SIZE=-1>AD</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>TRACE</FONT></TD>
+
+<TD><FONT SIZE=-1>TR</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>NOTICE</FONT></TD>
+
+<TD><FONT SIZE=-1>O</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>WALLCHOPS</FONT></TD>
+
+<TD><FONT SIZE=-1>WC</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CPRIVMSG</FONT></TD>
+
+<TD><FONT SIZE=-1>CP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CNOTICE</FONT></TD>
+
+<TD><FONT SIZE=-1>CN</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>JOIN</FONT></TD>
+
+<TD><FONT SIZE=-1>J</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PART</FONT></TD>
+
+<TD><FONT SIZE=-1>L</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>LUSERS</FONT></TD>
+
+<TD><FONT SIZE=-1>LU</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>MOTD</FONT></TD>
+
+<TD><FONT SIZE=-1>MO</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>MODE</FONT></TD>
+
+<TD><FONT SIZE=-1>M</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>KICK</FONT></TD>
+
+<TD><FONT SIZE=-1>K</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>USERHOST</FONT></TD>
+
+<TD><FONT SIZE=-1>USERHOST</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>USERIP</FONT></TD>
+
+<TD><FONT SIZE=-1>USERIP</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>ISON</FONT></TD>
+
+<TD><FONT SIZE=-1>ISON</FONT></TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=-1>SQUERY</FONT></I></TD>
+
+<TD><I><FONT SIZE=-1>SQUERY</FONT></I></TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=-1>SERVLIST</FONT></I></TD>
+
+<TD><I><FONT SIZE=-1>SERVLIST</FONT></I></TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=-1>SERVSET</FONT></I></TD>
+
+<TD><I><FONT SIZE=-1>SERVSET</FONT></I></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>REHASH</FONT></TD>
+
+<TD><FONT SIZE=-1>REHASH</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>RESTART</FONT></TD>
+
+<TD><FONT SIZE=-1>RESTART</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CLOSE</FONT></TD>
+
+<TD><FONT SIZE=-1>CLOSE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DIE</FONT></TD>
+
+<TD><FONT SIZE=-1>DIE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>HASH</FONT></TD>
+
+<TD><FONT SIZE=-1>HASH</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DNS</FONT></TD>
+
+<TD><FONT SIZE=-1>DNS</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>SILENCE</FONT></TD>
+
+<TD><FONT SIZE=-1>U</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>GLINE</FONT></TD>
+
+<TD><FONT SIZE=-1>GL</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>BURST</FONT></TD>
+
+<TD><FONT SIZE=-1>B</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>CREATE</FONT></TD>
+
+<TD><FONT SIZE=-1>C</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>DESTRUCT</FONT></TD>
+
+<TD><FONT SIZE=-1>DE</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>END_OF_BURST</FONT></TD>
+
+<TD><FONT SIZE=-1>EB</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>END_OF_BURST_ACK</FONT></TD>
+
+<TD><FONT SIZE=-1>EA</FONT></TD>
+</TR>
+
+<TR>
+<TD><FONT SIZE=-1>PROTO</FONT></TD>
+
+<TD><FONT SIZE=-1>PROTO</FONT></TD>
+</TR>
+</TABLE></CENTER>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<P><A NAME="chap3"></A><B><FONT SIZE=+2>3. Registration and syncronisation</FONT></B>
+<P><A NAME="chap3.1"></A><B><FONT SIZE=+1>3.1 Server registration and authentication</FONT></B>
+<P>After a TCP connection has been established, the server initally introduces
+itself via a "PASS" message as follows:
+<BLOCKQUOTE>
+<PRE><FONT COLOR="#00007F">PASS :[PASSWORD]</FONT></PRE>
+</BLOCKQUOTE>
+"PASSWORD" is simply compared with the password present in the destination
+servers config file, and is used to confirm credentials after the "SERVER"
+message has been recieved, as follows:
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">SERVER [SERVERNAME] [HOPCOUNT] [START TIME] [LINK TIME] [PROTOCOL] [NUMERIC/MAXCONN] :[DESCRIPTION]</FONT></TT></PRE>
+</BLOCKQUOTE>
+For Example:
+<BLOCKQUOTE>
+<PRE><B>1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;
+</B>SERVER irc.undernet.org 1 933022556 947908144 J10 AA]]] :[127.0.0.1] A Undernet Server.</PRE>
+</BLOCKQUOTE>
+<I>Notes:</I>
+<OL>
+<LI>
+The SERVER message, indicating this connection wishes to introduce a new
+server to the network.</LI>
+
+<LI>
+&nbsp;The name of the server you are introducing, a valid server name consists
+of [..defn..].</LI>
+
+<LI>
+&nbsp;The hop count of the server you are introducing, this is always 1
+when you are introducing yourself.</LI>
+
+<LI>
+&nbsp;The epoch timestamp specifying when the ircd was started.</LI>
+
+<LI>
+&nbsp;The epoch timestamp specifying the time the server initiated the
+link to the network.</LI>
+
+<LI>
+&nbsp;The Protocol identifier of this server.</LI>
+
+<OL>
+<LI>
+This token informs the network which protocol it is compliant with, eg:
+If it is a P10 compliant server, then the token will be "P10".</LI>
+
+<LI>
+&nbsp;If the server being introduced has not yet successfully synced its
+database with the network (Completed its net.burst - see 3.2), then the
+Protocol token should be prefixed with a J, instead of a P (Eg: J10) to
+indicate it is currently still <B>j</B>oining the network.</LI>
+
+<LI>
+&nbsp;The protocol token should always be JXX when the server is introducing
+<B>itself</B>.</LI>
+</OL>
+
+<LI>
+The numeric, and maximum connections identifier for this server.</LI>
+
+<OL>
+<LI>
+This token is formatted exactly the same as a client numeric is formatted.
+The first 2 characters identify the server's numeric, whilst in this situation,
+the final 3 characters define the maximum number of clients that this server
+can hold (and more importantly, the maximum number of numerics it will
+generate).</LI>
+
+<LI>
+&nbsp;The example "AA]]]" shows that this is a server with numeric 0, which
+will generate client numerics up to 262,143.</LI>
+</OL>
+
+<LI>
+This final parameter simply consists of a textual description of the server
+prefixed by a colon. This is displayed in a clients WHOIS line, aswell
+as in the LINKS reply.</LI>
+</OL>
+<A NAME="chap3.2"></A><B><FONT SIZE=+1>3.2 Network Database resyncronisation</FONT></B>
+<P>After the connection has been established and verified, the next step
+is to syncronise the database of client/server/channel information between
+the two servers.
+<BLOCKQUOTE><B>3.2.1 - SERVER Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Server details are transmitted via "SERVER" messages similar
+to the initial introduction message, with the following format:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE><TT><FONT COLOR="#00007F">[OWNING SERVER PREFIX] S [SERVERNAME]
+[HOPCOUNT] [START TIME] [LINK TIME] [PROTOCOL] [NUMERIC/MAXCONN] 0 :[DESCRIPTION]</FONT></TT></BLOCKQUOTE>
+<FONT COLOR="#000000">The syntax of this message is almost identical to
+the originally recieved server message, with the only exception being that
+the message is numeric prefixed, to indicate which server sent this message
+(and also therefore, which hub this new server is linked too). There is
+also a fixed "0" present before the Description field, this is a placeholder
+for future use and currently unused.</FONT>
+<P><B>3.2.2 - NICK Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Client information is transmitted via "NICK" messages, of the
+following format:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">[NUMERIC PREFIX] N [NICK] [HOPCOUNT] [TIMESTAMP] [USERNAME] [HOST] &lt;+modes> [BASE64 IP] [NUMERIC] :[USERINFO]</FONT></TT></PRE>
+</BLOCKQUOTE>
+<FONT COLOR="#00007F">For Example:</FONT>
+<BLOCKQUOTE><TT><FONT COLOR="#000000">1&nbsp; 2 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+4 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;
+7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;
+9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp; 11</FONT></TT>
+<BR><TT><FONT COLOR="#000000">AF N Client1 1 947957573 User userhost.net
++oiwg DAqAoB AFAAA :Generic Client.</FONT></TT></BLOCKQUOTE>
+<I>Notes:</I>
+<OL>
+<LI>
+The numeric of the server sending this message. (And hence, owning this
+client).</LI>
+
+<LI>
+The "NICK" token.</LI>
+
+<LI>
+The nickname of this client, currently max 9 chars.</LI>
+
+<LI>
+The "Hopcount" of this client, Ie: how many servers away it is on.</LI>
+
+<LI>
+The epoch timestamp indicating when the user was created.</LI>
+
+<LI>
+The "User" part of the user@host mask.</LI>
+
+<LI>
+the "Host" part of the user@host mask.</LI>
+
+<LI>
+[<B>Optional</B>]: User modes. If present, this is always +&lt;user modes
+for this client>.</LI>
+
+<LI>
+The real IP address of this client, a Base64 encoded 32bit int.</LI>
+
+<LI>
+This client's numeric, in SSCCC format.</LI>
+
+<LI>
+Free format user info line.</LI>
+
+<BR>&nbsp;</OL>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE><B>3.2.3 - BURST Messages</B></BLOCKQUOTE>
+
+<BLOCKQUOTE>Channel details and membership information is synchronised
+in one (or more) BURST messages for each channel that exists, formatted
+as follows:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE><TT><FONT COLOR="#00007F">[NUMERIC PREFIX] B [CHANNEL] [CREATION TIMESTAMP] &lt;+MODES> &lt;ARG1> &lt;ARG2> [MEMBER LIST] &lt;:%BANS></FONT></TT></PRE>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE>For Example:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE>1&nbsp; 2 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp; 7&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9
+AZ B #coder-com 949217470 +tinkl key 56 AAAAA,AAAAB,AAAAC,ABAAA,ABAAB,ABAAC,ACAAA :%*!*@*.net</PRE>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE><I>Notes:</I></BLOCKQUOTE>
+
+<OL>
+<LI>
+The numeric of the server sending this message.</LI>
+
+<LI>
+The "BURST" token.</LI>
+
+<LI>
+The name of the channel to which this data belongs. Currently #Channel
+and +Channel names can be sent in a BURST message, &amp;Channels are not
+because by definition they are local to the server.</LI>
+
+<LI>
+The epoch timestamp indicating when the channel was created.</LI>
+
+<LI>
+[<B>Optional</B>]: Channel Modes.</LI>
+
+<OL>
+<LI>
+The channel may have a number of modes set, aswell as relevant mode arguments
+in the following 2 parameters.</LI>
+</OL>
+
+<LI>
+[<B>Optional</B>]: Channel Key, this parameter is present if the channel
+modes contain a "k" mode.</LI>
+
+<LI>
+[<B>Optional</B>]: Channel Limit, this parameter is present if the channel
+modes contain a "l" mode.</LI>
+
+<LI>
+&nbsp;A <I>comma</I> seperated list of client numerics, with the following
+specific formatting rules to indicate +o, +v and +ov channel members.</LI>
+
+<OL>
+<LI>
+Numerics can have the following symbols appended on them; "<B>:ov</B>",
+"<B>:v</B>" or "<B>:o</B>". These indicate that this numeric is either
+Opped (<B>:o</B>), Voiced (<B>:v</B>) or both (<B>:ov</B>). This state
+applies to the numeric it is attached too, and all subsequent numerics
+until another state is encountered. <I>For Example:</I></LI>
+
+<LI>
+AAABA:ov, AAABB:o,AAABC,AAABD,AAABE:v,AAABZ</LI>
+
+<BR>Here, AAABA is both opped, and voiced, AAABB, AAABC and AAABD are opped
+leaving AAABE and AAABZ voiced.
+<LI>
+&nbsp;The first numeric of the member list will always contain a state
+symbol.</LI>
+</OL>
+
+<LI>
+A <I>space</I> seperated list of bans present in the channel. The start
+of the ban stream is indicated by a ":%", everything following the ":%"
+is the ban list.</LI>
+
+<BR><I>For Example:</I>
+<BR>:%*!*@*.foobar.net another!ban@*.com *!*fred@a.host.co.uk
+<BR>Would add the following bans to the channel:
+<P>*!*@*.foobar.net
+<BR>another!ban@*.com
+<BR>*!*fred@a.host.co.uk</OL>
+
+<BLOCKQUOTE>If the length of a BURST message exceeds the maximum lenght
+of a line (512 characters) then the remaining channel members/bans are
+sent in subsequent BURST lines. The subsequent burst lines are <B>only</B>
+used to add additional members to the channel, and if neccessary, channel
+bans. There will be no "Mode" parameters present. A sample additional burst
+line would be:</BLOCKQUOTE>
+
+<BLOCKQUOTE>
+<BLOCKQUOTE>
+<PRE>AZ BURST #coder-com 949217470 ACAAB:o,ACAAD :%*!*another@*.ban.com</PRE>
+</BLOCKQUOTE>
+</BLOCKQUOTE>
+
+<BLOCKQUOTE>Which adds two more opped members and a ban to the channel.</BLOCKQUOTE>
+<A NAME="chap3.3"></A><B><FONT SIZE=+1>3.3 Summary</FONT></B>
+<P>The following table summarises the sequence of events that occur when
+a server connects to another server. S1 is our server, and S2 is a HUB
+on the target network.
+<P>S1: Sends Password.
+<BR>S1: Sends initial SERVER message.
+<P><I>S2 Confirms S1 has the correct credentials, and if so, proceeds.
+If not, S1 is squit with a relevant reason.</I>
+<P>S2: Sends Password.
+<BR>S2: Sends initial SERVER message.
+<P><I>S1 Confirms S2 has the correct credentials, and if so, proceeds.
+If not, S2 is squit with a relevant reason.</I>
+<P><B><I>The follow occur asynchronously, however they have been shown
+seperately below for simplicity.</I></B>
+<P>S1: Sends all the servers it is aware of as a stream of SERVER messages.
+<BR>S1: Sends all the clients it is aware of as a stream of NICK messages.
+<BR>S1: Sends the database of channel states on the network, as a stream
+of BURST messages.
+<BR>S1: Sends a END_OF_BURST token (EB) to indicate it has finished sending.
+<P>S2: Sends all the servers it is aware of as a stream of SERVER messages.
+<BR>S2: Sends all the clients it is aware of as a stream of NICK messages.
+<BR>S2: Sends the database of channel states on the network, as a stream
+of BURST messages.
+<BR>S2: Sends a END_OF_BURST token (EB) to indicate it has finished sending.
+<P>S2: Sends an EOB_ACK token (EA) to indicate it has succesfully recieved
+the END_OF_BURST from S1
+<BR>S1: Sends an EOB_ACK token (EA) to indicate it has succesfully recieved
+the END_OF_BURST from S2
+<P><I>Example Session:</I>
+<PRE><FONT COLOR="#00007F">[WRITE]: PASS :54321
+[WRITE]: SERVER irc.undernet.org 1 947957852 947957852 J10 AB]]] :Undernet Client Server.
+[WRITE]: AB N MrFoo 1 947957852 ~me myhost.foobar.net +diksw DAqAoB ABAAA :Mr Foo (foo@bar.com).
+[WRITE]: AB B #mychannel 946101324 ABAAA:o
+[WRITE]: AB EB
+[ READ]: PASS :54321
+[ READ]: SERVER server1.undernet.org 1 947901540 947958150 J10 AFAD] :A Generic Server.
+[ READ]: AF S server2.undernet.org 2 0 947957585 P10 AZAD] 0 :[192.168.10.3] A Generic Server.
+[ READ]: AZ S server3.undernet.org 3 0 947957607 P10 AIAD] 0 :[192.168.10.5] A Generic Server.
+[ READ]: AF N Client1 1 947957573 Ident userhost.net +oiwg DAqAoB AFAAA :Generic Client.
+[ READ]: AZ N Client2 2 947957719 Ident userhost.net +iwg DAqAoB AZAAA :Generic Client.
+[ READ]: AI N Client3 3 947957742 Ident userhost.net +iwg DAqAoB AIAAA :Generic Client.
+[ READ]: AI N Client4 3 947958121 Ident userhost.net +iwg DAqAoB AIAAB :Generic Client.
+[ READ]: AF B #foobar 947957734 +tink akey AIAAB,AIAAA:v,AZAAA:o :%*!*another@*.ban.com *!*foo@bar.net
+[ READ]: AF B #coder-com 947957727 AIAAB,AZAAA:o
+[ READ]: AF B #another 946101321 AFAAA
+[ READ]: AF EB
+[WRITE]: AB EA
+[ READ]: AF EA</FONT></PRE>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR WIDTH="100%">
+<BR><A NAME="chap4"></A><B><FONT SIZE=+2>4. Continuous Operation</FONT></B>
+<P><FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<P><A NAME="chap5"></A><B><FONT SIZE=+2>5. Programmers reference: Client/Server
+Structures</FONT></B>
+<P>This section provides information on the standard Client/Server structures,
+for easy reference during development.
+<P><I>[..Link to autogenerated struct.html..]</I>
+<P><FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR ALIGN=LEFT WIDTH=100% SIZE=2>
+<BR><A NAME="chap7"></A><B><FONT SIZE=+2>7. FAQ</FONT></B>
+<P>Frequently asked questions.
+<UL>
+<LI>
+Q. How..</LI>
+
+<LI>
+A. ...</LI>
+</UL>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+<BR>
+<HR WIDTH="100%">
+<P><A NAME="chap8"></A><B><FONT SIZE=+2>8. Update History</FONT></B>
+<P>[20/01/2000]: Initial draft, structure, background info.
+<BR>[13/02/2000]: Added initial BURST documentation.
+<BR>[14/02/2000]: Continued BURST documentation / Begin NICK and SERVER
+documentation.
+<BR>[26/02/2000]: Continued chapter 5, few example fixes, added token table
+from msg.h. --Gte.
+<BR>[02/03/2000]: Added NICK spec. --Gte.
+<P><A NAME="chap8.1"></A><B><FONT SIZE=+1>8.1 TODO</FONT></B>
+<UL>
+<LI>
+Finish Chapter 5.</LI>
+
+<LI>
+Go through examples, and ensure they are all correct.</LI>
+
+<LI>
+Add common function headers, with argv listings.</LI>
+
+<LI>
+Add description of further server&lt;>server messages, with special cases
+and outcomes.</LI>
+
+<LI>
+Add FAQ Section.</LI>
+</UL>
+<FONT FACE="Arial,Helvetica"><FONT SIZE=-1><B>[</B><A HREF="#top">Back</A><B>]</B></FONT></FONT>
+</BODY>
+</HTML>
index 419abbe7178c3a540970f9d51ef18b2965260e4a..d0acefa5f2a2eab486b601bfa43119f6c39bf13f 100644 (file)
@@ -1,62 +1,56 @@
 WHO documentation, updated on 02 Jan 1999.
 
-Since ircu2.10.02 the WHO command had been changed from what
-described in RFC1459, while still keeping backward compatibility,
-actually it has been changed again in u2.10.05 so that since this
-release the format of the who query is now:
+Since ircu2.10.02 the WHO command had been changed from what described in
+RFC1459, while still keeping backward compatibility, actually it has been
+changed again in u2.10.05 so that since this release the format of the who
+query is now:
 
 [:source] WHO <mask1> [<options> [<mask2>]]
 
-<mask2> is optional, if mask2 is present it's used for matching and
-mask1 is ignored, otherwise mask1 is used for matching, since mask2
-is the last parameter it *can* contain a space and this can help
-when trying to match a "realname".
+<mask2> is optional, if mask2 is present it's used for matching and mask1 is
+ignored, otherwise mask1 is used for matching, since mask2 is the last
+parameter it *can* contain a space and this can help when trying to match a
+"realname".
 
 When matching IP numbers the <mask> can be in 3 forms:
 
 - The old and well known IRC masks using * and ? as wanted
 - The IPmask form a.b.c.d/e.f.g.h as used in most firewalls and
-  system configurations, where what is before the / are the bits
-  we expect in the IP number and what is after the / is the 
-  "filter mask" telling wich bits whould be considered and wich 
-  should be ignored.
-- The IPmask form a.b.c.d/bitcount where bitcount is an integer 
-  between 0 and 31 (inclusive), the matching will be for the IPs
-  whose first "bitcount" bits are equal to those in a.b.c.d
+  system configurations, where what is before the / are the bits we expect
+  in the IP number and what is after the / is the "filter mask" telling wich
+  bits whould be considered and wich should be ignored.
+- The IPmask form a.b.c.d/bitcount where bitcount is an integer between 0
+  and 31 (inclusive), the matching will be for the IPs whose first
+  "bitcount" bits are equal to those in a.b.c.d
 
 Note that:
 . The bitcount must be between 0 and 31, 32 is NOT good (and
-  makes no sense to use it... just match against the static IP
-  a.b.c.d)
-. The missing pieces of both the bitmask and the ipnumber in
-  the forms ipnumber/bitmask and ipnumber/bitcount default to
-  zero from right to left, this is NOT what inet_aton and most 
-  tools do but makes more sense here IMO, in example /who 194.243/16
-  is taken as /who 194.243.0.0/255.255.0.0 (inet_aton whould
-  take 194.243 as 194.0.0.243).
-. For the above reason and specified validity limits 1.2.3.4/31
-  becomes 1.2.3.4/255.255.255.254 while 1.2.3.4/32 becomes
-  1.2.3.4/32.0.0.0 :)
-
-For all the other fields th match happens as has always been,
-i.e. it's only considered the IRC mask with * and ? (that is:
-don't expect to catch an user with "realname" = "1.2.3.4" when
-doing "/who 1.2/16 h" :)
-
-For both the masks and the options (and thus for all flags) case is
-NOT significative (so "/who <any> o" is exactly the same as 
-"/who <ANY> O".
-
-The "options2 part can be as follows:
+  makes no sense to use it... just match against the static IP a.b.c.d)
+. The missing pieces of both the bitmask and the ipnumber in the forms
+  ipnumber/bitmask and ipnumber/bitcount default to zero from right to left,
+  this is NOT what inet_aton and most tools do but makes more sense here
+  IMO, in example /who 194.243/16 is taken as /who 194.243.0.0/255.255.0.0
+  (inet_aton whould take 194.243 as 194.0.0.243).
+. For the above reason and specified validity limits 1.2.3.4/31 becomes
+  1.2.3.4/255.255.255.254 while 1.2.3.4/32 becomes 1.2.3.4/32.0.0.0 :)
+
+For all the other fields th match happens as has always been, i.e. it's only
+considered the IRC mask with * and ? (that is: don't expect to catch an user
+with "realname" = "1.2.3.4" when doing "/who 1.2/16 h" :)
+
+For both the masks and the options (and thus for all flags) case is NOT
+significative (so "/who <any> o" is exactly the same as "/who <ANY> O".
+
+The "options2" part can be as follows:
 
  [<flags>][%[<fields>[,<querytype>]]]
 
-in wich:
+in which:
 
- <flags>: can be a sequence of field matching flags, use mode matching
-          flags and special purpose flags
+ <flags>: can be a sequence of field matching flags, use mode matching flags
+          and special purpose flags
 
-   Field matching flags, when one of these is specified the field in 
+   Field matching flags, when one of these is specified the field in
    question is matched against the mask, otherwise it's not matched.
 
    n   Nick (in nick!user@host)
@@ -66,12 +60,11 @@ in wich:
    s   Servername (the canonic name of the server the guy is on)
    r   Info text (formerly "Realname")
 
-   If no field-matching flags are specified they default to what
-   old servers used to do: nuhsr (= everything except the numeric IP)
+   If no field-matching flags are specified they default to what old servers
+   used to do: nuhsr (= everything except the numeric IP)
 
-   User mode matching flags (specifying one of these means that only 
-   clients with that umode are considered, what is not specified
-   is always matched):
+   User mode matching flags (specifying one of these means that only clients
+   with that umode are considered, what is not specified is always matched):
 
    o   Irc operator
        [In the future more flags will be supported, basically all
@@ -79,20 +72,19 @@ in wich:
 
    Special purpose flags:
 
-   x   If this is specified the extended visibility of information 
-       for opers is applied, what this means depends on the fact that
-       you are local or global operator and on how the admin configured
-       the server (global and eventually local irc opers might be
-       allowed with this flag to see +i local users, to see all +i users,
-       to see users into +p and/or +s channels, and so on). Using the 'x'
-       flag while not beeing irc operator is meaningless (it will be
-       ignored), using it while oper'd means that the query is almost
-       certainly logged and the admin might (rightfully) ask you an
-       explanation on why you did.
-
-   The rest, what follows the %, that is [%[fields[,<querytype>]]],
-   is as it has always been since the first who.patch, the <fields> part
-   specifies wich fields to include in the output as:
+   x   If this is specified the extended visibility of information for opers
+       is applied, what this means depends on the fact that you are local or
+       global operator and on how the admin configured the server (global
+       and eventually local irc opers might be allowed with this flag to see
+       +i local users, to see all +i users, to see users into +p and/or +s
+       channels, and so on). Using the 'x' flag while not being an irc
+       operator is meaningless (it will be ignored), using it while oper'd
+       means that the query is almost certainly logged and the admin might
+       (rightfully) ask you an explanation on why you did.
+
+   The rest, what follows the %, that is [%[fields[,<querytype>]]], is as it
+   has always been since the first who.patch, the <fields> part specifies
+   wich fields to include in the output as:
 
    c : Include (first) channel name
    d : Include "distance" in hops (hopcount)
@@ -105,16 +97,16 @@ in wich:
    t : Include the querytype in the reply
    u : Include userID with eventual ~
 
-And the ,<querytype> final option can be used to specify what you want
-the server to say in the querytype field of the output, useful to
-filter the output in scripts that do a kind of "on 354 ..."
+And the ,<querytype> final option can be used to specify what you want the
+server to say in the querytype field of the output, useful to filter the
+output in scripts that do a kind of "on 354 ..."
 
-If no %fields are specified the reply is _exactly_ the same as
-has always been, numeric 352, same fields, same order.
+If no %fields are specified the reply is _exactly_ the same as has always
+been, numeric 352, same fields, same order.
 
-If one or more %fields are specified the reply uses a new numeric,
-since an out-of-standard 352 crashes EPIC and confuses several other
-clients. I used 354.
+If one or more %fields are specified the reply uses a new numeric, since an
+out-of-standard 352 crashes EPIC and confuses several other clients. I used
+354.
 
 :"source" 354 "target" ["querytype"] ["channel"] ["user"] 
                        ["IP"] ["host"] ["server"] ["nick"] 
@@ -122,35 +114,34 @@ clients. I used 354.
 
 Where only the fields specified in the %fields options are present.
 
-"querytype" is the same value passed in the /who command, it
-is provided to simplify scripting, in example one could pass
-a certain value in the query and have that value "signal" back
-what is to be done with those replies.
-
-The number of lines in the reply is still limited to avoid self-flooding
-and sooner or later another limitation will be added: you will be forced
-to do no more than one /who query every 'n' seconds where 'n' depends
-on the number of fields you actually match (the field-match flags specified
-before % in the option, defaulting to 6 if you don't specify an option
-at all), infact matching against many fields as the default query does
-severely affects the CPU usage of the server and is *much* better to
-specify with the field-atching flags what you are looking for, in example
-when you are looking for all french users a "/who *.fr h" is A LOT
-better than just "/who *.fr" (and actually you want users that have the
+"querytype" is the same value passed in the /who command, it is provided to
+simplify scripting, in example one could pass a certain value in the query
+and have that value "signal" back what is to be done with those replies.
+
+The number of lines in the reply is still limited to avoid self-flooding and
+sooner or later another limitation will be added: you will be forced to do
+no more than one /who query every 'n' seconds where 'n' depends on the
+number of fields you actually match (the field-match flags specified before
+% in the option, defaulting to 6 if you don't specify an option at all),
+infact matching against many fields as the default query does severely
+affects the CPU usage of the server and is *much* better to specify with the
+field-matching flags what you are looking for, in example when you are
+looking for all french users a "/who *.fr h" is A LOT better than just "/who
+*.fr" (and actually you want users that have the
 _hostname_ matching *.fr, you wouldn't want to match a japanese user
 that has the realname "ku fung-kay aj.fr" in example...)
 
 Note that:
 
 - An user doing a "/who whatever" or a "/who whatever o"
-  will not see any change (except for the anti-flood limit
-  and sooner or later the CPU usage limit)
+  will not see any change (except for the anti-flood limit and sooner or
+  later the CPU usage limit)
 
-- An user doing a "/who #wasteland %n" will get just a list
-  of nicks (lame, very lame way of doing it :-)
+- An user doing a "/who #wasteland %n" will get just a list of nicks (lame,
+  very lame way of doing it :-)
 
-- An user doing a "/who 0 o%nuhs" will get a list of the opers
-  with Nick, userID, server and hostname like:
+- An user doing a "/who 0 o%nuhs" will get a list of the opers with Nick,
+  userID, server and hostname like:
   
 :Amst* 354 Nemesi #wasteland nbakker pc73.a.sn.no Oslo*.org Niels
 
@@ -165,12 +156,12 @@ Note that:
   "on 354 * 166" display "There is an oper ..."
 
 - The client will have to sort/format the fields by itself,
-  the _order_ in wich flags are passed is not significant,
-  the fields in the reply will always have the same order.
+  the _order_ in which flags are passed is not significant, the fields in the
+  reply will always have the same order.
 
 - The maximum number of _lines_ reported as reply for a query
-  is 2048/(n+4) where 'n' is the number of flags "enabled"
-  that is the number of fields included in each reply.
+  is 2048/(n+4) where 'n' is the number of flags "enabled" that is the
+  number of fields included in each reply.
 
   Actually:   1 field  returned = maximum 409 replies
               2 fields returned = maximum 341 replies
@@ -183,63 +174,61 @@ Note that:
               9 fields returned = maximum 157 replies
              10 fields returned = maximum 146 replies
 
-  If the limit is reached before completing the query the
-  reply is truncated and a new numeric error is issued after
-  the "End of WHO", anyway the "end of" numeric is _always_ 
-  sent (otherwise some scripts and clients get crazy).
+  If the limit is reached before completing the query the reply is truncated
+  and a new numeric error is issued after the "End of WHO", anyway the "end
+  of" numeric is _always_ sent (otherwise some scripts and clients go
+  crazy).
 
 The actual "mask" to match can have one of the two following forms:
 
 - A comma-separated list of elements: in this case each element
-  is treated as a flat channel or nick name and is not matched
-  to the other elements. Nicks do count in the limit of output
-  lines (they should not be that many anyway), channels count
-  if who asks the query is not on the channel. (That is: a /who
-  #channel gives unlimited output if you are in there).
-
-- A _single_ mask: in this case (no commas, only one element) the
-  mask is first checked to be a full channel or nickname, then
-  it is matched against all relevant fiels as already known.
-  These happens in different steps with replicates-removal so
-  that if one has (?) something like "#wasteland" as "real name"
-  or is on a channel named "#***MyChan***" it all works nicely.
+  is treated as a flat channel or nick name and is not matched to the other
+  elements. Nicks do count in the limit of output lines (they should not be
+  that many anyway), channels count if who asks the query is not on the
+  channel. (That is: a /who #channel gives unlimited output if you are in
+  there).
+
+- A _single_ mask: in this case (no commas, only one element) the mask is
+  first checked to be a full channel or nickname, then it is matched against
+  all relevant fiels as already known.  These happens in different steps
+  with replicates-removal so that if one has (?) something like "#wasteland"
+  as "real name" or is on a channel named "#***MyChan***" it all works
+  nicely.
 
 Miscellaneous bug fixes / "undocumented feature" changes:
 
-- /who NickName did not show the user with nick = NickName  when it
-  was invisible, even if the nick was given completely (without 
-  wildchars) now it does, since one could always see him as /whois 
-  NickName.
-  It does not report him twice if he also has in example the 
-  userID == NickName and is -i.
-
-- ":source WHO :The Black Hacker" did not report an user having
-  "The Black Hacker" as real name, now it does. Since this can only
-  be done without the flags/format specificator because that would
-  become the "last parameter" an escape has been provided: if you
-  pass to m_who _3_ parameters the first one will be ignored and the
-  last one used for matching, like in example
-  ":source WHO foo %nuh :*Black Hacker*" where "foo" will not
-  be used and the match will happen on "*Black Hacker*".
-  (It was passed through clean_channelname() that prevented the mask
-  from containing spaces and such...)
+- /who NickName did not show the user with nick = NickName  when it was
+  invisible, even if the nick was given completely (without wildchars) now
+  it does, since one could always see him as /whois NickName.  It does not
+  report him twice if he also has in example the userID == NickName and is
+  -i.
+
+- ":source WHO :The Black Hacker" did not report an user having "The Black
+  Hacker" as real name, now it does. Since this can only be done without the
+  flags/format specificator because that would become the "last parameter"
+  an escape has been provided: if you pass to m_who _3_ parameters the first
+  one will be ignored and the last one used for matching, like in example
+  ":source WHO foo %nuh :*Black Hacker*" where "foo" will not be used and
+  the match will happen on "*Black Hacker*".  (It was passed through
+  clean_channelname() that prevented the mask from containing spaces and
+  such...)
 
 - When one user was umode -i he was shown or not depending on the 
-  fact he was on a +p or +s channel... since we are doing a lookup
-  on the _user_ this makes no sense to me, example:
+  fact he was on a +p or +s channel... since we are doing a lookup on the
+  _user_ this makes no sense to me, example: 
   Neme1 : umode -i, on no channels, was SEEN with a /who 0
   Neme2 : umode -i, on channel #p with chmode +p, was NOT SEEN by /who 0
   Neme3 : umode -i, on channel #s with chmode +s, was NOT SEEN by /who 0
 
-  Now all users "-i" are matched with a "/who mask", the +i users 
-  instead must bee on a _common_ channel to be seen. 
+  Now all users "-i" are matched with a "/who mask", the +i users instead
+  must be on a _common_ channel to be seen.
 
-  Basically beeing on "one" +s|p channel "forced" a +i status while
-  one might want to be on #secret (mode +s) and have nobody know that
-  he is in there but on the other side stay -i so others can find him.
-  Of course a +s|p channel is never shown in the reply unless who asks 
-  the query is in there, if no "visible" channels are available for 
-  a -i user he is shown on "channel *".
+  Basically being on "one" +s|p channel "forced" a +i status while one might
+  want to be on #secret (mode +s) and have nobody know that he is in there
+  but on the other side stay -i so others can find him.  Of course a +s|p
+  channel is never shown in the reply unless who asks the query is in there,
+  if no "visible" channels are available for a -i user he is shown on
+  "channel *".
 
 - When one user is +i is shown _only_ if there is a common channel,
   the first common channel found is shown in the reply.
@@ -268,22 +257,21 @@ Miscellaneous bug fixes / "undocumented feature" changes:
   now it does (and does NOT report him twice if he is ALSO on a
   channel named #John, strange but true: this can happen).
 
-- "/who a,b,c,d" where a b c and d are channelnames/nicks now uses 
-  an hash lookup and therefore is extremely efficient, if _only_ one
-  field is specified it is looked in all the fields; who really wants
-  _only_ users on a specific channel or a single nick (without looking 
-  for a match in the other fields) can force the server to consider
-  the parameter as a list adding a comma somewhere, like:
+- "/who a,b,c,d" where a b c and d are channelnames/nicks now uses an hash
+  lookup and therefore is extremely efficient, if _only_ one field is
+  specified it is looked in all the fields; who really wants _only_ users on
+  a specific channel or a single nick (without looking for a match in the
+  other fields) can force the server to consider the parameter as a list
+  adding a comma somewhere, like:
 
   "/who #Italia," or "/who ,Nemesi"
 
   Or even better to avoid misbehaviour with other servers:
   "/who #Italia %... #Italia,"   or "/who Nemesi %... Nemesi,"
 
-  This will make old servers act properly and new ones and should 
-  be the reccomended way for GUI based clients to get
-  a channel's userlist and all the infos they want about users
-  on the channel.
+  This will make old servers act properly and new ones and should be the
+  recomended way for GUI based clients to get a channel's userlist and all
+  the infos they want about users on the channel.
 
 Regards, Andrea aka Nemesi
 
diff --git a/doc/rfc1413.txt b/doc/rfc1413.txt
new file mode 100644 (file)
index 0000000..0522c7b
--- /dev/null
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group                                       M. St. Johns
+Request for Comments: 1413                      US Department of Defense
+Obsoletes: 931                                             February 1993
+
+
+                        Identification Protocol
+
+Status of this Memo
+
+   This RFC specifies an IAB standards track protocol for the Internet
+   community, and requests discussion and suggestions for improvements.
+   Please refer to the current edition of the "IAB Official Protocol
+   Standards" for the standardization state and status of this protocol.
+   Distribution of this memo is unlimited.
+
+1.  INTRODUCTION
+
+   The Identification Protocol (a.k.a., "ident", a.k.a., "the Ident
+   Protocol") provides a means to determine the identity of a user of a
+   particular TCP connection.  Given a TCP port number pair, it returns
+   a character string which identifies the owner of that connection on
+   the server's system.
+
+   The Identification Protocol was formerly called the Authentication
+   Server Protocol.  It has been renamed to better reflect its function.
+   This document is a product of the TCP Client Identity Protocol
+   Working Group of the Internet Engineering Task Force (IETF).
+
+2.  OVERVIEW
+
+   This is a connection based application on TCP.  A server listens for
+   TCP connections on TCP port 113 (decimal).  Once a connection is
+   established, the server reads a line of data which specifies the
+   connection of interest.  If it exists, the system dependent user
+   identifier of the connection of interest is sent as the reply.  The
+   server may then either shut the connection down or it may continue to
+   read/respond to multiple queries.
+
+   The server should close the connection down after a configurable
+   amount of time with no queries - a 60-180 second idle timeout is
+   recommended.  The client may close the connection down at any time;
+   however to allow for network delays the client should wait at least
+   30 seconds (or longer) after a query before abandoning the query and
+   closing the connection.
+
+
+
+
+
+
+
+St. Johns                                                       [Page 1]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+3.  RESTRICTIONS
+
+   Queries are permitted only for fully specified connections.  The
+   query contains the local/foreign port pair -- the local/foreign
+   address pair used to fully specify the connection is taken from the
+   local and foreign address of query connection.  This means a user on
+   address A may only query the server on address B about connections
+   between A and B.
+
+4.  QUERY/RESPONSE FORMAT
+
+   The server accepts simple text query requests of the form:
+
+            <port-on-server> , <port-on-client>
+
+   where <port-on-server> is the TCP port (decimal) on the target (where
+   the "ident" server is running) system, and <port-on-client> is the
+   TCP port (decimal) on the source (client) system.
+
+   N.B - If a client on host A wants to ask a server on host B about a
+   connection specified locally (on the client's machine) as 23, 6191
+   (an inbound TELNET connection), the client must actually ask about
+   6191, 23 - which is how the connection would be specified on host B.
+
+      For example:
+
+                 6191, 23
+
+   The response is of the form
+
+   <port-on-server> , <port-on-client> : <resp-type> : <add-info>
+
+   where <port-on-server>,<port-on-client> are the same pair as the
+   query, <resp-type> is a keyword identifying the type of response, and
+   <add-info> is context dependent.
+
+   The information returned is that associated with the fully specified
+   TCP connection identified by <server-address>, <client-address>,
+   <port-on-server>, <port-on-client>, where <server-address> and
+   <client-address> are the local and foreign IP addresses of the
+   querying connection -- i.e., the TCP connection to the Identification
+   Protocol Server.  (<port-on-server> and <port-on-client> are taken
+   from the query.)
+
+      For example:
+
+         6193, 23 : USERID : UNIX : stjohns
+         6195, 23 : ERROR : NO-USER
+
+
+
+St. Johns                                                       [Page 2]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+5.  RESPONSE TYPES
+
+A response can be one of two types:
+
+USERID
+
+     In this case, <add-info> is a string consisting of an
+     operating system name (with an optional character set
+     identifier), followed by ":", followed by an
+     identification string.
+
+     The character set (if present) is separated from the
+     operating system name by ",".  The character set
+     identifier is used to indicate the character set of the
+     identification string.  The character set identifier,
+     if omitted, defaults to "US-ASCII" (see below).
+
+     Permitted operating system names and character set
+     names are specified in RFC 1340, "Assigned Numbers" or
+     its successors.
+
+     In addition to those operating system and character set
+     names specified in "Assigned Numbers" there is one
+     special case operating system identifier - "OTHER".
+
+     Unless "OTHER" is specified as the operating system
+     type, the server is expected to return the "normal"
+     user identification of the owner of this connection.
+     "Normal" in this context may be taken to mean a string
+     of characters which uniquely identifies the connection
+     owner such as a user identifier assigned by the system
+     administrator and used by such user as a mail
+     identifier, or as the "user" part of a user/password
+     pair used to gain access to system resources.  When an
+     operating system is specified (e.g., anything but
+     "OTHER"), the user identifier is expected to be in a
+     more or less immediately useful form - e.g., something
+     that could be used as an argument to "finger" or as a
+     mail address.
+
+     "OTHER" indicates the identifier is an unformatted
+     character string consisting of printable characters in
+     the specified character set.  "OTHER" should be
+     specified if the user identifier does not meet the
+     constraints of the previous paragraph.  Sending an
+     encrypted audit token, or returning other non-userid
+     information about a user (such as the real name and
+     phone number of a user from a UNIX passwd file) are
+
+
+
+St. Johns                                                       [Page 3]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+     both examples of when "OTHER" should be used.
+
+     Returned user identifiers are expected to be printable
+     in the character set indicated.
+
+     The identifier is an unformatted octet string - - all
+     octets are permissible EXCEPT octal 000 (NUL), 012 (LF)
+     and 015 (CR).  N.B. - space characters (040) following the
+     colon separator ARE part of the identifier string and
+     may not be ignored. A response string is still
+     terminated normally by a CR/LF.  N.B. A string may be
+     printable, but is not *necessarily* printable.
+
+ERROR
+
+   For some reason the port owner could not be determined, <add-info>
+   tells why.  The following are the permitted values of <add-info> and
+   their meanings:
+
+          INVALID-PORT
+
+          Either the local or foreign port was improperly
+          specified.  This should be returned if either or
+          both of the port ids were out of range (TCP port
+          numbers are from 1-65535), negative integers, reals or
+          in any fashion not recognized as a non-negative
+          integer.
+
+          NO-USER
+
+          The connection specified by the port pair is not
+          currently in use or currently not owned by an
+          identifiable entity.
+
+          HIDDEN-USER
+
+          The server was able to identify the user of this
+          port, but the information was not returned at the
+          request of the user.
+
+          UNKNOWN-ERROR
+
+          Can't determine connection owner; reason unknown.
+          Any error not covered above should return this
+          error code value.  Optionally, this code MAY be
+          returned in lieu of any other specific error code
+          if, for example, the server desires to hide
+          information implied by the return of that error
+
+
+
+St. Johns                                                       [Page 4]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+          code, or for any other reason.  If a server
+          implements such a feature, it MUST be configurable
+          and it MUST default to returning the proper error
+          message.
+
+   Other values may eventually be specified and defined in future
+   revisions to this document.  If an implementer has a need to specify
+   a non-standard error code, that code must begin with "X".
+
+   In addition, the server is allowed to drop the query connection
+   without responding.  Any premature close (i.e., one where the client
+   does not receive the EOL, whether graceful or an abort should be
+   considered to have the same meaning as "ERROR : UNKNOWN-ERROR".
+
+FORMAL SYNTAX
+
+   <request> ::= <port-pair> <EOL>
+
+   <port-pair> ::= <integer> "," <integer>
+
+   <reply> ::= <reply-text> <EOL>
+
+   <EOL> ::= "015 012"  ; CR-LF End of Line Indicator
+
+   <reply-text> ::= <error-reply> | <ident-reply>
+
+   <error-reply> ::= <port-pair> ":" "ERROR" ":" <error-type>
+
+   <ident-reply> ::= <port-pair> ":" "USERID" ":" <opsys-field>
+                     ":" <user-id>
+
+   <error-type> ::= "INVALID-PORT" | "NO-USER" | "UNKNOWN-ERROR"
+                    | "HIDDEN-USER" |  <error-token>
+
+   <opsys-field> ::= <opsys> [ "," <charset>]
+
+   <opsys> ::= "OTHER" | "UNIX" | <token> ...etc.
+               ;  (See "Assigned Numbers")
+
+   <charset> ::= "US-ASCII" | ...etc.
+                 ;  (See "Assigned Numbers")
+
+   <user-id> ::= <octet-string>
+
+   <token> ::= 1*64<token-characters> ; 1-64 characters
+
+   <error-token> ::= "X"1*63<token-characters>
+                     ; 2-64 chars beginning w/X
+
+
+
+St. Johns                                                       [Page 5]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+   <integer> ::= 1*5<digit> ; 1-5 digits.
+
+   <digit> ::= "0" | "1" ... "8" | "9" ; 0-9
+
+   <token-characters> ::=
+                  <Any of these ASCII characters: a-z, A-Z,
+                   - (dash), .!@#$%^&*()_=+.,<>/?"'~`{}[]; >
+                               ; upper and lowercase a-z plus
+                               ; printables minus the colon ":"
+                               ; character.
+
+   <octet-string> ::= 1*512<octet-characters>
+
+   <octet-characters> ::=
+                  <any octet from  00 to 377 (octal) except for
+                   ASCII NUL (000), CR (015) and LF (012)>
+
+Notes on Syntax:
+
+   1)   To promote interoperability among variant
+        implementations, with respect to white space the above
+        syntax is understood to embody the "be conservative in
+        what you send and be liberal in what you accept"
+        philosophy.  Clients and servers should not generate
+        unnecessary white space (space and tab characters) but
+        should accept white space anywhere except within a
+        token.  In parsing responses, white space may occur
+        anywhere, except within a token.  Specifically, any
+        amount of white space is permitted at the beginning or
+        end of a line both for queries and responses.  This
+        does not apply for responses that contain a user ID
+        because everything after the colon after the operating
+        system type until the terminating CR/LF is taken as
+        part of the user ID.  The terminating CR/LF is NOT
+        considered part of the user ID.
+
+   2)   The above notwithstanding, servers should restrict the
+        amount of inter-token white space they send to the
+        smallest amount reasonable or useful.  Clients should
+        feel free to abort a connection if they receive 1000
+        characters without receiving an <EOL>.
+
+   3)   The 512 character limit on user IDs and the 64
+        character limit on tokens should be understood to mean
+        as follows: a) No new token (i.e., OPSYS or ERROR-TYPE)
+        token will be defined that has a length greater than 64
+        and b) a server SHOULD NOT send more than 512 octets of
+        user ID and a client MUST accept at least 512 octets of
+
+
+
+St. Johns                                                       [Page 6]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+        user ID.  Because of this limitation, a server MUST
+        return the most significant portion of the user ID in
+        the first 512 octets.
+
+   4)   The character sets and character set identifiers should
+        map directly to those defined in or referenced by RFC 1340,
+        "Assigned Numbers" or its successors.  Character set
+        identifiers only apply to the user identification field
+        - all other fields will be defined in and must be sent
+        as US-ASCII.
+
+   5)   Although <user-id> is defined as an <octet-string>
+        above, it must follow the format and character set
+        constraints implied by the <opsys-field>; see the
+        discussion above.
+
+   6)   The character set provides context for the client to
+        print or store the returned user identification string.
+        If the client does not recognize or implement the
+        returned character set, it should handle the returned
+        identification string as OCTET, but should in addition
+        store or report the character set.  An OCTET string
+        should be printed, stored or handled in hex notation
+        (0-9a-f) in addition to any other representation the
+        client implements - this provides a standard
+        representation among differing implementations.
+
+6.  Security Considerations
+
+   The information returned by this protocol is at most as trustworthy
+   as the host providing it OR the organization operating the host.  For
+   example, a PC in an open lab has few if any controls on it to prevent
+   a user from having this protocol return any identifier the user
+   wants.  Likewise, if the host has been compromised the information
+   returned may be completely erroneous and misleading.
+
+   The Identification Protocol is not intended as an authorization or
+   access control protocol.  At best, it provides some additional
+   auditing information with respect to TCP connections.  At worst, it
+   can provide misleading, incorrect, or maliciously incorrect
+   information.
+
+   The use of the information returned by this protocol for other than
+   auditing is strongly discouraged.  Specifically, using Identification
+   Protocol information to make access control decisions - either as the
+   primary method (i.e., no other checks) or as an adjunct to other
+   methods may result in a weakening of normal host security.
+
+
+
+
+St. Johns                                                       [Page 7]
+\f
+RFC 1413                Identification Protocol            February 1993
+
+
+   An Identification server may reveal information about users,
+   entities, objects or processes which might normally be considered
+   private.  An Identification server provides service which is a rough
+   analog of the CallerID services provided by some phone companies and
+   many of the same privacy considerations and arguments that apply to
+   the CallerID service apply to Identification.  If you wouldn't run a
+   "finger" server due to privacy considerations you may not want to run
+   this protocol.
+
+7.  ACKNOWLEDGEMENTS
+
+   Acknowledgement is given to Dan Bernstein who is primarily
+   responsible for renewing interest in this protocol and for pointing
+   out some annoying errors in RFC 931.
+
+References
+
+   [1] St. Johns, M., "Authentication Server", RFC 931, TPSC, January
+       1985.
+
+   [2] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1340,
+       USC/Information Sciences Institute, July 1992.
+
+Author's Address
+
+       Michael C. St. Johns
+       DARPA/CSTO
+       3701 N. Fairfax Dr
+       Arlington, VA 22203
+
+       Phone: (703) 696-2271
+       EMail: stjohns@DARPA.MIL
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+St. Johns                                                       [Page 8]
+\f
diff --git a/doc/rfc1459.unet b/doc/rfc1459.unet
new file mode 100644 (file)
index 0000000..98fe3dd
--- /dev/null
@@ -0,0 +1,3642 @@
+Network Working Group                                      J. Oikarinen
+Request for Comments: 1459                                      D. Reed
+                                                               May 1993
+
+
+                      Internet Relay Chat Protocol
+
+Undernet Specific Annotations and Changes
+   This document exists here in order to attempt to describe the existing
+   protocol that is currently in use on the Undernet IRC Network. Since
+   the original standard was released, many networks have made
+   significant changes and enhancements to the protocol described in the
+   original version of this document. This version of the standard should
+   be updated by the current maintainers of the Undernet server software
+   distribution as changes are made that affect the protocol. Please be
+   aware that some sections may be out of date.
+
+Status of This Memo
+
+   This memo defines an Experimental Protocol for the Internet
+   community.  Discussion and suggestions for improvement are requested.
+   Please refer to the current edition of the "IAB Official Protocol
+   Standards" for the standardization state and status of this protocol.
+   Distribution of this memo is unlimited.
+
+Abstract
+
+   The IRC protocol was developed over the last 4 years since it was
+   first implemented as a means for users on a BBS to chat amongst
+   themselves.  Now it supports a world-wide network of servers and
+   clients, and is stringing to cope with growth. Over the past 2 years,
+   the average number of users connected to the main IRC network has
+   grown by a factor of 10.
+
+   The IRC protocol is a text-based protocol, with the simplest client
+   being any socket program capable of connecting to the server.
+
+Table of Contents
+
+   1.  INTRODUCTION ...............................................    4
+      1.1  Servers ................................................    4
+      1.2  Clients ................................................    5
+         1.2.1 Operators ..........................................    5
+      1.3 Channels ................................................    5
+      1.3.1  Channel Operators ....................................    6
+   2. THE IRC SPECIFICATION .......................................    7
+      2.1 Overview ................................................    7
+      2.2 Character codes .........................................    7
+      2.3 Messages ................................................    7
+         2.3.1  Message format in 'pseudo' BNF ....................    8
+      2.4 Numeric replies .........................................   10
+   3. IRC Concepts ................................................   10
+      3.1 One-to-one communication ................................   10
+      3.2 One-to-many .............................................   11
+         3.2.1 To a list ..........................................   11
+         3.2.2 To a group (channel) ...............................   11
+         3.2.3 To a host/server mask ..............................   12
+      3.3 One to all ..............................................   12
+
+
+
+Oikarinen & Reed                                                [Page 1]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+         3.3.1 Client to Client ...................................   12
+         3.3.2 Clients to Server ..................................   12
+         3.3.3 Server to Server ...................................   12
+   4. MESSAGE DETAILS .............................................   13
+      4.1 Connection Registration .................................   13
+         4.1.1 Password message ...................................   14
+         4.1.2 Nickname message ...................................   14
+         4.1.3 User message .......................................   15
+         4.1.4 Server message .....................................   16
+         4.1.5 Operator message ...................................   17
+         4.1.6 Quit message .......................................   17
+         4.1.7 Server Quit message ................................   18
+      4.2 Channel operations ......................................   19
+         4.2.1 Join message .......................................   19
+         4.2.2 Part message .......................................   20
+         4.2.3 Mode message .......................................   21
+            4.2.3.1 Channel modes .................................   21
+            4.2.3.2 User modes ....................................   22
+         4.2.4 Topic message ......................................   23
+         4.2.5 Names message ......................................   24
+         4.2.6 List message .......................................   24
+         4.2.7 Invite message .....................................   25
+         4.2.8 Kick message .......................................   25
+      4.3 Server queries and commands .............................   26
+         4.3.1 Version message ....................................   26
+         4.3.2 Stats message ......................................   27
+         4.3.3 Links message ......................................   28
+         4.3.4 Time message .......................................   29
+         4.3.5 Connect message ....................................   29
+         4.3.6 Trace message ......................................   30
+         4.3.7 Admin message ......................................   31
+         4.3.8 Info message .......................................   31
+      4.4 Sending messages ........................................   32
+         4.4.1 Private messages ...................................   32
+         4.4.2 Notice messages ....................................   33
+      4.5 User-based queries ......................................   33
+         4.5.1 Who query ..........................................   33
+         4.5.2 Whois query ........................................   34
+         4.5.3 Whowas message .....................................   35
+      4.6 Miscellaneous messages ..................................   35
+         4.6.1 Kill message .......................................   36
+         4.6.2 Ping message .......................................   37
+         4.6.3 Pong message .......................................   37
+         4.6.4 Error message ......................................   38
+   5. OPTIONAL MESSAGES ...........................................   38
+      5.1 Away message ............................................   38
+      5.2 Rehash command ..........................................   39
+      5.3 Restart command .........................................   39
+
+
+
+Oikarinen & Reed                                                [Page 2]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+      5.4 Summon message ..........................................   40
+      5.5 Users message ...........................................   40
+      5.6 Operwall command ........................................   41
+      5.7 Userhost message ........................................   42
+      5.8 Ison message ............................................   42
+   6. REPLIES .....................................................   43
+      6.1 Error Replies ...........................................   43
+      6.2 Command responses .......................................   48
+      6.3 Reserved numerics .......................................   56
+   7. Client and server authentication ............................   56
+   8. Current Implementations Details .............................   56
+      8.1 Network protocol: TCP ...................................   57
+         8.1.1 Support of Unix sockets ............................   57
+      8.2 Command Parsing .........................................   57
+      8.3 Message delivery ........................................   57
+      8.4 Connection 'Liveness' ...................................   58
+      8.5 Establishing a server-client connection .................   58
+      8.6 Establishing a server-server connection .................   58
+         8.6.1 State information exchange when connecting .........   59
+      8.7 Terminating server-client connections ...................   59
+      8.8 Terminating server-server connections ...................   59
+      8.9 Tracking nickname changes ...............................   60
+      8.10 Flood control of clients ...............................   60
+      8.11 Non-blocking lookups ...................................   61
+         8.11.1 Hostname (DNS) lookups ............................   61
+         8.11.2 Username (Ident) lookups ..........................   61
+      8.12 Configuration file .....................................   61
+         8.12.1 Allowing clients to connect .......................   62
+         8.12.2 Operators .........................................   62
+         8.12.3 Allowing servers to connect .......................   62
+         8.12.4 Administrivia .....................................   63
+      8.13 Channel membership .....................................   63
+   9. Current problems ............................................   63
+      9.1 Scalability .............................................   63
+      9.2 Labels ..................................................   63
+         9.2.1 Nicknames ..........................................   63
+         9.2.2 Channels ...........................................   64
+         9.2.3 Servers ............................................   64
+      9.3 Algorithms ..............................................   64
+   10. Support and availability ...................................   64
+   11. Security Considerations ....................................   65
+   12. Authors' Addresses .........................................   65
+
+
+
+
+
+
+
+
+
+Oikarinen & Reed                                                [Page 3]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+1.  INTRODUCTION
+
+   The IRC (Internet Relay Chat) protocol has been designed over a
+   number of years for use with text based conferencing.  This document
+   describes the current IRC protocol.
+
+   The IRC protocol has been developed on systems using the TCP/IP
+   network protocol, although there is no requirement that this remain
+   the only sphere in which it operates.
+
+   IRC itself is a teleconferencing system, which (through the use of
+   the client-server model) is well-suited to running on many machines
+   in a distributed fashion.  A typical setup involves a single process
+   (the server) forming a central point for clients (or other servers)
+   to connect to, performing the required message delivery/multiplexing
+   and other functions.
+
+1.1 Servers
+
+   The server forms the backbone of IRC, providing a point to which
+   clients may connect to to talk to each other, and a point for other
+   servers to connect to, forming an IRC network.  The only network
+   configuration allowed for IRC servers is that of a spanning tree [see
+   Fig. 1] where each server acts as a central node for the rest of the
+   net it sees.
+
+
+                           [ Server 15 ]  [ Server 13 ] [ Server 14]
+                                 /                \         /
+                                /                  \       /
+        [ Server 11 ] ------ [ Server 1 ]       [ Server 12]
+                              /        \          /
+                             /          \        /
+                  [ Server 2 ]          [ Server 3 ]
+                    /       \                      \
+                   /         \                      \
+           [ Server 4 ]    [ Server 5 ]         [ Server 6 ]
+            /    |    \                           /
+           /     |     \                         /
+          /      |      \____                   /
+         /       |           \                 /
+ [ Server 7 ] [ Server 8 ] [ Server 9 ]   [ Server 10 ]
+
+                                  :
+                               [ etc. ]
+                                  :
+
+                 [ Fig. 1. Format of IRC server network ]
+
+
+
+Oikarinen & Reed                                                [Page 4]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+1.2 Clients
+
+   A client is anything connecting to a server that is not another
+   server.  Each client is distinguished from other clients by a unique
+   nickname having a maximum length of nine (9) characters.  See the
+   protocol grammar rules for what may and may not be used in a
+   nickname.  In addition to the nickname, all servers must have the
+   following information about all clients: the real name of the host
+   that the client is running on, the username of the client on that
+   host, and the server to which the client is connected.
+
+1.2.1 Operators
+
+   To allow a reasonable amount of order to be kept within the IRC
+   network, a special class of clients (operators) is allowed to perform
+   general maintenance functions on the network.  Although the powers
+   granted to an operator can be considered as 'dangerous', they are
+   nonetheless required.  Operators should be able to perform basic
+   network tasks such as disconnecting and reconnecting servers as
+   needed to prevent long-term use of bad network routing.  In
+   recognition of this need, the protocol discussed herein provides for
+   operators only to be able to perform such functions.  See sections
+   4.1.7 (SQUIT) and 4.3.5 (CONNECT).
+
+   A more controversial power of operators is the ability  to  remove  a
+   user  from  the connected network by 'force', i.e. operators are able
+   to close the connection between any client and server.   The
+   justification for  this  is delicate since its abuse is both
+   destructive and annoying.  For further details on this type of
+   action, see section 4.6.1 (KILL).
+
+1.3 Channels
+
+   A channel is a named group of one or more clients which will all
+   receive messages addressed to that channel.  The channel is created
+   implicitly when the first client joins it, and the channel ceases to
+   exist when the last client leaves it.  While channel exists, any
+   client can reference the channel using the name of the channel.
+
+   Channels names are strings (beginning with a '&' or '#' character) of
+   length up to 200 characters.  Apart from the the requirement that the
+   first character being either '&' or '#'; the only restriction on a
+   channel name is that it may not contain any spaces (' '), a control G
+   (^G or ASCII 7), or a comma (',' which is used as a list item
+   separator by the protocol).
+
+   There are two types of channels allowed by this protocol.  One is a
+   distributed channel which is known to all the servers that are
+
+
+
+Oikarinen & Reed                                                [Page 5]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   connected to the network. These channels are marked by the first
+   character being a only clients on the server where it exists may join
+   it.  These are distinguished by a leading '&' character.  On top of
+   these two types, there are the various channel modes available to
+   alter the characteristics of individual channels.  See section 4.2.3
+   (MODE command) for more details on this.
+
+   To create a new channel or become part of an existing channel, a user
+   is required to JOIN the channel.  If the channel doesn't exist prior
+   to joining, the channel is created and the creating user becomes a
+   channel operator.  If the channel already exists, whether or not your
+   request to JOIN that channel is honoured depends on the current modes
+   of the channel. For example, if the channel is invite-only, (+i),
+   then you may only join if invited.  As part of the protocol, a user
+   may be a part of several channels at once, but a limit of ten (10)
+   channels is recommended as being ample for both experienced and
+   novice users.  See section 8.13 for more information on this.
+
+   If the IRC network becomes disjoint because of a split between two
+   servers, the channel on each side is only composed of those clients
+   which are connected to servers on the respective sides of the split,
+   possibly ceasing to exist on one side of the split.  When the split
+   is healed, the connecting servers announce to each other who they
+   think is in each channel and the mode of that channel.  If the
+   channel exists on both sides, the JOINs and MODEs are interpreted in
+   an inclusive manner so that both sides of the new connection will
+   agree about which clients are in the channel and what modes the
+   channel has.
+
+1.3.1 Channel Operators
+
+   The channel operator (also referred to as a "chop" or "chanop") on a
+   given channel is considered to 'own' that channel.  In recognition of
+   this status, channel operators are endowed with certain powers which
+   enable them to keep control and some sort of sanity in their channel.
+   As an owner of a channel, a channel operator is not required to have
+   reasons for their actions, although if their actions are generally
+   antisocial or otherwise abusive, it might be reasonable to ask an IRC
+   operator to intervene, or for the usersjust leave and go elsewhere
+   and form their own channel.
+
+   The commands which may only be used by channel operators are:
+
+        KICK    - Eject a client from the channel
+        MODE    - Change the channel's mode
+        INVITE  - Invite a client to an invite-only channel (mode +i)
+        TOPIC   - Change the channel topic in a mode +t channel
+
+
+
+
+Oikarinen & Reed                                                [Page 6]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   A channel operator is identified by the '@' symbol next to their
+   nickname whenever it is associated with a channel (ie replies to the
+   NAMES, WHO and WHOIS commands).
+
+2. The IRC Specification
+
+2.1 Overview
+
+   The protocol as described herein is for use both with server to
+   server and client to server connections.  There are, however, more
+   restrictions on client connections (which are considered to be
+   untrustworthy) than on server connections.
+
+2.2 Character codes
+
+   No specific character set is specified. The protocol is based on a a
+   set of codes which are composed of eight (8) bits, making up an
+   octet.  Each message may be composed of any number of these octets;
+   however, some octet values are used for control codes which act as
+   message delimiters.
+
+   Regardless of being an 8-bit protocol, the delimiters and keywords
+   are such that protocol is mostly usable from USASCII terminal and a
+   telnet connection.
+
+   Because of IRC's scandanavian origin, the characters {}| are
+   considered to be the lower case equivalents of the characters []\,
+   respectively. This is a critical issue when determining the
+   equivalence of two nicknames.
+
+2.3 Messages
+
+   Servers and clients send eachother messages which may or may not
+   generate a reply.  If the message contains a valid command, as
+   described in later sections, the client should expect a reply as
+   specified but it is not advised to wait forever for the reply; client
+   to server and server to server communication is essentially
+   asynchronous in nature.
+
+   Each IRC message may consist of up to three main parts: the prefix
+   (optional), the command, and the command parameters (of which there
+   may be up to 15).  The prefix, command, and all parameters are
+   separated by one (or more) ASCII space character(s) (0x20).
+
+   The presence of a prefix is indicated with a single leading ASCII
+   colon character (':', 0x3b), which must be the first character of the
+   message itself.  There must be no gap (whitespace) between the colon
+   and the prefix.  The prefix is used by servers to indicate the true
+
+
+
+Oikarinen & Reed                                                [Page 7]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   origin of the message.  If the prefix is missing from the message, it
+   is assumed to have originated from the connection from which it was
+   received.  Clients should not use prefix when sending a message from
+   themselves; if they use a prefix, the only valid prefix is the
+   registered nickname associated with the client.  If the source
+   identified by the prefix cannot be found from the server's internal
+   database, or if the source is registered from a different link than
+   from which the message arrived, the server must ignore the message
+   silently.
+
+   The command must either be a valid IRC command or a three (3) digit
+   number represented in ASCII text.
+
+   IRC messages are always lines of characters terminated with a CR-LF
+   (Carriage Return - Line Feed) pair, and these messages shall not
+   exceed 512 characters in length, counting all characters including
+   the trailing CR-LF. Thus, there are 510 characters maximum allowed
+   for the command and its parameters.  There is no provision for
+   continuation message lines.  See section 7 for more details about
+   current implementations.
+
+2.3.1 Message format in 'pseudo' BNF
+
+   The protocol messages must be extracted from the contiguous stream of
+   octets.  The current solution is to designate two characters, CR and
+   LF, as message separators.   Empty  messages  are  silently  ignored,
+   which permits  use  of  the  sequence  CR-LF  between  messages
+   without extra problems.
+
+   The extracted message is parsed into the components <prefix>,
+   <command> and list of parameters matched either by <middle> or
+   <trailing> components.
+
+   The BNF representation for this is:
+
+
+<server_message> ::= <numeric> <command> <params> <crlf>
+<message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
+<prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
+<command>  ::= <letter> { <letter> } | <number> <number> <number>
+<SPACE>    ::= ' ' { ' ' }
+<params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
+<numeric>  ::= <numeric> { <letter> | <number> | '[' | ']' }
+
+<middle>   ::= <Any *non-empty* sequence of octets not including SPACE
+               or NUL or CR or LF, the first of which may not be ':'>
+<trailing> ::= <Any, possibly *empty*, sequence of octets not including
+                 NUL or CR or LF>
+
+<crlf>     ::= CR LF
+
+
+
+Oikarinen & Reed                                                [Page 8]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+NOTES:
+
+  1)    <SPACE> is consists only of SPACE character(s) (0x20).
+        Specially notice that TABULATION, and all other control
+        characters are considered NON-WHITE-SPACE.
+
+  2)    After extracting the parameter list, all parameters are equal,
+        whether matched by <middle> or <trailing>. <Trailing> is just
+        a syntactic trick to allow SPACE within parameter.
+
+  3)    The fact that CR and LF cannot appear in parameter strings is
+        just artifact of the message framing. This might change later.
+
+  4)    The NUL character is not special in message framing, and
+        basically could end up inside a parameter, but as it would
+        cause extra complexities in normal C string handling. Therefore
+        NUL is not allowed within messages.
+
+  5)    The last parameter may be an empty string.
+
+  6)    Use of the extended prefix (['!' <user> ] ['@' <host> ]) must
+        not be used in server to server communications and is only
+        intended for server to client messages in order to provide
+        clients with more useful information about who a message is
+        from without the need for additional queries.
+
+   Most protocol messages specify additional semantics and syntax for
+   the extracted parameter strings dictated by their position in the
+   list.  For example, many server commands will assume that the first
+   parameter after the command is the list of targets, which can be
+   described with:
+
+   <target>     ::= <to> [ "," <target> ]
+   <to>         ::= <channel> | <user> '@' <servername> | <nick> | <mask>
+   <channel>    ::= ('#' | '&' | '+') <chstring>
+   <servername> ::= <host>
+   <host>       ::= see RFC 952 [DNS:4] for details on allowed hostnames
+   <nick>       ::= <letter> { <letter> | <number> | <special> }
+   <mask>       ::= $(<servername> | @<hostname>)
+   <chstring>   ::= <any 8bit code except SPACE, BELL, NUL, CR, LF and
+                     comma (',')>
+
+   Other parameter syntaxes are:
+
+   <user>       ::= <nonwhite> { <nonwhite> }
+   <letter>     ::= 'a' ... 'z' | 'A' ... 'Z'
+   <number>     ::= '0' ... '9'
+   <special>    ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
+
+
+
+Oikarinen & Reed                                                [Page 9]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   <nonwhite>   ::= <any 8bit code except SPACE (0x20), NUL (0x0), CR
+                     (0xd), and LF (0xa)>
+
+2.4 Numeric replies
+
+   Most of the messages sent to the server generate a reply of some
+   sort.  The most common reply is the numeric reply, used for both
+   errors and normal replies.  The numeric reply must be sent as one
+   message consisting of the sender prefix, the three digit numeric, and
+   the target of the reply.  A numeric reply is not allowed to originate
+   from a client; any such messages received by a server are silently
+   dropped. In all other respects, a numeric reply is just like a normal
+   message, except that the keyword is made up of 3 numeric digits
+   rather than a string of letters.  A list of different replies is
+   supplied in section 6.
+
+3. IRC Concepts.
+
+   This section is devoted to describing the actual concepts behind  the
+   organization  of  the  IRC  protocol and how the current
+   implementations deliver different classes of messages.
+
+
+
+                          1--\
+                              A        D---4
+                          2--/ \      /
+                                B----C
+                               /      \
+                              3        E
+
+   Servers: A, B, C, D, E         Clients: 1, 2, 3, 4
+
+                    [ Fig. 2. Sample small IRC network ]
+
+3.1 One-to-one communication
+
+   Communication on a one-to-one basis is usually only performed by
+   clients, since most server-server traffic is not a result of servers
+   talking only to each other.  To provide a secure means for clients to
+   talk to each other, it is required that all servers be able to send a
+   message in exactly one direction along the spanning tree in order to
+   reach any client.  The path of a message being delivered is the
+   shortest path between any two points on the spanning tree.
+
+   The following examples all refer to Figure 2 above.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 10]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Example 1:
+     A message between clients 1 and 2 is only seen by server A, which
+     sends it straight to client 2.
+
+Example 2:
+     A message between clients 1 and 3 is seen by servers A & B, and
+     client 3.  No other clients or servers are allowed see the message.
+
+Example 3:
+     A message between clients 2 and 4 is seen by servers A, B, C & D
+     and client 4 only.
+
+3.2 One-to-many
+
+   The main goal of IRC is to provide a  forum  which  allows  easy  and
+   efficient  conferencing (one to many conversations).  IRC offers
+   several means to achieve this, each serving its own purpose.
+
+3.2.1 To a list
+
+   The least efficient style of one-to-many conversation is through
+   clients talking to a 'list' of users.  How this is done is almost
+   self explanatory: the client gives a list of destinations to which
+   the message is to be delivered and the server breaks it up and
+   dispatches a separate copy of the message to each given destination.
+   This isn't as efficient as using a group since the destination list
+   is broken up and the dispatch sent without checking to make sure
+   duplicates aren't sent down each path.
+
+3.2.2 To a group (channel)
+
+   In IRC the channel has a role equivalent to that of the multicast
+   group; their existence is dynamic (coming and going as people join
+   and leave channels) and the actual conversation carried out on a
+   channel is only sent to servers which are supporting users on a given
+   channel.  If there are multiple users on a server in the same
+   channel, the message text is sent only once to that server and then
+   sent to each client on the channel.  This action is then repeated for
+   each client-server combination until the original message has fanned
+   out and reached each member of the channel.
+
+   The following examples all refer to Figure 2.
+
+Example 4:
+     Any channel with 1 client in it. Messages to the channel go to the
+     server and then nowhere else.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 11]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Example 5:
+     2 clients in a channel. All messages traverse a path as if they
+     were private messages between the two clients outside a channel.
+
+Example 6:
+     Clients 1, 2 and 3 in a channel.  All messages to the channel are
+     sent to all clients and only those servers which must be traversed
+     by the message if it were a private message to a single client.  If
+     client 1 sends a message, it goes back to client 2 and then via
+     server B to client 3.
+
+3.2.3 To a host/server mask
+
+   To provide IRC operators with some mechanism to send  messages  to  a
+   large body of related users, host and server mask messages are
+   provided.  These messages are sent to users whose host or server
+   information  match that  of  the mask.  The messages are only sent to
+   locations where users are, in a fashion similar to that of channels.
+
+3.3 One-to-all
+
+   The one-to-all type of message is better described as a broadcast
+   message, sent to all clients or servers or both.  On a large network
+   of users and servers, a single message can result in a lot of traffic
+   being sent over the network in an effort to reach all of the desired
+   destinations.
+
+   For some messages, there is no option but to broadcast it to all
+   servers so that the state information held by each server is
+   reasonably consistent between servers.
+
+3.3.1 Client-to-Client
+
+   There is no class of message which, from a single message, results in
+   a message being sent to every other client.
+
+3.3.2 Client-to-Server
+
+   Most of the commands which result in a change of state information
+   (such as channel membership, channel mode, user status, etc) must be
+   sent to all servers by default, and this distribution may not be
+   changed by the client.
+
+3.3.3 Server-to-Server.
+
+   While most messages between servers are distributed to all 'other'
+   servers, this is only required for any message that affects either a
+   user, channel or server.  Since these are the basic items found in
+
+
+
+Oikarinen & Reed                                               [Page 12]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   IRC, nearly all messages originating from a server are broadcast to
+   all other connected servers.
+
+4. Message details
+
+   On the following pages are descriptions of each message recognized by
+   the IRC server and client.  All commands described in this section
+   must be implemented by any server for this protocol.
+
+   Where the reply ERR_NOSUCHSERVER is listed, it means that the
+   <server> parameter could not be found.  The server must not send any
+   other replies after this for that command.
+
+   The server to which a client is connected is required to parse the
+   complete message, returning any appropriate errors.  If the server
+   encounters a fatal error while parsing a message, an error must be
+   sent back to the client and the parsing terminated.  A fatal error
+   may be considered to be incorrect command, a destination which is
+   otherwise unknown to the server (server, nick or channel names fit
+   this category), not enough parameters or incorrect privileges.
+
+   If a full set of parameters is presented, then each must be checked
+   for validity and appropriate responses sent back to the client.  In
+   the case of messages which use parameter lists using the comma as an
+   item separator, a reply must be sent for each item.
+
+   In the examples below, some messages appear using the full format:
+
+   :Name COMMAND parameter list
+
+   Such examples represent a message from "Name" in transit between
+   servers, where it is essential to include the name of the original
+   sender of the message so remote servers may send back a reply along
+   the correct path.
+
+4.1 Connection Registration
+
+   The commands described here are used to register a connection with an
+   IRC server as either a user or a server as well as correctly
+   disconnect.
+
+   A "PASS" command is not required for either client or server
+   connection to be registered, but it must precede the server message
+   or the latter of the NICK/USER combination.  It is strongly
+   recommended that all server connections have a password in order to
+   give some level of security to the actual connections.  The
+   recommended order for a client to register is as follows:
+
+
+
+
+Oikarinen & Reed                                               [Page 13]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           1. Pass message
+           2. Nick message
+           3. User message
+
+4.1.1 Password message
+
+
+      Command: PASS
+   Parameters: <password>
+
+   The PASS command is used to set a 'connection password'.  The
+   password can and must be set before any attempt to register the
+   connection is made.  Currently this requires that clients send a PASS
+   command before sending the NICK/USER combination and servers *must*
+   send a PASS command before any SERVER command.  The password supplied
+   must match the one contained in the C/N lines (for servers) or I
+   lines (for clients).  It is possible to send multiple PASS commands
+   before registering but only the last one sent is used for
+   verification and it may not be changed once registered.  Numeric
+   Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+
+   Example:
+
+           PASS secretpasswordhere
+
+4.1.2 Nick message
+
+      Command: NICK
+   Parameters: <nickname> [ <hopcount> ]
+
+   NICK message is used to give user a nickname or change the previous
+   one.  The <hopcount> parameter is only used by servers to indicate
+   how far away a nick is from its home server.  A local connection has
+   a hopcount of 0.  If supplied by a client, it must be ignored.
+
+   If a NICK message arrives at a server which already knows about an
+   identical nickname for another client, a nickname collision occurs.
+   As a result of a nickname collision, all instances of the nickname
+   are removed from the server's database, and a KILL command is issued
+   to remove the nickname from all other server's database. If the NICK
+   message causing the collision was a nickname change, then the
+   original (old) nick must be removed as well.
+
+   If the server recieves an identical NICK from a client which is
+   directly connected, it may issue an ERR_NICKCOLLISION to the local
+   client, drop the NICK command, and not generate any kills.
+
+
+
+Oikarinen & Reed                                               [Page 14]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Numeric Replies:
+
+           ERR_NONICKNAMEGIVEN             ERR_ERRONEUSNICKNAME
+           ERR_NICKNAMEINUSE               ERR_NICKCOLLISION
+
+   Example:
+
+   NICK Wiz                        ; Introducing new nick "Wiz".
+
+   :WiZ NICK Kilroy                ; WiZ changed his nickname to Kilroy.
+
+4.1.3 User message
+
+      Command: USER
+   Parameters: <username> <usermode> <snomask> <info>
+
+   The USER message is used at the beginning of connection to specify
+   the username, usermod, snomask and information of a new user. Servers
+   use the NICK command to send all information once USER and NICK have
+   been received from the client. Only after both USER and NICK have been
+   received from a client does a user become registered.
+
+   Undernet does not send USER between servers, NICK is used to send
+   all information about a user. The usermode parameter allows clients to
+   set their initial user mode (see MODE) upon registration, the snomask
+   parameter allows the user to specify a specific set of server notices
+   they wish to receive. If the usermode and snomasks look like host names
+   they are ignored. If a valid ident response is received from the
+   client's host upon connection, the name returned from the ident server
+   is used and username is ignored. 
+   It must be noted that info parameter must be the last parameter,
+   because it may contain space characters and must be prefixed with a
+   colon (':') to make sure this is recognised as such.
+
+   Since it is easy for a client to lie about its username by relying
+   solely on the USER message, the use of an "Identity Server" is
+   recommended.  If the host which a user connects from has such a
+   server enabled the username is set to that as in the reply from the
+   "Identity Server".
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_ALREADYREGISTRED
+
+   Examples:
+
+
+   USER guest tolmoon tolsun :Ronnie Reagan
+
+
+
+Oikarinen & Reed                                               [Page 15]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                   ; User registering themselves with a
+                                   username of "guest" and real name
+                                   "Ronnie Reagan".
+
+
+   :testnick USER guest tolmoon tolsun :Ronnie Reagan
+                                   ; message between servers with the
+                                   nickname for which the USER command
+                                   belongs to
+
+4.1.4 Server message
+
+      Command: SERVER
+   Parameters: <servername> <hopcount> <info>
+
+   The server message is used to tell a server that the other end of a
+   new connection is a server. This message is also used to pass server
+   data over whole net.  When a new server is connected to net,
+   information about it be broadcast to the whole network.  <hopcount>
+   is used to give all servers some internal information on how far away
+   all servers are.  With a full server list, it would be possible to
+   construct a map of the entire server tree, but hostmasks prevent this
+   from being done.
+
+   The SERVER message must only be accepted from either (a) a connection
+   which is yet to be registered and is attempting to register as a
+   server, or (b) an existing connection to another server, in  which
+   case the SERVER message is introducing a new server behind that
+   server.
+
+   Most errors that occur with the receipt of a SERVER command result in
+   the connection being terminated by the destination host (target
+   SERVER).  Error replies are usually sent using the "ERROR" command
+   rather than the numeric since the ERROR command has several useful
+   properties which make it useful here.
+
+   If a SERVER message is parsed and attempts to introduce a server
+   which is already known to the receiving server, the connection from
+   which that message must be closed (following the correct procedures),
+   since a duplicate route to a server has formed and the acyclic nature
+   of the IRC tree broken.
+
+   Numeric Replies:
+
+           ERR_ALREADYREGISTRED
+
+   Example:
+
+
+
+
+Oikarinen & Reed                                               [Page 16]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+SERVER test.oulu.fi 1 :[tolsun.oulu.fi] Experimental server
+                                ; New server test.oulu.fi introducing
+                                itself and attempting to register.  The
+                                name in []'s is the hostname for the
+                                host running test.oulu.fi.
+
+
+:tolsun.oulu.fi SERVER csd.bu.edu 5 :BU Central Server
+                                ; Server tolsun.oulu.fi is our uplink
+                                for csd.bu.edu which is 5 hops away.
+
+4.1.5 Oper
+
+      Command: OPER
+   Parameters: <user> <password>
+
+   OPER message is used by a normal user to obtain operator privileges.
+   The combination of <user> and <password> are required to gain
+   Operator privileges.
+
+   If the client sending the OPER command supplies the correct password
+   for the given user, the server then informs the rest of the network
+   of the new operator by issuing a "MODE +o" for the clients nickname.
+
+   The OPER message is client-server only.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              RPL_YOUREOPER
+           ERR_NOOPERHOST                  ERR_PASSWDMISMATCH
+
+   Example:
+
+   OPER foo bar                    ; Attempt to register as an operator
+                                   using a username of "foo" and "bar" as
+                                   the password.
+
+4.1.6 Quit
+
+      Command: QUIT
+   Parameters: [<Quit message>]
+
+   A client session is ended with a quit message.  The server must close
+   the connection to a client which sends a QUIT message. If a "Quit
+   Message" is given, this will be sent instead of the default message,
+   the nickname.
+
+   When netsplits (disconnecting of two servers) occur, the quit message
+
+
+
+Oikarinen & Reed                                               [Page 17]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   is composed of the names of two servers involved, separated by a
+   space.  The first name is that of the server which is still connected
+   and the second name is that of the server that has become
+   disconnected.
+
+   If, for some other reason, a client connection is closed without  the
+   client  issuing  a  QUIT  command  (e.g.  client  dies and EOF occurs
+   on socket), the server is required to fill in the quit  message  with
+   some sort  of  message  reflecting the nature of the event which
+   caused it to happen.
+
+   Numeric Replies:
+
+           None.
+
+   Examples:
+
+   QUIT :Gone to have lunch        ; Preferred message format.
+
+4.1.7 Server quit message
+
+      Command: SQUIT
+   Parameters: <server> <comment>
+
+   The SQUIT message is needed to tell about quitting or dead servers.
+   If a server wishes to break the connection to another server it must
+   send a SQUIT message to the other server, using the the name of the
+   other server as the server parameter, which then closes its
+   connection to the quitting server.
+
+   This command is also available operators to help keep a network of
+   IRC servers connected in an orderly fashion.  Operators may also
+   issue an SQUIT message for a remote server connection.  In this case,
+   the SQUIT must be parsed by each server inbetween the operator and
+   the remote server, updating the view of the network held by each
+   server as explained below.
+
+   The <comment> should be supplied by all operators who execute a SQUIT
+   for a remote server (that is not connected to the server they are
+   currently on) so that other operators are aware for the reason of
+   this action.  The <comment> is also filled in by servers which may
+   place an error or similar message here.
+
+   Both of the servers which are on either side of the connection being
+   closed are required to to send out a SQUIT message (to all its other
+   server connections) for all other servers which are considered to be
+   behind that link.
+
+
+
+
+Oikarinen & Reed                                               [Page 18]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Similarly, a QUIT message must be sent to the other connected servers
+   rest of the network on behalf of all clients behind that link.  In
+   addition to this, all channel members of a channel which lost a
+   member due to the split must be sent a QUIT message.
+
+   If a server connection is terminated prematurely (e.g. the server  on
+   the  other  end  of  the  link  died),  the  server  which  detects
+   this disconnection is required to inform the rest of  the  network
+   that  the connection  has  closed  and  fill  in  the comment field
+   with something appropriate.
+
+   Numeric replies:
+
+           ERR_NOPRIVILEGES                ERR_NOSUCHSERVER
+
+   Example:
+
+   SQUIT tolsun.oulu.fi :Bad Link ? ; the server link tolson.oulu.fi has
+                                   been terminated because of "Bad Link".
+
+   :Trillian SQUIT cm22.eng.umd.edu :Server out of control
+                                    ; message from Trillian to disconnect
+                                   "cm22.eng.umd.edu" from the net
+                                    because "Server out of control".
+
+4.2 Channel operations
+
+   This group of messages is concerned with manipulating channels, their
+   properties (channel modes), and their contents (typically clients).
+   In implementing these, a number of race conditions are inevitable
+   when clients at opposing ends of a network send commands which will
+   ultimately clash.  It is also required that servers keep a nickname
+   history to ensure that wherever a <nick> parameter is given, the
+   server check its history in case it has recently been changed.
+
+4.2.1 Join message
+
+      Command: JOIN
+   Parameters: <channel>{,<channel>} [<key>{,<key>}]
+
+   The JOIN command is used by client to start listening a specific
+   channel. Whether or not a client is allowed to join a channel is
+   checked only by the server the client is connected to; all other
+   servers automatically add the user to the channel when it is received
+   from other servers.  The conditions which affect this are as follows:
+
+           1.  the user must be invited if the channel is invite-only;
+
+
+
+
+Oikarinen & Reed                                               [Page 19]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           2.  the user's nick/username/hostname must not match any
+               active bans;
+
+           3.  the correct key (password) must be given if it is set.
+
+   These are discussed in more detail under the MODE command (see
+   section 4.2.3 for more details).
+
+   Once a user has joined a channel, they receive notice about all
+   commands their server receives which affect the channel.  This
+   includes MODE, KICK, PART, QUIT and of course PRIVMSG/NOTICE.  The
+   JOIN command needs to be broadcast to all servers so that each server
+   knows where to find the users who are on the channel.  This allows
+   optimal delivery of PRIVMSG/NOTICE messages to the channel.
+
+   If a JOIN is successful, the user is then sent the channel's topic
+   (using RPL_TOPIC) and the list of users who are on the channel (using
+   RPL_NAMREPLY), which must include the user joining.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_BANNEDFROMCHAN
+           ERR_INVITEONLYCHAN              ERR_BADCHANNELKEY
+           ERR_CHANNELISFULL               ERR_BADCHANMASK
+           ERR_NOSUCHCHANNEL               ERR_TOOMANYCHANNELS
+           RPL_TOPIC
+
+   Examples:
+
+   JOIN #foobar                    ; join channel #foobar.
+
+   JOIN &foo fubar                 ; join channel &foo using key "fubar".
+
+   JOIN #foo,&bar fubar            ; join channel #foo using key "fubar"
+                                   and &bar using no key.
+
+   JOIN #foo,#bar fubar,foobar     ; join channel #foo using key "fubar".
+                                   and channel #bar using key "foobar".
+
+   JOIN #foo,#bar                  ; join channels #foo and #bar.
+
+   :WiZ JOIN #Twilight_zone        ; JOIN message from WiZ
+
+4.2.2 Part message
+
+      Command: PART
+   Parameters: <channel>{,<channel>}
+
+
+
+
+Oikarinen & Reed                                               [Page 20]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The PART message causes the client sending the message to be removed
+   from the list of active users for all given channels listed in the
+   parameter string.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+           ERR_NOTONCHANNEL
+
+   Examples:
+
+   PART #twilight_zone             ; leave channel "#twilight_zone"
+
+   PART #oz-ops,&group5            ; leave both channels "&group5" and
+                                   "#oz-ops".
+
+4.2.3 Mode message
+
+      Command: MODE
+
+   The MODE command is a dual-purpose command in IRC.  It allows both
+   usernames and channels to have their mode changed.  The rationale for
+   this choice is that one day nicknames will be obsolete and the
+   equivalent property will be the channel.
+
+   When parsing MODE messages, it is recommended that the entire message
+   be parsed first and then the changes which resulted then passed on.
+
+4.2.3.1 Channel modes
+
+   Parameters: <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>]
+               [<ban mask>]
+
+   The MODE command is provided so that channel operators may change the
+   characteristics of `their' channel.  It is also required that servers
+   be able to change channel modes so that channel operators may be
+   created.
+
+   The various modes available for channels are as follows:
+
+           o - give/take channel operator privileges;
+           p - private channel flag;
+           s - secret channel flag;
+           i - invite-only channel flag;
+           t - topic settable by channel operator only flag;
+           n - no messages to channel from clients on the outside;
+           m - moderated channel;
+           l - set the user limit to channel;
+
+
+
+Oikarinen & Reed                                               [Page 21]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+           b - set a ban mask to keep users out;
+           v - give/take the ability to speak on a moderated channel;
+           k - set a channel key (password).
+
+   When using the 'o' and 'b' options, a restriction on a total of three
+   per mode command has been imposed.  That is, any combination of 'o'
+   and
+
+4.2.3.2 User modes
+
+   Parameters: <nickname> {[+|-]|i|w|s|o}
+
+   The user MODEs are typically changes which affect either how the
+   client is seen by others or what 'extra' messages the client is sent.
+   A user MODE command may only be accepted if both the sender of the
+   message and the nickname given as a parameter are both the same.
+
+   The available modes are as follows:
+
+           i - marks a users as invisible;
+           s - marks a user for receipt of server notices;
+           w - user receives wallops;
+           o - operator flag.
+
+   Additional modes may be available later on.
+
+   If a user attempts to make themselves an operator using the "+o"
+   flag, the attempt should be ignored.  There is no restriction,
+   however, on anyone `deopping' themselves (using "-o").  Numeric
+   Replies:
+
+           ERR_NEEDMOREPARAMS              RPL_CHANNELMODEIS
+           ERR_CHANOPRIVSNEEDED            ERR_NOSUCHNICK
+           ERR_NOTONCHANNEL                ERR_KEYSET
+           RPL_BANLIST                     RPL_ENDOFBANLIST
+           ERR_UNKNOWNMODE                 ERR_NOSUCHCHANNEL
+
+           ERR_USERSDONTMATCH              RPL_UMODEIS
+           ERR_UMODEUNKNOWNFLAG
+
+   Examples:
+
+           Use of Channel Modes:
+
+MODE #Finnish +im               ; Makes #Finnish channel moderated and
+                                'invite-only'.
+
+MODE #Finnish +o Kilroy         ; Gives 'chanop' privileges to Kilroy on
+
+
+
+Oikarinen & Reed                                               [Page 22]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                channel #Finnish.
+
+MODE #Finnish +v Wiz            ; Allow WiZ to speak on #Finnish.
+
+MODE #Fins -s                   ; Removes 'secret' flag from channel
+                                #Fins.
+
+MODE #42 +k oulu                ; Set the channel key to "oulu".
+
+MODE #eu-opers +l 10            ; Set the limit for the number of users
+                                on channel to 10.
+
+MODE &oulu +b                   ; list ban masks set for channel.
+
+MODE &oulu +b *!*@*             ; prevent all users from joining.
+
+MODE &oulu +b *!*@*.edu         ; prevent any user from a hostname
+                                matching *.edu from joining.
+
+        Use of user Modes:
+
+:MODE WiZ -w                    ; turns reception of WALLOPS messages
+                                off for WiZ.
+
+:Angel MODE Angel +i            ; Message from Angel to make themselves
+                                invisible.
+
+MODE WiZ -o                     ; WiZ 'deopping' (removing operator
+                                status).  The plain reverse of this
+                                command ("MODE WiZ +o") must not be
+                                allowed from users since would bypass
+                                the OPER command.
+
+4.2.4 Topic message
+
+      Command: TOPIC
+   Parameters: <channel> [<topic>]
+
+   The TOPIC message is used to change or view the topic of a channel.
+   The topic for channel <channel> is returned if there is no <topic>
+   given.  If the <topic> parameter is present, the topic for that
+   channel will be changed, if the channel modes permit this action.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOTONCHANNEL
+           RPL_NOTOPIC                     RPL_TOPIC
+           ERR_CHANOPRIVSNEEDED
+
+
+
+Oikarinen & Reed                                               [Page 23]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Examples:
+
+   :Wiz TOPIC #test :New topic     ;User Wiz setting the topic.
+
+   TOPIC #test :another topic      ;set the topic on #test to "another
+                                   topic".
+
+   TOPIC #test                     ; check the topic for #test.
+
+4.2.5 Names message
+
+      Command: NAMES
+   Parameters: [<channel>{,<channel>}]
+
+   By using the NAMES command, a user can list all nicknames that are
+   visible to them on any channel that they can see.  Channel names
+   which they can see are those which aren't private (+p) or secret (+s)
+   or those which they are actually on.  The <channel> parameter
+   specifies which channel(s) to return information about if valid.
+   There is no error reply for bad channel names.
+
+   If no <channel> parameter is given, a list of all channels and their
+   occupants is returned.  At the end of this list, a list of users who
+   are visible but either not on any channel or not on a visible channel
+   are listed as being on `channel' "*".
+
+   Numerics:
+
+           RPL_NAMREPLY                    RPL_ENDOFNAMES
+
+   Examples:
+
+   NAMES #twilight_zone,#42        ; list visible users on #twilight_zone
+                                   and #42 if the channels are visible to
+                                   you.
+
+   NAMES                           ; list all visible channels and users
+
+4.2.6 List message
+
+      Command: LIST
+   Parameters: [<channel>{,<channel>} [<server>]]
+
+   The list message is used to list channels and their topics.  If  the
+   <channel>  parameter  is  used,  only  the  status  of  that  channel
+   is displayed.  Private  channels  are  listed  (without  their
+   topics)  as channel "Prv" unless the client generating the query is
+   actually on that channel.  Likewise, secret channels are not listed
+
+
+
+Oikarinen & Reed                                               [Page 24]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   at  all  unless  the client is a member of the channel in question.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_LISTSTART
+           RPL_LIST                        RPL_LISTEND
+
+   Examples:
+
+   LIST                            ; List all channels.
+
+   LIST #twilight_zone,#42         ; List channels #twilight_zone and #42
+
+4.2.7 Invite message
+
+      Command: INVITE
+   Parameters: <nickname> <channel>
+
+   The INVITE message is used to invite users to a channel.  The
+   parameter <nickname> is the nickname of the person to be invited to
+   the target channel <channel>.  There is no requirement that the
+   channel the target user is being invited to must exist or be a valid
+   channel.  To invite a user to a channel which is invite only (MODE
+   +i), the client sending the invite must be recognised as being a
+   channel operator on the given channel.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHNICK
+           ERR_NOTONCHANNEL                ERR_USERONCHANNEL
+           ERR_CHANOPRIVSNEEDED
+           RPL_INVITING                    RPL_AWAY
+
+   Examples:
+
+   :Angel INVITE Wiz #Dust         ; User Angel inviting WiZ to channel
+                                   #Dust
+
+   INVITE Wiz #Twilight_Zone       ; Command to invite WiZ to
+                                   #Twilight_zone
+
+4.2.8 Kick command
+
+      Command: KICK
+   Parameters: <channel> <user> [<comment>]
+
+   The KICK command can be  used  to  forcibly  remove  a  user  from  a
+   channel.   It  'kicks  them  out'  of the channel (forced PART).
+
+
+
+Oikarinen & Reed                                               [Page 25]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Only a channel operator may kick another user out of a  channel.
+   Each  server that  receives  a KICK message checks that it is valid
+   (ie the sender is actually a  channel  operator)  before  removing
+   the  victim  from  the channel.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS              ERR_NOSUCHCHANNEL
+           ERR_BADCHANMASK                 ERR_CHANOPRIVSNEEDED
+           ERR_NOTONCHANNEL
+
+   Examples:
+
+KICK &Melbourne Matthew         ; Kick Matthew from &Melbourne
+
+KICK #Finnish John :Speaking English
+                                ; Kick John from #Finnish using
+                                "Speaking English" as the reason
+                                (comment).
+
+:WiZ KICK #Finnish John         ; KICK message from WiZ to remove John
+                                from channel #Finnish
+
+NOTE:
+     It is possible to extend the KICK command parameters to the
+following:
+
+<channel>{,<channel>} <user>{,<user>} [<comment>]
+
+4.3 Server queries and commands
+
+   The server query group of commands has been designed to return
+   information about any server which is connected to the network.  All
+   servers connected must respond to these queries and respond
+   correctly.  Any invalid response (or lack thereof) must be considered
+   a sign of a broken server and it must be disconnected/disabled as
+   soon as possible until the situation is remedied.
+
+   In these queries, where a parameter appears as "<server>", it will
+   usually mean it can be a nickname or a server or a wildcard name of
+   some sort.  For each parameter, however, only one query and set of
+   replies is to be generated.
+
+4.3.1 Version message
+
+      Command: VERSION
+   Parameters: [<server>]
+
+
+
+
+Oikarinen & Reed                                               [Page 26]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The VERSION message is used  to  query  the  version  of  the  server
+   program.  An optional parameter <server> is used to query the version
+   of the server program which a client is not directly connected to.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_VERSION
+
+   Examples:
+
+   :Wiz VERSION *.se               ; message from Wiz to check the version
+                                   of a server matching "*.se"
+
+   VERSION tolsun.oulu.fi          ; check the version of server
+                                   "tolsun.oulu.fi".
+
+4.3.2 Stats message
+
+      Command: STATS
+   Parameters: [<query> [<server>]]
+
+   Many stats commands are only available to opers, please document
+   which ones are available to users and which are available to opers.
+
+   The stats message is used to query statistics of certain server.  If
+   <server> parameter is omitted, only the end of stats reply is sent
+   back.  The implementation of this command is highly dependent on the
+   server which replies, although the server must be able to supply
+   information as described by the queries below (or similar).
+
+   A query may be given by any single letter which is only checked by
+   the destination server (if given as the <server> parameter) and is
+   otherwise passed on by intermediate servers, ignored and unaltered.
+   The following queries are those found in the current IRC
+   implementation and provide a large portion of the setup information
+   for that server.  Although these may not be supported in the same way
+   by other versions, all servers should be able to supply a valid reply
+   to a STATS query which is consistent with the reply formats currently
+   used and the purpose of the query.
+
+   The currently supported queries are:
+
+           c - returns a list of servers which the server may connect
+               to or allow connections from;
+           h - returns a list of servers which are either forced to be
+               treated as leaves or allowed to act as hubs;
+           i - returns a list of hosts which the server allows a client
+               to connect from;
+           k - returns a list of banned username/hostname combinations
+               for that server;
+           l - returns a list of the server's connections, showing how
+
+
+
+Oikarinen & Reed                                               [Page 27]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+               long each connection has been established and the traffic
+               over that connection in bytes and messages for each
+               direction;
+           m - returns a list of commands supported by the server and
+               the usage count for each if the usage count is non zero;
+           o - returns a list of hosts from which normal clients may
+               become operators;
+           y - show Y (Class) lines from server's configuration file;
+           u - returns a string showing how long the server has been up.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_STATSCLINE                  RPL_STATSNLINE
+           RPL_STATSILINE                  RPL_STATSKLINE
+           RPL_STATSQLINE                  RPL_STATSLLINE
+           RPL_STATSLINKINFO               RPL_STATSUPTIME
+           RPL_STATSCOMMANDS               RPL_STATSOLINE
+           RPL_STATSHLINE                  RPL_ENDOFSTATS
+
+   Examples:
+
+STATS m                         ; check the command usage for the server
+                                you are connected to
+
+:Wiz STATS c eff.org            ; request by WiZ for C/N line
+                                information from server eff.org
+
+4.3.3 Links message
+
+      Command: LINKS
+   Parameters: [[<remote server>] <server mask>]
+
+   With LINKS, a user can list all servers which are known by the server
+   answering the query.  The returned list of servers must match the
+   mask, or if no mask is given, the full list is returned.
+
+   If <remote server> is given in addition to <server mask>, the LINKS
+   command is forwarded to the first server found that matches that name
+   (if any), and that server is then required to answer the query.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_LINKS                       RPL_ENDOFLINKS
+
+   Examples:
+
+
+
+
+Oikarinen & Reed                                               [Page 28]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+LINKS *.au                      ; list all servers which have a name
+                                that matches *.au;
+
+:WiZ LINKS *.bu.edu *.edu       ; LINKS message from WiZ to the first
+                                server matching *.edu for a list of
+                                servers matching *.bu.edu.
+
+4.3.4 Time message
+
+      Command: TIME
+   Parameters: [<server>]
+
+   The time message is used to query local time from the specified
+   server. If the server parameter is not given, the server handling the
+   command must reply to the query.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                RPL_TIME
+
+   Examples:
+
+   TIME tolsun.oulu.fi             ; check the time on the server
+                                   "tolson.oulu.fi"
+
+   Angel TIME *.au                 ; user angel checking the time on a
+                                   server matching "*.au"
+
+4.3.5 Connect message
+
+      Command: CONNECT
+   Parameters: <target server> [<port> [<remote server>]]
+
+   The CONNECT command can be used to force a server to try to establish
+   a new connection to another server immediately.  CONNECT is a
+   privileged command and is to be available only to IRC Operators.  If
+   a remote server is given then the CONNECT attempt is made by that
+   server to <target server> and <port>.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_NOPRIVILEGES
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+CONNECT tolsun.oulu.fi          ; Attempt to connect a server to
+                                tolsun.oulu.fi
+
+
+
+Oikarinen & Reed                                               [Page 29]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+:WiZ CONNECT eff.org 6667 csd.bu.edu
+                                ; CONNECT attempt by WiZ to get servers
+                                eff.org and csd.bu.edu connected on port
+                                6667.
+
+4.3.6 Trace message
+
+      Command: TRACE
+   Parameters: [<server>]
+
+   TRACE command is used to find the route to specific server.  Each
+   server that processes this message must tell the sender about it by
+   sending a reply indicating it is a pass-through link, forming a chain
+   of replies similar to that gained from using "traceroute".  After
+   sending this reply back, it must then send the TRACE message to the
+   next server until given server is reached.  If the <server> parameter
+   is omitted, it is recommended that TRACE command send a message to
+   the sender telling which servers the current server has direct
+   connection to.
+
+   If the destination given by "<server>" is an actual server, then the
+   destination server is required to report all servers and users which
+   are connected to it, although only operators are permitted to see
+   users present.  If the destination given by <server> is a nickname,
+   they only a reply for that nickname is given.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+
+   If the TRACE message is destined for another server, all intermediate
+   servers must return a RPL_TRACELINK reply to indicate that the TRACE
+   passed through it and where its going next.
+
+           RPL_TRACELINK
+   A TRACE reply may be composed of any number of the following numeric
+   replies.
+
+           RPL_TRACECONNECTING             RPL_TRACEHANDSHAKE
+           RPL_TRACEUNKNOWN                RPL_TRACEOPERATOR
+           RPL_TRACEUSER                   RPL_TRACESERVER
+           RPL_TRACESERVICE                RPL_TRACENEWTYPE
+           RPL_TRACECLASS
+
+   Examples:
+
+TRACE *.oulu.fi                 ; TRACE to a server matching *.oulu.fi
+
+
+
+
+Oikarinen & Reed                                               [Page 30]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+:WiZ TRACE AngelDust            ; TRACE issued by WiZ to nick AngelDust
+
+4.3.7 Admin command
+
+      Command: ADMIN
+   Parameters: [<server>]
+
+   The admin message is used to find the name of the administrator of
+   the given server, or current server if <server> parameter is omitted.
+   Each server must have the ability to forward ADMIN messages to other
+   servers.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_ADMINME                     RPL_ADMINLOC1
+           RPL_ADMINLOC2                   RPL_ADMINEMAIL
+
+   Examples:
+
+   ADMIN tolsun.oulu.fi            ; request an ADMIN reply from
+                                   tolsun.oulu.fi
+
+   :WiZ ADMIN *.edu                ; ADMIN request from WiZ for first
+                                   server found to match *.edu.
+
+4.3.8 Info command
+
+      Command: INFO
+   Parameters: [<server>]
+
+   The INFO command is required to return information which describes
+   the server: its version, when it was compiled, the patchlevel, when
+   it was started, and any other miscellaneous information which may be
+   considered to be relevant.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_INFO                        RPL_ENDOFINFO
+
+   Examples:
+
+   INFO csd.bu.edu                 ; request an INFO reply from
+   csd.bu.edu
+
+   :Avalon INFO *.fi               ; INFO request from Avalon for first
+                                   server found to match *.fi.
+
+
+
+Oikarinen & Reed                                               [Page 31]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   INFO Angel                      ; request info from the server that
+                                   Angel is connected to.
+
+4.4 Sending messages
+
+   The main purpose of the IRC protocol is to provide a base for clients
+   to communicate with each other.  PRIVMSG and NOTICE are the only
+   messages available which actually perform delivery of a text message
+   from one client to another - the rest just make it possible and try
+   to ensure it happens in a reliable and structured manner.
+
+4.4.1 Private messages
+
+      Command: PRIVMSG
+   Parameters: <receiver>{,<receiver>} <text to be sent>
+
+   PRIVMSG is used to send private messages between users.  <receiver>
+   is the nickname of the receiver of the message.  <receiver> can also
+   be a list of names or channels separated with commas.
+
+   The <receiver> parameter may also me a host mask  ($@mask)  or  server
+   mask  ($mask).   In  both cases the server will only send the PRIVMSG
+   to those who have a server or host matching the mask.  The mask  must
+   have at  least  1  (one)  "."  in it and no wildcards following the
+   last ".".  This requirement exists to prevent people sending messages
+   to  "$@*"  or "$*",  which  would  broadcast  to  all  users; from
+   experience, this is abused more than used responsibly and properly.
+   Wildcards are  the  '*' and  '?'   characters.   This  extension  to
+   the PRIVMSG command is only available to Operators.
+
+   Numeric Replies:
+
+           ERR_NORECIPIENT                 ERR_NOTEXTTOSEND
+           ERR_CANNOTSENDTOCHAN            ERR_NOTOPLEVEL
+           ERR_WILDTOPLEVEL                ERR_TOOMANYTARGETS
+           ERR_NOSUCHNICK
+           RPL_AWAY
+
+   Examples:
+
+:Angel PRIVMSG Wiz :Hello are you receiving this message ?
+                                ; Message from Angel to Wiz.
+
+PRIVMSG Angel :yes I'm receiving it !receiving it !'u>(768u+1n) .br ;
+                                Message to Angel.
+
+PRIVMSG jto@tolsun.oulu.fi :Hello !
+                                ; Message to a client on server
+
+
+
+Oikarinen & Reed                                               [Page 32]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                tolsun.oulu.fi with username of "jto".
+
+PRIVMSG $*.fi :Server tolsun.oulu.fi rebooting.
+                                ; Message to everyone on a server which
+                                has a name matching *.fi.
+
+PRIVMSG $@*.edu :NSFNet is undergoing work, expect interruptions
+                                ; Message to all users who come from a
+                                host which has a name matching *.edu.
+
+4.4.2 Notice
+
+      Command: NOTICE
+   Parameters: <nickname> <text>
+
+   The NOTICE message is used similarly to PRIVMSG.  The difference
+   between NOTICE and PRIVMSG is that automatic replies must never be
+   sent in response to a NOTICE message.  This rule applies to servers
+   too - they must not send any error reply back to the client on
+   receipt of a notice.  The object of this rule is to avoid loops
+   between a client automatically sending something in response to
+   something it received.  This is typically used by automatons (clients
+   with either an AI or other interactive program controlling their
+   actions) which are always seen to be replying lest they end up in a
+   loop with another automaton.
+
+   See PRIVMSG for more details on replies and examples.
+
+4.5 User based queries
+
+   User queries are a group of commands which are primarily concerned
+   with finding details on a particular user or group users.  When using
+   wildcards with any of these commands, if they match, they will only
+   return information on users who are 'visible' to you.  The visibility
+   of a user is determined as a combination of the user's mode and the
+   common set of channels you are both on.
+
+4.5.1 Who query
+
+      Command: WHO
+   Parameters: [<name> [<o>]]
+
+   The WHO message is used by a client to generate a query which returns
+   a list of information which 'matches' the <name> parameter given by
+   the client.  In the absence of the <name> parameter, all visible
+   (users who aren't invisible (user mode +i) and who don't have a
+   common channel with the requesting client) are listed.  The same
+   result can be achieved by using a <name> of "0" or any wildcard which
+
+
+
+Oikarinen & Reed                                               [Page 33]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   will end up matching every entry possible.
+
+   The <name> passed to WHO is matched against users' host, server, real
+   name and nickname if the channel <name> cannot be found.
+
+   If the "o" parameter is passed only operators are returned according
+   to the name mask supplied.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER
+           RPL_WHOREPLY                    RPL_ENDOFWHO
+
+   Examples:
+
+   WHO *.fi                        ; List all users who match against
+                                   "*.fi".
+
+   WHO jto* o                      ; List all users with a match against
+                                   "jto*" if they are an operator.
+
+4.5.2 Whois query
+
+      Command: WHOIS
+   Parameters: [<server>] <nickmask>[,<nickmask>[,...]]
+
+   This message is used to query information about particular user.  The
+   server will answer this message with several numeric messages
+   indicating different statuses of each user which matches the nickmask
+   (if you are entitled to see them).  If no wildcard is present in the
+   <nickmask>, any information about that nick which you are allowed to
+   see is presented.  A comma (',') separated list of nicknames may be
+   given.
+
+   The latter version sends the query to a specific server.  It is
+   useful if you want to know how long the user in question has been
+   idle as only local server (ie. the server the user is directly
+   connected to) knows that information, while everything else is
+   globally known.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_NONICKNAMEGIVEN
+           RPL_WHOISUSER                   RPL_WHOISCHANNELS
+           RPL_WHOISCHANNELS               RPL_WHOISSERVER
+           RPL_AWAY                        RPL_WHOISOPERATOR
+           RPL_WHOISIDLE                   ERR_NOSUCHNICK
+           RPL_ENDOFWHOIS
+
+
+
+Oikarinen & Reed                                               [Page 34]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   Examples:
+
+   WHOIS wiz                       ; return available user information
+                                   about nick WiZ
+
+   WHOIS eff.org trillian          ; ask server eff.org for user
+                                   information about trillian
+
+4.5.3 Whowas
+
+      Command: WHOWAS
+   Parameters: <nickname> [<count> [<server>]]
+
+   Whowas asks for information about a nickname which no longer exists.
+   This may either be due to a nickname change or the user leaving IRC.
+   In response to this query, the server searches through its nickname
+   history, looking for any nicks which are lexically the same (no wild
+   card matching here).  The history is searched backward, returning the
+   most recent entry first.  If there are multiple entries, up to
+   <count> replies will be returned (or all of them if no <count>
+   parameter is given).  If a non-positive number is passed as being
+   <count>, then a full search is done.
+
+   Numeric Replies:
+
+           ERR_NONICKNAMEGIVEN             ERR_WASNOSUCHNICK
+           RPL_WHOWASUSER                  RPL_WHOISSERVER
+           RPL_ENDOFWHOWAS
+
+   Examples:
+
+   WHOWAS Wiz                      ; return all information in the nick
+                                   history about nick "WiZ";
+
+   WHOWAS Mermaid 9                ; return at most, the 9 most recent
+                                   entries in the nick history for
+                                   "Mermaid";
+
+   WHOWAS Trillian 1 *.edu         ; return the most recent history for
+                                   "Trillian" from the first server found
+                                   to match "*.edu".
+
+4.6 Miscellaneous messages
+
+   Messages in this category do not fit into any of the above categories
+   but are nonetheless still a part of and required by the protocol.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 35]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+4.6.1 Kill message
+
+      Command: KILL
+   Parameters: <nickname> <comment>
+
+   The KILL message is used to cause a client-server connection to be
+   closed by the server which has the actual connection.  KILL is used
+   by servers when they encounter a duplicate entry in the list of valid
+   nicknames and is used to remove both entries.  It is also available
+   to operators.
+
+   Clients which have automatic reconnect algorithms effectively make
+   this command useless since the disconnection is only brief.  It does
+   however break the flow of data and can be used to stop large amounts
+   of being abused, any user may elect to receive KILL messages
+   generated for others to keep an 'eye' on would be trouble spots.
+
+   In an arena where nicknames are required to be globally unique at all
+   times, KILL messages are sent whenever 'duplicates' are detected
+   (that is an attempt to register two users with the same nickname) in
+   the hope that both of them will disappear and only 1 reappear.
+
+   The comment given must reflect the actual reason for the KILL.  For
+   server-generated KILLs it usually is made up of details concerning
+   the origins of the two conflicting nicknames.  For users it is left
+   up to them to provide an adequate reason to satisfy others who see
+   it.  To prevent/discourage fake KILLs from being generated to hide
+   the identify of the KILLer, the comment also shows a 'kill-path'
+   which is updated by each server it passes through, each prepending
+   its name to the path.
+
+   Numeric Replies:
+
+           ERR_NOPRIVILEGES                ERR_NEEDMOREPARAMS
+           ERR_NOSUCHNICK                  ERR_CANTKILLSERVER
+
+
+   KILL David (csd.bu.edu <- tolsun.oulu.fi)
+                                   ; Nickname collision between csd.bu.edu
+                                   and tolson.oulu.fi
+
+
+   NOTE:
+   It is recommended that only Operators be allowed to kill other users
+   with KILL message.  In an ideal world not even operators would need
+   to do this and it would be left to servers to deal with.
+
+
+
+
+
+Oikarinen & Reed                                               [Page 36]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+4.6.2 Ping message
+
+      Command: PING
+   Parameters: <server1> [<server2>]
+
+   The PING message is used to test the presence of an active client at
+   the other end of the connection.  A PING message is sent at regular
+   intervals if no other activity detected coming from a connection.  If
+   a connection fails to respond to a PING command within a set amount
+   of time, that connection is closed.
+
+   Any client which receives a PING message must respond to <server1>
+   (server which sent the PING message out) as quickly as possible with
+   an appropriate PONG message to indicate it is still there and alive.
+   Servers should not respond to PING commands but rely on PINGs from
+   the other end of the connection to indicate the connection is alive.
+   If the <server2> parameter is specified, the PING message gets
+   forwarded there.
+
+   Numeric Replies:
+
+           ERR_NOORIGIN                    ERR_NOSUCHSERVER
+
+   Examples:
+
+   PING tolsun.oulu.fi             ; server sending a PING message to
+                                   another server to indicate it is still
+                                   alive.
+
+   PING WiZ                        ; PING message being sent to nick WiZ
+
+4.6.3 Pong message
+
+      Command: PONG
+   Parameters: <daemon> [<daemon2>]
+
+   PONG message is a reply to ping message.  If parameter <daemon2> is
+   given this message must be forwarded to given daemon.  The <daemon>
+   parameter is the name of the daemon who has responded to PING message
+   and generated this message.
+
+   Numeric Replies:
+
+           ERR_NOORIGIN                    ERR_NOSUCHSERVER
+
+   Examples:
+
+   PONG csd.bu.edu tolsun.oulu.fi  ; PONG message from csd.bu.edu to
+
+
+
+Oikarinen & Reed                                               [Page 37]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                                   tolsun.oulu.fi
+
+4.6.4 Error
+
+      Command: ERROR
+   Parameters: <error message>
+
+   The ERROR command is for use by servers when reporting a serious or
+   fatal error to its operators.  It may also be sent from one server to
+   another but must not be accepted from any normal unknown clients.
+
+   An ERROR message is for use for reporting errors which occur with a
+   server-to-server link only.  An ERROR message is sent to the server
+   at the other end (which sends it to all of its connected operators)
+   and to all operators currently connected.  It is not to be passed
+   onto any other servers by a server if it is received from a server.
+
+   When a server sends a received ERROR message to its operators, the
+   message should be encapsulated inside a NOTICE message, indicating
+   that the client was not responsible for the error.
+
+   Numerics:
+
+           None.
+
+   Examples:
+
+   ERROR :Server *.fi already exists; ERROR message to the other server
+                                   which caused this error.
+
+   NOTICE WiZ :ERROR from csd.bu.edu -- Server *.fi already exists
+                                   ; Same ERROR message as above but sent
+                                   to user WiZ on the other server.
+
+5. OPTIONALS
+
+   This section describes OPTIONAL messages.  They are not required in a
+   working server implementation of the protocol described herein.  In
+   the absence of the option, an error reply message must be generated
+   or an unknown command error.  If the message is destined for another
+   server to answer then it must be passed on (elementary parsing
+   required) The allocated numerics for this are listed with the
+   messages below.
+
+5.1 Away
+
+      Command: AWAY
+   Parameters: [message]
+
+
+
+Oikarinen & Reed                                               [Page 38]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   With the AWAY message, clients can set an automatic reply string for
+   any PRIVMSG commands directed at them (not to a channel they are on).
+   The automatic reply is sent by the server to client sending the
+   PRIVMSG command.  The only replying server is the one to which the
+   sending client is connected to.
+
+   The AWAY message is used either with one parameter (to set an AWAY
+   message) or with no parameters (to remove the AWAY message).
+
+   Numeric Replies:
+
+           RPL_UNAWAY                      RPL_NOWAWAY
+
+   Examples:
+
+   AWAY :Gone to lunch.  Back in 5 ; set away message to "Gone to lunch.
+                                   Back in 5".
+
+   :WiZ AWAY                       ; unmark WiZ as being away.
+
+
+5.2 Rehash message
+
+      Command: REHASH
+   Parameters: None
+
+   The rehash message can be used by the operator to force the server to
+   re-read and process its configuration file.
+
+   Numeric Replies:
+
+        RPL_REHASHING                   ERR_NOPRIVILEGES
+
+Examples:
+
+REHASH                          ; message from client with operator
+                                status to server asking it to reread its
+                                configuration file.
+
+5.3 Restart message
+
+      Command: RESTART
+   Parameters: None
+
+   The restart message can only be used by an operator to force a server
+   restart itself.  This message is optional since it may be viewed as a
+   risk to allow arbitrary people to connect to a server as an operator
+   and execute this command, causing (at least) a disruption to service.
+
+
+
+Oikarinen & Reed                                               [Page 39]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The RESTART command must always be fully processed by the server to
+   which the sending client is connected and not be passed onto other
+   connected servers.
+
+   Numeric Replies:
+
+           ERR_NOPRIVILEGES
+
+   Examples:
+
+   RESTART                         ; no parameters required.
+
+                                   running.
+
+5.5 Users
+
+      Command: USERS
+   Parameters: [<server>]
+
+
+
+Oikarinen & Reed                                               [Page 40]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   The USERS command returns a list of users logged into the server in a
+   similar  format  to  who(1),  rusers(1)  and finger(1).  Some people
+   may disable this command on their server for security related
+   reasons.   If disabled, the correct numeric must be returned to
+   indicate this.
+
+   Numeric Replies:
+
+           ERR_NOSUCHSERVER                ERR_FILEERROR
+           RPL_USERSSTART                  RPL_USERS
+           RPL_NOUSERS                     RPL_ENDOFUSERS
+           ERR_USERSDISABLED
+
+   Disabled Reply:
+
+           ERR_USERSDISABLED
+
+   Examples:
+
+USERS eff.org                   ; request a list of users logged in on
+                                server eff.org
+
+:John USERS tolsun.oulu.fi      ; request from John for a list of users
+                                logged in on server tolsun.oulu.fi
+
+5.6 Operwall message
+
+      Command: WALLOPS
+   Parameters: Text to be sent to all operators currently online
+
+   Sends  a  message  to  all   operators   currently   online.    After
+   implementing  WALLOPS  as  a user command it was found that it was
+   often and commonly abused as a means of sending a message to a lot
+   of  people (much  similar to WALL).  Due to this it is recommended
+   that the current implementation of  WALLOPS  be  used  as  an
+   example  by  allowing  and recognising only servers as the senders of
+   WALLOPS.
+
+   Numeric Replies:
+
+           ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   :csd.bu.edu WALLOPS :Connect '*.uiuc.edu 6667' from Joshua; WALLOPS
+                                   message from csd.bu.edu announcing a
+                                   CONNECT message it received and acted
+                                   upon from Joshua.
+
+
+
+Oikarinen & Reed                                               [Page 41]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+5.7 Userhost message
+
+      Command: USERHOST
+   Parameters: <nickname>{<space><nickname>}
+
+   The USERHOST command takes a list of up to 5 nicknames, each
+   separated by a space character and returns a list of information
+   about each nickname that it found.  The returned list has each reply
+   separated by a space.
+
+   Numeric Replies:
+
+           RPL_USERHOST                    ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   USERHOST Wiz Michael Marty p    ;USERHOST request for information on
+                                   nicks "Wiz", "Michael", "Marty" and "p"
+
+5.7.1 Userip message
+
+      Command: USERIP
+   Parameters: <nickname>{<space><nickname>}
+
+   The USERHOST command takes a list of up to 5 nicknames, each
+   separated by a space character and returns a list of information
+   about each nickname that it found.  The returned list has each reply
+   separated by a space.
+
+   Numeric Replies:
+
+           RPL_USERIP                    ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   USERIP Wiz Michael Marty p    ;USERIP request for information on
+                                   nicks "Wiz", "Michael", "Marty" and "p"
+
+5.8 Ison message
+
+      Command: ISON
+   Parameters: <nickname>{<space><nickname>}
+
+   The ISON command was implemented to provide  a  quick  and  efficient
+   means  to get a response about whether a given nickname was currently
+   on IRC. ISON only takes one (1) parameter: a space-separated list of
+   nicks.  For  each  nickname in the list that is present, the server
+   adds that to its reply string.  Thus the reply string may return
+   empty (none  of  the given  nicks are present), an exact copy of the
+   parameter string (all of them present) or as any other subset of the
+   set of nicks  given  in  the parameter.  The only limit on the number
+   of nicks that may be checked is that the combined length must not be
+   too large as to cause the server to chop it off so it fits in 512
+   characters.
+
+   ISON is only be processed by the server local to the client sending
+   the command and thus not passed onto other servers for further
+   processing.
+
+   Numeric Replies:
+
+           RPL_ISON                ERR_NEEDMOREPARAMS
+
+   Examples:
+
+   ISON phone trillian WiZ jarlek Avalon Angel Monstah
+                                   ; Sample ISON request for 7 nicks.
+
+
+
+Oikarinen & Reed                                               [Page 42]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+6. REPLIES
+
+   The following is a list of numeric replies which are generated in
+   response to the commands given above.  Each numeric is given with its
+   number, name and reply string.
+
+6.1 Error Replies.
+
+        401     ERR_NOSUCHNICK
+                        "<nickname> :No such nick/channel"
+
+                - Used to indicate the nickname parameter supplied to a
+                  command is currently unused.
+
+        402     ERR_NOSUCHSERVER
+                        "<server name> :No such server"
+
+                - Used to indicate the server name given currently
+                  doesn't exist.
+
+        403     ERR_NOSUCHCHANNEL
+                        "<channel name> :No such channel"
+
+                - Used to indicate the given channel name is invalid.
+
+        404     ERR_CANNOTSENDTOCHAN
+                        "<channel name> :Cannot send to channel"
+
+                - Sent to a user who is either (a) not on a channel
+                  which is mode +n or (b) not a chanop (or mode +v) on
+                  a channel which has mode +m set and is trying to send
+                  a PRIVMSG message to that channel.
+
+        405     ERR_TOOMANYCHANNELS
+                        "<channel name> :You have joined too many \
+                         channels"
+                - Sent to a user when they have joined the maximum
+                  number of allowed channels and they try to join
+                  another channel.
+
+        406     ERR_WASNOSUCHNICK
+                        "<nickname> :There was no such nickname"
+
+                - Returned by WHOWAS to indicate there is no history
+                  information for that nickname.
+
+        407     ERR_TOOMANYTARGETS
+                        "<target> :Duplicate recipients. No message \
+
+
+
+Oikarinen & Reed                                               [Page 43]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                         delivered"
+
+                - Returned to a client which is attempting to send a
+                  PRIVMSG/NOTICE using the user@host destination format
+                  and for a user@host which has several occurrences.
+
+        409     ERR_NOORIGIN
+                        ":No origin specified"
+
+                - PING or PONG message missing the originator parameter
+                  which is required since these commands must work
+                  without valid prefixes.
+
+        411     ERR_NORECIPIENT
+                        ":No recipient given (<command>)"
+        412     ERR_NOTEXTTOSEND
+                        ":No text to send"
+        413     ERR_NOTOPLEVEL
+                        "<mask> :No toplevel domain specified"
+        414     ERR_WILDTOPLEVEL
+                        "<mask> :Wildcard in toplevel domain"
+
+                - 412 - 414 are returned by PRIVMSG to indicate that
+                  the message wasn't delivered for some reason.
+                  ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
+                  are returned when an invalid use of
+                  "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
+
+        421     ERR_UNKNOWNCOMMAND
+                        "<command> :Unknown command"
+
+                - Returned to a registered client to indicate that the
+                  command sent is unknown by the server.
+
+        422     ERR_NOMOTD
+                        ":MOTD File is missing"
+
+                - Server's MOTD file could not be opened by the server.
+
+        423     ERR_NOADMININFO
+                        "<server> :No administrative info available"
+
+                - Returned by a server in response to an ADMIN message
+                  when there is an error in finding the appropriate
+                  information.
+
+        424     ERR_FILEERROR
+                ":File error doing <file op> on <file>"
+
+
+
+Oikarinen & Reed                                               [Page 44]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                - Generic error message used to report a failed file
+                  operation during the processing of a message.
+
+        431     ERR_NONICKNAMEGIVEN
+                        ":No nickname given"
+
+                - Returned when a nickname parameter expected for a
+                  command and isn't found.
+
+        432     ERR_ERRONEUSNICKNAME
+                        "<nick> :Erroneus nickname"
+
+                - Returned after receiving a NICK message which contains
+                  characters which do not fall in the defined set.  See
+                  section x.x.x for details on valid nicknames.
+
+        433     ERR_NICKNAMEINUSE
+                        "<nick> :Nickname is already in use"
+
+                - Returned when a NICK message is processed that results
+                  in an attempt to change to a currently existing
+                  nickname.
+
+        436     ERR_NICKCOLLISION
+                        "<nick> :Nickname collision KILL"
+
+                - Returned by a server to a client when it detects a
+                  nickname collision (registered of a NICK that
+                  already exists by another server).
+
+        441     ERR_USERNOTINCHANNEL
+                        "<nick> <channel> :They aren't on that channel"
+
+                - Returned by the server to indicate that the target
+                  user of the command is not on the given channel.
+
+        442     ERR_NOTONCHANNEL
+                        "<channel> :You're not on that channel"
+
+                - Returned by the server whenever a client tries to
+                  perform a channel effecting command for which the
+                  client isn't a member.
+
+        443     ERR_USERONCHANNEL
+                        "<user> <channel> :is already on channel"
+
+                - Returned when a client tries to invite a user to a
+                  channel they are already on.
+
+
+
+Oikarinen & Reed                                               [Page 45]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        444     ERR_NOLOGIN
+                        "<user> :User not logged in"
+
+                - Returned by the summon after a SUMMON command for a
+                  user was unable to be performed since they were not
+                  logged in.
+
+        445     ERR_SUMMONDISABLED
+                        ":SUMMON has been disabled"
+
+                - Returned as a response to the SUMMON command.  Must be
+                  returned by any server which does not implement it.
+
+        446     ERR_USERSDISABLED
+                        ":USERS has been disabled"
+
+                - Returned as a response to the USERS command.  Must be
+                  returned by any server which does not implement it.
+
+        451     ERR_NOTREGISTERED
+                        ":You have not registered"
+
+                - Returned by the server to indicate that the client
+                  must be registered before the server will allow it
+                  to be parsed in detail.
+
+        461     ERR_NEEDMOREPARAMS
+                        "<command> :Not enough parameters"
+
+                - Returned by the server by numerous commands to
+                  indicate to the client that it didn't supply enough
+                  parameters.
+
+        462     ERR_ALREADYREGISTRED
+                        ":You may not reregister"
+
+                - Returned by the server to any link which tries to
+                  change part of the registered details (such as
+                  password or user details from second USER message).
+
+
+        463     ERR_NOPERMFORHOST
+                        ":Your host isn't among the privileged"
+
+                - Returned to a client which attempts to register with
+                  a server which does not been setup to allow
+                  connections from the host the attempted connection
+                  is tried.
+
+
+
+Oikarinen & Reed                                               [Page 46]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        464     ERR_PASSWDMISMATCH
+                        ":Password incorrect"
+
+                - Returned to indicate a failed attempt at registering
+                  a connection for which a password was required and
+                  was either not given or incorrect.
+
+        465     ERR_YOUREBANNEDCREEP
+                        ":You are banned from this server"
+
+                - Returned after an attempt to connect and register
+                  yourself with a server which has been setup to
+                  explicitly deny connections to you.
+
+        467     ERR_KEYSET
+                        "<channel> :Channel key already set"
+        471     ERR_CHANNELISFULL
+                        "<channel> :Cannot join channel (+l)"
+        472     ERR_UNKNOWNMODE
+                        "<char> :is unknown mode char to me"
+        473     ERR_INVITEONLYCHAN
+                        "<channel> :Cannot join channel (+i)"
+        474     ERR_BANNEDFROMCHAN
+                        "<channel> :Cannot join channel (+b)"
+        475     ERR_BADCHANNELKEY
+                        "<channel> :Cannot join channel (+k)"
+        481     ERR_NOPRIVILEGES
+                        ":Permission Denied- You're not an IRC operator"
+
+                - Any command requiring operator privileges to operate
+                  must return this error to indicate the attempt was
+                  unsuccessful.
+
+        482     ERR_CHANOPRIVSNEEDED
+                        "<channel> :You're not channel operator"
+
+                - Any command requiring 'chanop' privileges (such as
+                  MODE messages) must return this error if the client
+                  making the attempt is not a chanop on the specified
+                  channel.
+
+        483     ERR_CANTKILLSERVER
+                        ":You cant kill a server!"
+
+                - Any attempts to use the KILL command on a server
+                  are to be refused and this error returned directly
+                  to the client.
+
+
+
+
+Oikarinen & Reed                                               [Page 47]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        491     ERR_NOOPERHOST
+                        ":No O-lines for your host"
+
+                - If a client sends an OPER message and the server has
+                  not been configured to allow connections from the
+                  client's host as an operator, this error must be
+                  returned.
+
+        501     ERR_UMODEUNKNOWNFLAG
+                        ":Unknown MODE flag"
+
+                - Returned by the server to indicate that a MODE
+                  message was sent with a nickname parameter and that
+                  the a mode flag sent was not recognized.
+
+        502     ERR_USERSDONTMATCH
+                        ":Cant change mode for other users"
+
+                - Error sent to any user trying to view or change the
+                  user mode for a user other than themselves.
+
+6.2 Command responses.
+
+        300     RPL_NONE
+                        Dummy reply number. Not used.
+
+        302     RPL_USERHOST
+                        ":[<reply>{<space><reply>}]"
+
+                - Reply format used by USERHOST to list replies to
+                  the query list.  The reply string is composed as
+                  follows:
+
+                  <reply> ::= <nick>['*'] '=' <'+'|'-'><hostname>
+
+                  The '*' indicates whether the client has registered
+                  as an Operator.  The '-' or '+' characters represent
+                  whether the client has set an AWAY message or not
+                  respectively.
+
+        303     RPL_ISON
+                        ":[<nick> {<space><nick>}]"
+
+                - Reply format used by ISON to list replies to the
+                  query list.
+
+        301     RPL_AWAY
+                        "<nick> :<away message>"
+
+
+
+Oikarinen & Reed                                               [Page 48]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+        305     RPL_UNAWAY
+                        ":You are no longer marked as being away"
+        306     RPL_NOWAWAY
+                        ":You have been marked as being away"
+
+                - These replies are used with the AWAY command (if
+                  allowed).  RPL_AWAY is sent to any client sending a
+                  PRIVMSG to a client which is away.  RPL_AWAY is only
+                  sent by the server to which the client is connected.
+                  Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
+                  client removes and sets an AWAY message.
+
+        311     RPL_WHOISUSER
+                        "<nick> <user> <host> * :<real name>"
+        312     RPL_WHOISSERVER
+                        "<nick> <server> :<server info>"
+        313     RPL_WHOISOPERATOR
+                        "<nick> :is an IRC operator"
+        317     RPL_WHOISIDLE
+                        "<nick> <integer> :seconds idle"
+        318     RPL_ENDOFWHOIS
+                        "<nick> :End of /WHOIS list"
+        319     RPL_WHOISCHANNELS
+                        "<nick> :{[@|+]<channel><space>}"
+
+                - Replies 311 - 313, 317 - 319 are all replies
+                  generated in response to a WHOIS message.  Given that
+                  there are enough parameters present, the answering
+                  server must either formulate a reply out of the above
+                  numerics (if the query nick is found) or return an
+                  error reply.  The '*' in RPL_WHOISUSER is there as
+                  the literal character and not as a wild card.  For
+                  each reply set, only RPL_WHOISCHANNELS may appear
+                  more than once (for long lists of channel names).
+                  The '@' and '+' characters next to the channel name
+                  indicate whether a client is a channel operator or
+                  has been granted permission to speak on a moderated
+                  channel.  The RPL_ENDOFWHOIS reply is used to mark
+                  the end of processing a WHOIS message.
+
+        314     RPL_WHOWASUSER
+                        "<nick> <user> <host> * :<real name>"
+        369     RPL_ENDOFWHOWAS
+                        "<nick> :End of WHOWAS"
+
+                - When replying to a WHOWAS message, a server must use
+                  the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
+                  ERR_WASNOSUCHNICK for each nickname in the presented
+
+
+
+Oikarinen & Reed                                               [Page 49]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  list.  At the end of all reply batches, there must
+                  be RPL_ENDOFWHOWAS (even if there was only one reply
+                  and it was an error).
+
+        321     RPL_LISTSTART
+                        "Channel :Users  Name"
+        322     RPL_LIST
+                        "<channel> <# visible> :<topic>"
+        323     RPL_LISTEND
+                        ":End of /LIST"
+
+                - Replies RPL_LISTSTART, RPL_LIST, RPL_LISTEND mark
+                  the start, actual replies with data and end of the
+                  server's response to a LIST command.  If there are
+                  no channels available to return, only the start
+                  and end reply must be sent.
+
+        324     RPL_CHANNELMODEIS
+                        "<channel> <mode> <mode params>"
+
+        331     RPL_NOTOPIC
+                        "<channel> :No topic is set"
+        332     RPL_TOPIC
+                        "<channel> :<topic>"
+
+                - When sending a TOPIC message to determine the
+                  channel topic, one of two replies is sent.  If
+                  the topic is set, RPL_TOPIC is sent back else
+                  RPL_NOTOPIC.
+
+        341     RPL_INVITING
+                        "<channel> <nick>"
+
+                - Returned by the server to indicate that the
+                  attempted INVITE message was successful and is
+                  being passed onto the end client.
+
+        342     RPL_SUMMONING
+                        "<user> :Summoning user to IRC"
+
+                - Returned by a server answering a SUMMON message to
+                  indicate that it is summoning that user.
+
+        351     RPL_VERSION
+                        "<version>.<debuglevel> <server> :<comments>"
+
+                - Reply by the server showing its version details.
+                  The <version> is the version of the software being
+
+
+
+Oikarinen & Reed                                               [Page 50]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  used (including any patchlevel revisions) and the
+                  <debuglevel> is used to indicate if the server is
+                  running in "debug mode".
+
+                  The "comments" field may contain any comments about
+                  the version or further version details.
+
+        352     RPL_WHOREPLY
+                        "<channel> <user> <host> <server> <nick> \
+                         <H|G>[*][@|+] :<hopcount> <real name>"
+        315     RPL_ENDOFWHO
+                        "<name> :End of /WHO list"
+
+                - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
+                  to answer a WHO message.  The RPL_WHOREPLY is only
+                  sent if there is an appropriate match to the WHO
+                  query.  If there is a list of parameters supplied
+                  with a WHO message, a RPL_ENDOFWHO must be sent
+                  after processing each list item with <name> being
+                  the item.
+
+        353     RPL_NAMREPLY
+                        "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"
+        366     RPL_ENDOFNAMES
+                        "<channel> :End of /NAMES list"
+
+                - To reply to a NAMES message, a reply pair consisting
+                  of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
+                  server back to the client.  If there is no channel
+                  found as in the query, then only RPL_ENDOFNAMES is
+                  returned.  The exception to this is when a NAMES
+                  message is sent with no parameters and all visible
+                  channels and contents are sent back in a series of
+                  RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
+                  the end.
+
+        364     RPL_LINKS
+                        "<mask> <server> :<hopcount> <server info>"
+        365     RPL_ENDOFLINKS
+                        "<mask> :End of /LINKS list"
+
+                - In replying to the LINKS message, a server must send
+                  replies back using the RPL_LINKS numeric and mark the
+                  end of the list using an RPL_ENDOFLINKS reply.
+
+        367     RPL_BANLIST
+                        "<channel> <banid>"
+        368     RPL_ENDOFBANLIST
+
+
+
+Oikarinen & Reed                                               [Page 51]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        "<channel> :End of channel ban list"
+
+                - When listing the active 'bans' for a given channel,
+                  a server is required to send the list back using the
+                  RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate
+                  RPL_BANLIST is sent for each active banid.  After the
+                  banids have been listed (or if none present) a
+                  RPL_ENDOFBANLIST must be sent.
+
+        371     RPL_INFO
+                        ":<string>"
+        374     RPL_ENDOFINFO
+                        ":End of /INFO list"
+
+                - A server responding to an INFO message is required to
+                  send all its 'info' in a series of RPL_INFO messages
+                  with a RPL_ENDOFINFO reply to indicate the end of the
+                  replies.
+
+        375     RPL_MOTDSTART
+                        ":- <server> Message of the day - "
+        372     RPL_MOTD
+                        ":- <text>"
+        376     RPL_ENDOFMOTD
+                        ":End of /MOTD command"
+
+                - When responding to the MOTD message and the MOTD file
+                  is found, the file is displayed line by line, with
+                  each line no longer than 80 characters, using
+                  RPL_MOTD format replies.  These should be surrounded
+                  by a RPL_MOTDSTART (before the RPL_MOTDs) and an
+                  RPL_ENDOFMOTD (after).
+
+        381     RPL_YOUREOPER
+                        ":You are now an IRC operator"
+
+                - RPL_YOUREOPER is sent back to a client which has
+                  just successfully issued an OPER message and gained
+                  operator status.
+
+        382     RPL_REHASHING
+                        "<config file> :Rehashing"
+
+                - If the REHASH option is used and an operator sends
+                  a REHASH message, an RPL_REHASHING is sent back to
+                  the operator.
+
+        391     RPL_TIME
+
+
+
+Oikarinen & Reed                                               [Page 52]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        "<server> :<string showing server's local time>"
+
+                - When replying to the TIME message, a server must send
+                  the reply using the RPL_TIME format above.  The string
+                  showing the time need only contain the correct day and
+                  time there.  There is no further requirement for the
+                  time string.
+
+        392     RPL_USERSSTART
+                        ":UserID   Terminal  Host"
+        393     RPL_USERS
+                        ":%-8s %-9s %-8s"
+        394     RPL_ENDOFUSERS
+                        ":End of users"
+        395     RPL_NOUSERS
+                        ":Nobody logged in"
+
+                - If the USERS message is handled by a server, the
+                  replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
+                  RPL_NOUSERS are used.  RPL_USERSSTART must be sent
+                  first, following by either a sequence of RPL_USERS
+                  or a single RPL_NOUSER.  Following this is
+                  RPL_ENDOFUSERS.
+
+        200     RPL_TRACELINK
+                        "Link <version & debug level> <destination> \
+                         <next server>"
+        201     RPL_TRACECONNECTING
+                        "Try. <class> <server>"
+        202     RPL_TRACEHANDSHAKE
+                        "H.S. <class> <server>"
+        203     RPL_TRACEUNKNOWN
+                        "???? <class> [<client IP address in dot form>]"
+        204     RPL_TRACEOPERATOR
+                        "Oper <class> <nick>"
+        205     RPL_TRACEUSER
+                        "User <class> <nick>"
+        206     RPL_TRACESERVER
+                        "Serv <class> <int>S <int>C <server> \
+                         <nick!user|*!*>@<host|server>"
+        208     RPL_TRACENEWTYPE
+                        "<newtype> 0 <client name>"
+        261     RPL_TRACELOG
+                        "File <logfile> <debug level>"
+
+                - The RPL_TRACE* are all returned by the server in
+                  response to the TRACE message.  How many are
+                  returned is dependent on the the TRACE message and
+
+
+
+Oikarinen & Reed                                               [Page 53]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                  whether it was sent by an operator or not.  There
+                  is no predefined order for which occurs first.
+                  Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
+                  RPL_TRACEHANDSHAKE are all used for connections
+                  which have not been fully established and are either
+                  unknown, still attempting to connect or in the
+                  process of completing the 'server handshake'.
+                  RPL_TRACELINK is sent by any server which handles
+                  a TRACE message and has to pass it on to another
+                  server.  The list of RPL_TRACELINKs sent in
+                  response to a TRACE command traversing the IRC
+                  network should reflect the actual connectivity of
+                  the servers themselves along that path.
+                  RPL_TRACENEWTYPE is to be used for any connection
+                  which does not fit in the other categories but is
+                  being displayed anyway.
+
+        211     RPL_STATSLINKINFO
+                        "<linkname> <sendq> <sent messages> \
+                         <sent bytes> <received messages> \
+                         <received bytes> <time open>"
+        212     RPL_STATSCOMMANDS
+                        "<command> <count>"
+        213     RPL_STATSCLINE
+                        "C <host> * <name> <port> <class>"
+        214     RPL_STATSNLINE
+                        "N <host> * <name> <port> <class>"
+        215     RPL_STATSILINE
+                        "I <host> * <host> <port> <class>"
+        216     RPL_STATSKLINE
+                        "K <host> * <username> <port> <class>"
+        218     RPL_STATSYLINE
+                        "Y <class> <ping frequency> <connect \
+                         frequency> <max sendq>"
+        219     RPL_ENDOFSTATS
+                        "<stats letter> :End of /STATS report"
+        241     RPL_STATSLLINE
+                        "L <hostmask> * <servername> <maxdepth>"
+        242     RPL_STATSUPTIME
+                        ":Server Up %d days %d:%02d:%02d"
+        243     RPL_STATSOLINE
+                        "O <hostmask> * <name>"
+        244     RPL_STATSHLINE
+                        "H <hostmask> * <servername>"
+
+        221     RPL_UMODEIS
+                        "<user mode string>"
+
+
+
+
+Oikarinen & Reed                                               [Page 54]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+                        - To answer a query about a client's own mode,
+                          RPL_UMODEIS is sent back.
+
+        251     RPL_LUSERCLIENT
+                        ":There are <integer> users and <integer> \
+                         invisible on <integer> servers"
+        252     RPL_LUSEROP
+                        "<integer> :operator(s) online"
+        253     RPL_LUSERUNKNOWN
+                        "<integer> :unknown connection(s)"
+        254     RPL_LUSERCHANNELS
+                        "<integer> :channels formed"
+        255     RPL_LUSERME
+                        ":I have <integer> clients and <integer> \
+                          servers"
+
+                        - In processing an LUSERS message, the server
+                          sends a set of replies from RPL_LUSERCLIENT,
+                          RPL_LUSEROP, RPL_USERUNKNOWN,
+                          RPL_LUSERCHANNELS and RPL_LUSERME.  When
+                          replying, a server must send back
+                          RPL_LUSERCLIENT and RPL_LUSERME.  The other
+                          replies are only sent back if a non-zero count
+                          is found for them.
+
+        256     RPL_ADMINME
+                        "<server> :Administrative info"
+        257     RPL_ADMINLOC1
+                        ":<admin info>"
+        258     RPL_ADMINLOC2
+                        ":<admin info>"
+        259     RPL_ADMINEMAIL
+                        ":<admin info>"
+
+                        - When replying to an ADMIN message, a server
+                          is expected to use replies RLP_ADMINME
+                          through to RPL_ADMINEMAIL and provide a text
+                          message with each.  For RPL_ADMINLOC1 a
+                          description of what city, state and country
+                          the server is in is expected, followed by
+                          details of the university and department
+                          (RPL_ADMINLOC2) and finally the administrative
+                          contact for the server (an email address here
+                          is required) in RPL_ADMINEMAIL.
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 55]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+6.3 Reserved numerics.
+
+   These numerics are not described above since they fall into one of
+   the following categories:
+
+        1. no longer in use;
+
+        2. reserved for future planned use;
+
+        3. in current use but are part of a non-generic 'feature' of
+           the current IRC server.
+
+        209     RPL_TRACECLASS          217     RPL_STATSQLINE
+        231     RPL_SERVICEINFO         232     RPL_ENDOFSERVICES
+        233     RPL_SERVICE             234     RPL_SERVLIST
+        235     RPL_SERVLISTEND
+        316     RPL_WHOISCHANOP         361     RPL_KILLDONE
+        362     RPL_CLOSING             363     RPL_CLOSEEND
+        373     RPL_INFOSTART           384     RPL_MYPORTIS
+        466     ERR_YOUWILLBEBANNED     476     ERR_BADCHANMASK
+        492     ERR_NOSERVICEHOST
+
+7. Client and server authentication
+
+   Clients and servers are both subject to the same level of
+   authentication.  For both, an IP number to hostname lookup (and
+   reverse check on this) is performed for all connections made to the
+   server.  Both connections are then subject to a password check (if
+   there is a password set for that connection).  These checks are
+   possible on all connections although the password check is only
+   commonly used with servers.
+
+   An additional check that is becoming of more and more common is that
+   of the username responsible for making the connection.  Finding the
+   username of the other end of the connection typically involves
+   connecting to an authentication server such as IDENT as described in
+   RFC 1413.
+
+   Given that without passwords it is not easy to reliably determine who
+   is on the other end of a network connection, use of passwords is
+   strongly recommended on inter-server connections in addition to any
+   other measures such as using an ident server.
+
+8. Current implementations
+
+   The only current implementation of this protocol is the IRC server,
+   version 2.8. Earlier versions may implement some or all of the
+   commands described by this document with NOTICE messages replacing
+
+
+
+Oikarinen & Reed                                               [Page 56]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   many of the numeric replies.  Unfortunately, due to backward
+   compatibility requirements, the implementation of some parts of this
+   document varies with what is laid out.  On notable difference is:
+
+        * recognition that any LF or CR anywhere in a message marks the
+          end of that message (instead of requiring CR-LF);
+
+   The rest of this section deals with issues that are mostly of
+   importance to those who wish to implement a server but some parts
+   also apply directly to clients as well.
+
+8.1 Network protocol: TCP - why it is best used here.
+
+   IRC has been implemented on top of TCP since TCP supplies a reliable
+   network protocol which is well suited to this scale of conferencing.
+   The use of multicast IP is an alternative, but it is not widely
+   available or supported at the present time.
+
+8.1.1 Support of Unix sockets
+
+   Given that Unix domain sockets allow listen/connect operations, the
+   current implementation can be configured to listen and accept both
+   client and server connections on a Unix domain socket.  These are
+   recognized as sockets where the hostname starts with a '/'.
+
+   When providing any information about the connections on a Unix domain
+   socket, the server is required to supplant the actual hostname in
+   place of the pathname unless the actual socket name is being asked
+   for.
+
+8.2 Command Parsing
+
+   To provide useful 'non-buffered' network IO for clients and servers,
+   each connection is given its own private 'input buffer' in which the
+   results of the most recent read and parsing are kept.  A buffer size
+   of 512 bytes is used so as to hold 1 full message, although, this
+   will usually hold several commands.  The private buffer is parsed
+   after every read operation for valid messages.  When dealing with
+   multiple messages from one client in the buffer, care should be taken
+   in case one happens to cause the client to be 'removed'.
+
+8.3 Message delivery
+
+   It is common to find network links saturated or hosts to which you
+   are sending data unable to send data.  Although Unix typically
+   handles this through the TCP window and internal buffers, the server
+   often has large amounts of data to send (especially when a new
+   server-server link forms) and the small buffers provided in the
+
+
+
+Oikarinen & Reed                                               [Page 57]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   kernel are not enough for the outgoing queue.  To alleviate this
+   problem, a "send queue" is used as a FIFO queue for data to be sent.
+   A typical "send queue" may grow to 200 Kbytes on a large IRC network
+   with a slow network connection when a new server connects.
+
+   When polling its connections, a server will first read and parse all
+   incoming data, queuing any data to be sent out. When all available
+   input is processed, the queued data is sent. This reduces the number
+   of write() system calls and helps TCP make bigger packets.
+
+8.4 Connection 'Liveness'
+
+   To detect when a connection has died or become unresponsive, the
+   server must ping each of its connections that it doesn't get a
+   response from in a given amount of time.
+
+   If a connection doesn't respond in time, its connection is closed
+   using the appropriate procedures.  A connection is also dropped if
+   its sendq grows beyond the maximum allowed, because it is better to
+   close a slow connection than have a server process block.
+
+8.5 Establishing a server to client connection
+
+   Upon connecting to an IRC server, a client is sent the MOTD (if
+   present) as well as the current user/server count (as per the LUSER
+   command).  The server is also required to give an unambiguous message
+   to the client which states its name and version as well as any other
+   introductory messages which may be deemed appropriate.
+
+   After dealing with this, the server must then send out the new user's
+   nickname and other information as supplied by itself (USER command)
+   and as the server could discover (from DNS/authentication servers).
+   The server must send this information out with NICK first followed by
+   USER.
+
+8.6 Establishing a server-server connection.
+
+   The process of establishing of a server-to-server connection is
+   fraught with danger since there are many possible areas where
+   problems can occur - the least of which are race conditions.
+
+   After a server has received a connection following by a PASS/SERVER
+   pair which were recognised as being valid, the server should then
+   reply with its own PASS/SERVER information for that connection as
+   well as all of the other state information it knows about as
+   described below.
+
+   When the initiating server receives a PASS/SERVER pair, it too then
+
+
+
+Oikarinen & Reed                                               [Page 58]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   checks that the server responding is authenticated properly before
+   accepting the connection to be that server.
+
+8.6.1 Server exchange of state information when connecting
+
+   The order of state information being exchanged between servers is
+   essential.  The required order is as follows:
+
+        * all known other servers;
+
+        * all known user information;
+
+        * all known channel information.
+
+   Information regarding servers is sent via extra SERVER messages, user
+   information with NICK/USER/MODE/JOIN messages and channels with MODE
+   messages.
+
+   NOTE: channel topics are *NOT* exchanged here because the TOPIC
+   command overwrites any old topic information, so at best, the two
+   sides of the connection would exchange topics.
+
+   By passing the state information about servers first, any collisions
+   with servers that already exist occur before nickname collisions due
+   to a second server introducing a particular nickname.  Due to the IRC
+   network only being able to exist as an acyclic graph, it may be
+   possible that the network has already reconnected in another
+   location, the place where the collision occurs indicating where the
+   net needs to split.
+
+8.7 Terminating server-client connections
+
+   When a client connection closes, a QUIT message is generated on
+   behalf of the client by the server to which the client connected.  No
+   other message is to be generated or used.
+
+8.8 Terminating server-server connections
+
+   If a server-server connection is closed, either via a remotely
+   generated SQUIT or 'natural' causes, the rest of the connected IRC
+   network must have its information updated with by the server which
+   detected the closure.  The server then sends a list of SQUITs (one
+   for each server behind that connection) and a list of QUITs (again,
+   one for each client behind that connection).
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 59]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+8.9 Tracking nickname changes
+
+   All IRC servers are required to keep a history of recent nickname
+   changes.  This is required to allow the server to have a chance of
+   keeping in touch of things when nick-change race conditions occur
+   with commands which manipulate them.  Commands which must trace nick
+   changes are:
+
+        * KILL (the nick being killed)
+
+        * MODE (+/- o,v)
+
+        * KICK (the nick being kicked)
+
+   No other commands are to have nick changes checked for.
+
+   In the above cases, the server is required to first check for the
+   existence of the nickname, then check its history to see who that
+   nick currently belongs to (if anyone!).  This reduces the chances of
+   race conditions but they can still occur with the server ending up
+   affecting the wrong client.  When performing a change trace for an
+   above command it is recommended that a time range be given and
+   entries which are too old ignored.
+
+   For a reasonable history, a server should be able to keep previous
+   nickname for every client it knows about if they all decided to
+   change.  This size is limited by other factors (such as memory, etc).
+
+8.10 Flood control of clients
+
+   With a large network of interconnected IRC servers, it is quite easy
+   for any single client attached to the network to supply a continuous
+   stream of messages that result in not only flooding the network, but
+   also degrading the level of service provided to others.  Rather than
+   require every 'victim' to be provide their own protection, flood
+   protection was written into the server and is applied to all clients
+   except services.  The current algorithm is as follows:
+
+        * check to see if client's `message timer' is less than
+          current time (set to be equal if it is);
+
+        * read any data present from the client;
+
+        * while the timer is less than ten seconds ahead of the current
+          time, parse any present messages and penalize the client by
+          2 seconds for each message;
+
+   which in essence means that the client may send 1 message every 2
+
+
+
+Oikarinen & Reed                                               [Page 60]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   seconds without being adversely affected.
+
+8.11 Non-blocking lookups
+
+   In a real-time environment, it is essential that a server process do
+   as little waiting as possible so that all the clients are serviced
+   fairly.  Obviously this requires non-blocking IO on all network
+   read/write operations.  For normal server connections, this was not
+   difficult, but there are other support operations that may cause the
+   server to block (such as disk reads).  Where possible, such activity
+   should be performed with a short timeout.
+
+8.11.1 Hostname (DNS) lookups
+
+   Using the standard resolver libraries from Berkeley and others has
+   meant large delays in some cases where replies have timed out.  To
+   avoid this, a separate set of DNS routines were written which were
+   setup for non-blocking IO operations and then polled from within the
+   main server IO loop.
+
+8.11.2 Username (Ident) lookups
+
+   Although there are numerous ident libraries for use and inclusion
+   into other programs, these caused problems since they operated in a
+   synchronous manner and resulted in frequent delays.  Again the
+   solution was to write a set of routines which would cooperate with
+   the rest of the server and work using non-blocking IO.
+
+8.12 Configuration File
+
+   To provide a flexible way of setting up and running the server, it is
+   recommended that a configuration file be used which contains
+   instructions to the server on the following:
+
+        * which hosts to accept client connections from;
+
+        * which hosts to allow to connect as servers;
+
+        * which hosts to connect to (both actively and
+          passively);
+
+        * information about where the server is (university,
+          city/state, company are examples of this);
+
+        * who is responsible for the server and an email address
+          at which they can be contacted;
+
+        * hostnames and passwords for clients which wish to be given
+
+
+
+Oikarinen & Reed                                               [Page 61]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+          access to restricted operator commands.
+
+   In specifying hostnames, both domain names and use of the 'dot'
+   notation (127.0.0.1) should both be accepted.  It must be possible to
+   specify the password to be used/accepted for all outgoing and
+   incoming connections (although the only outgoing connections are
+   those to other servers).
+
+   The above list is the minimum requirement for any server which wishes
+   to make a connection with another server.  Other items which may be
+   of use are:
+
+        * specifying which servers other server may introduce;
+
+        * how deep a server branch is allowed to become;
+
+        * hours during which clients may connect.
+
+8.12.1 Allowing clients to connect
+
+   A server should use some sort of 'access control list' (either in the
+   configuration file or elsewhere) that is read at startup and used to
+   decide what hosts clients may use to connect to it.
+
+   Both 'deny' and 'allow' should be implemented to provide the required
+   flexibility for host access control.
+
+8.12.2 Operators
+
+   The granting of operator privileges to a disruptive person can have
+   dire consequences for the well-being of the IRC net in general due to
+   the powers given to them.  Thus, the acquisition of such powers
+   should not be very easy.  The current setup requires two 'passwords'
+   to be used although one of them is usually easy guessed.  Storage of
+   oper passwords in configuration files is preferable to hard coding
+   them in and should be stored in a crypted format (ie using crypt(3)
+   from Unix) to prevent easy theft.
+
+8.12.3 Allowing servers to connect
+
+   The interconnection of server is not a trivial matter: a bad
+   connection can have a large impact on the usefulness of IRC.  Thus,
+   each server should have a list of servers to which it may connect and
+   which servers may connect to it.  Under no circumstances should a
+   server allow an arbitrary host to connect as a server.  In addition
+   to which servers may and may not connect, the configuration file
+   should also store the password and other characteristics of that
+   link.
+
+
+
+Oikarinen & Reed                                               [Page 62]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+8.12.4 Administrivia
+
+   To provide accurate and valid replies to the ADMIN command (see
+   section 4.3.7), the server should find the relevant details in the
+   configuration.
+
+8.13 Channel membership
+
+   The current server allows any registered local user to join upto 10
+   different channels.  There is no limit imposed on non-local users so
+   that the server remains (reasonably) consistant with all others on a
+   channel membership basis
+
+9. Current problems
+
+   There are a number of recognized problems with this protocol, all  of
+   which  hope to be solved sometime in the near future during its
+   rewrite.  Currently, work is underway to find working solutions to
+   these problems.
+
+9.1 Scalability
+
+   It is widely recognized that this protocol does not scale
+   sufficiently well when used in a large arena.  The main problem comes
+   from the requirement that all servers know about all other servers
+   and users and that information regarding them be updated as soon as
+   it changes.  It is also desirable to keep the number of servers low
+   so that the path length between any two points is kept minimal and
+   the spanning tree as strongly branched as possible.
+
+9.2 Labels
+
+   The current IRC protocol has 3 types of labels: the nickname, the
+   channel name and the server name.  Each of the three types has its
+   own domain and no duplicates are allowed inside that domain.
+   Currently, it is possible for users to pick the label for any of the
+   three, resulting in collisions.  It is widely recognized that this
+   needs reworking, with a plan for unique names for channels and nicks
+   that don't collide being desirable as well as a solution allowing a
+   cyclic tree.
+
+9.2.1 Nicknames
+
+   The idea of the nickname on IRC is very convenient for users to use
+   when talking to each other outside of a channel, but there is only a
+   finite nickname space and being what they are, its not uncommon for
+   several people to want to use the same nick.  If a nickname is chosen
+   by two people using this protocol, either one will not succeed or
+
+
+
+Oikarinen & Reed                                               [Page 63]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+   both will removed by use of KILL (4.6.1).
+
+9.2.2 Channels
+
+   The current channel layout requires that all servers know about all
+   channels, their inhabitants and properties.  Besides not scaling
+   well, the issue of privacy is also a concern.  A collision of
+   channels is treated as an inclusive event (both people who create the
+   new channel are considered to be members of it) rather than an
+   exclusive one such as used to solve nickname collisions.
+
+9.2.3 Servers
+
+   Although the number of servers is usually small relative to the
+   number of users and channels, they two currently required to be known
+   globally, either each one separately or hidden behind a mask.
+
+9.3 Algorithms
+
+   In some places within the server code, it has not  been  possible  to
+   avoid  N^2  algorithms  such  as  checking  the channel list of a set
+   of clients.
+
+   In current server versions, there are no database consistency checks,
+   each server assumes that a neighbouring server is correct.  This
+   opens the door to large problems if a connecting server is buggy or
+   otherwise tries to introduce contradictions to the existing net.
+
+   Currently, because of the lack of unique internal and global labels,
+   there are a multitude of race conditions that exist.  These race
+   conditions generally arise from the problem of it taking time for
+   messages to traverse and effect the IRC network.  Even by changing to
+   unique labels, there are problems with channel-related commands being
+   disrupted.
+
+10. Current support and availability
+
+           Mailing lists for IRC related discussion:
+                Future protocol: ircd-three-request@eff.org
+                General discussion: operlist-request@eff.org
+
+           Software implemenations
+                cs.bu.edu:/irc
+                nic.funet.fi:/pub/irc
+                coombs.anu.edu.au:/pub/irc
+
+           Newsgroup: alt.irc
+
+
+
+
+Oikarinen & Reed                                               [Page 64]
+\f
+RFC 1459              Internet Relay Chat Protocol              May 1993
+
+
+Security Considerations
+
+   Security issues are discussed in sections 4.1, 4.1.1, 4.1.3, 5.5, and
+   7.
+
+12. Authors' Addresses
+
+   Jarkko Oikarinen
+   Tuirantie 17 as 9
+   90500 OULU
+   FINLAND
+
+   Email: jto@tolsun.oulu.fi
+
+
+   Darren Reed
+   4 Pateman Street
+   Watsonia, Victoria 3087
+   Australia
+
+   Email: avalon@coombs.anu.edu.au
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Oikarinen & Reed                                               [Page 65]
+\f
diff --git a/doc/snomask.html b/doc/snomask.html
new file mode 100644 (file)
index 0000000..68ddc65
--- /dev/null
@@ -0,0 +1,201 @@
+<html>\r
+<head>\r
+<title>SNOMASK - Server Notice Masks</title>\r
+</head>\r
+<body bgcolor=#FFFFFF text=#000000 link=#700000 vlink=#404040>\r
+<center>\r
+<font face="arial">\r
+<h2>SNOMASK - Server Notice Masks</h2></font>\r
+<font face="arial" size="2">\r
+Written by <a href="mailto:foxxe@wolfspirit.org">Ghostwolf</a> 18th June 1997<br>\r
+Modified with permission by <a href="mailto:loki@undernet.org">loki</a> 12th November 1997\r
+</center>\r
+<p><hr width="80%" noshade>\r
+\r
+<blockquote>\r
+This document (hopefully) gives a brief explanation of the use of server\r
+notice masks new to ircu2.10.00. This mask allows clients to specify which\r
+types of server notices they will receive when usermode +s. The mask may\r
+optionally be omitted, and reasonable defaults will be used by the server.\r
+<p>\r
+Note: the descriptions here will be best understood by those with knowledge\r
+of C syntax. We do not attempt to explain either this or hexadecimal values\r
+in this document, and familiarity with these is assumed of the reader.\r
+<p>\r
+Usage:\r
+</font><kbd><strong>\r
+/mode &lt;nick&gt; +s [+/-][mask]</kbd></strong>\r
+<font face="arial" size="2">\r
+<p>\r
+<center>\r
+<table border=0 cellspacing=5 cellpadding=0 width=85%>\r
+<tr align=center valign=middle>\r
+<th align=left><font face="arial" size="2">Mask</th>\r
+<th align=left>&nbsp;</th>\r
+<th align=left><font face="arial" size="2">Hex value</th>\r
+<th align=left><font face="arial" size="2">Description</th>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">1</td>\r
+<td><font face="arial" size="2">SNO_OLDSNO</td>\r
+<td><font face="arial" size="2">0x1</td>\r
+<td><font face="arial" size="2">/* unsorted old messages */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">2</td>\r
+<td><font face="arial" size="2">SNO_SERVKILL</td>\r
+<td><font face="arial" size="2">0x2</td>\r
+<td><font face="arial" size="2">/* server kills (nick collisions) */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">4</td>\r
+<td><font face="arial" size="2">SNO_OPERKILL</td>\r
+<td><font face="arial" size="2">0x4</td>\r
+<td><font face="arial" size="2">/* oper kills */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">8</td>\r
+<td><font face="arial" size="2">SNO_HACK2</td>\r
+<td><font face="arial" size="2">0x8</td>\r
+<td><font face="arial" size="2">/* desyncs */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">16</td>\r
+<td><font face="arial" size="2">SNO_HACK3\r
+<td><font face="arial" size="2">0x10</td>\r
+<td><font face="arial" size="2">/* temporary desyncs */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">32</td>\r
+<td><font face="arial" size="2">SNO_UNAUTH</td>\r
+<td><font face="arial" size="2">0x20</td>\r
+<td><font face="arial" size="2">/* unauthorized connections */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">64</td>\r
+<td><font face="arial" size="2">SNO_TCPCOMMON</td>\r
+<td><font face="arial" size="2">0x40</td>\r
+<td><font face="arial" size="2">/* common TCP or socket errors */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">128</td>\r
+<td><font face="arial" size="2">SNO_TOOMANY</td>\r
+<td><font face="arial" size="2">0x80</td>\r
+<td><font face="arial" size="2">/* too many connections */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">256</td>\r
+<td><font face="arial" size="2">SNO_HACK4</td>\r
+<td><font face="arial" size="2">0x100</td>\r
+<td><font face="arial" size="2">/* Uworld actions on channels */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">512</td>\r
+<td><font face="arial" size="2">SNO_GLINE</td>\r
+<td><font face="arial" size="2">0x200</td>\r
+<td><font face="arial" size="2">/* glines */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">1024</td>\r
+<td><font face="arial" size="2">SNO_NETWORK</td>\r
+<td><font face="arial" size="2">0x400</td>\r
+<td><font face="arial" size="2">/* net join/break, etc */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">2048</td>\r
+<td><font face="arial" size="2">SNO_IPMISMATCH</td>\r
+<td><font face="arial" size="2">0x800</td>\r
+<td><font face="arial" size="2">/* IP mismatches */</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">4096</td>\r
+<td><font face="arial" size="2">SNO_THROTTLE</td>\r
+<td><font face="arial" size="2">0x1000</td>\r
+<td><font face="arial" size="2">/* host throttle add/remove notices */</td>\r
+</tr>\r
+<td><font face="arial" size="2">8192</td>\r
+<td><font face="arial" size="2">SNO_OLDREALOP</td>\r
+<td><font face="arial" size="2">0x2000</td>\r
+<td><font face="arial" size="2">/* old oper-only messages */</td>\r
+</tr>\r
+<td><font face="arial" size="2">16384</td>\r
+<td><font face="arial" size="2">SNO_CONNEXIT</td>\r
+<td><font face="arial" size="2">0x4000</td>\r
+<td><font face="arial" size="2">/* client connect/exit (ugh) */</td>\r
+</tr>\r
+</table>\r
+</center>\r
+\r
+<p>\r
+\r
+<table border=0 cellpadding=0 cellspacing=5 width=90%>\r
+<tr>\r
+<td><font face="arial" size="2">standard +s</td>\r
+<td><font face="arial" size="2">SNO_DEFAULT (SNO_NETWORK | SNO_OPERKILL | SNO_GLINE)</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">standard +s when +o/O</td>\r
+<td><font face="arial" size="2">SNO_DEFAULT | SNO_HACK2 | SNO_HACK4 | SNO_OLDSNO)</td>\r
+</tr>\r
+<tr>\r
+<td><font face="arial" size="2">only opers may set</td>\r
+<td><font face="arial" size="2">SNO_OPER (SNO_CONNEXIT | SNO_OLDREALOP)</td>\r
+</tr>\r
+</table>\r
+\r
+<p><hr width="80%" noshade>\r
+<h3 align=center>Examples of Usage</h3>\r
+To receive only operkills, use /mode <nick> +s 4<br>\r
+To receive operkills and glines, add the values:\r
+</font>\r
+<blockquote><kbd><strong>\r
+/mode &lt;nick&gt; +s 516</kbd></strong><p>\r
+<font face="arial" size="2">\r
+(512+4=516)\r
+</blockquote>\r
+<p>\r
+If you are already receiving some notices and you wish to add notices of\r
+netjoins/breaks use:\r
+</font>\r
+<blockquote><kbd><strong>\r
+/mode Ghostwolf +s +1024</kbd></strong><p>\r
+</blockquote>\r
+<font face="arial" size="2">\r
+<p>\r
+If you wish to stop receiving netjoin/break notices, but continue to receive\r
+other notices, use:\r
+</font>\r
+<blockquote><kbd><strong>\r
+/mode Ghostwolf +s -1024<br>\r
+ OR<br>\r
+/mode Ghostwolf -s +1024</kbd></strong>\r
+</blockquote>\r
+<font face="arial" size="2">\r
+<p>\r
+A user typing <strong>/mode Ghostwolf +s </strong>will receive netsplits/joins, operkills, and g-lines.<p>\r
+\r
+Opers who are +s will additionally receive HACK notices and anything that\r
+was originally in sendto_ops() and wasn't changed. Only opers can choose to\r
+receive connect/exit notices and anything that originally was in\r
+sendtoreal_ops() and hasn't been changed (connect/exit notices also require\r
+a #define in config.h).\r
+<p>\r
+</font><center>\r
+<hr width=80% noshade><font size=-1><strong>\r
+If you have further questions about server notices (implementation, etc.),<br>\r
+please consult the ircu source code and/or e-mail <a\r
+href="mailto:coder-com@undernet.org">coder-com@undernet.org</a>.\r
+</strong></font></center>\r
+<hr width="80%" noshade><p>\r
+\r
+<p align="right">\r
+<em>\r
+<font face="times new roman" font size="-1">\r
+Return to <a href="http://www.user-com.undernet.org/documents/" target="nfo">main Documents Project page</a><br>\r
+</em>\r
+</font>\r
+\r
+</body>\r
+</html>\r
+\r
+\r
diff --git a/doc/strings.txt b/doc/strings.txt
new file mode 100644 (file)
index 0000000..ce3562f
--- /dev/null
@@ -0,0 +1,33 @@
+Strings Information for ircu
+
+Client:
+
+name: (nickname for clients, server name for servers)
+  set in s_conf.c when checking C/N lines for a server
+  set in s_user.c during client registration
+
+username: (user name string)
+  set in s_auth.c if the client RFC 931 authentication query successful.
+  set in s_user.c if auth query unsuccessful.
+  
+info: (string)
+  set in s_serv.c during server registration
+  set in s_user.c during client registration
+
+passwd: (password string)
+  set in xxx.c when
+  used in xxx.c
+  cleared in xxx.c when
+
+sock_ip: (ip address)
+  set in s_bsd.c when connection is established
+  used in s_conf.c when looking for conf entries
+  not cleared
+
+sockhost: (resolved host name or ip address)
+  set in s_bsd.c when connection is established (copied from sock_ip)
+  set in s_auth.c if dns query is successful
+  set in s_conf.c if a C line is found that matches something in dns_reply.hp
+  used in opercmds.c
+  
+
index f27499603406995ded7a84ac91e0e3d70734f4de..ee17ac39f6feec1c1ee20ed3f1fef69373ed9253 100644 (file)
@@ -1,16 +1,31 @@
-#ifndef IPCHECK_H
-#define IPCHECK_H
-
-/*=============================================================================
- * Proto types
+/*
+ * IPcheck.h
+ *
+ * $Id$
  */
+#ifndef INCLUDED_ipcheck_h
+#define INCLUDED_ipcheck_h
+
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>          /* time_t, size_t */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>         /* in_addr */
+#define INCLUDED_netinet_in_h
+#endif
 
-extern int IPcheck_local_connect(aClient *cptr);
-extern void IPcheck_connect_fail(aClient *cptr);
-extern void IPcheck_connect_succeeded(aClient *cptr);
-extern int IPcheck_remote_connect(aClient *cptr, const char *hostname,
+struct Client;
+
+/*
+ * Prototypes
+ */
+extern int IPcheck_local_connect(struct in_addr ip, time_t* next_target_out);
+extern void IPcheck_connect_fail(struct in_addr ip);
+extern void IPcheck_connect_succeeded(struct Client *cptr);
+extern int IPcheck_remote_connect(struct Client *cptr, const char *hostname,
     int is_burst);
-extern void IPcheck_disconnect(aClient *cptr);
-extern unsigned short IPcheck_nr(aClient *cptr);
+extern void IPcheck_disconnect(struct Client *cptr);
+extern unsigned short IPcheck_nr(struct Client *cptr);
 
-#endif /* IPCHECK_H */
+#endif /* INCLUDED_ipcheck_h */
diff --git a/include/bsd.h b/include/bsd.h
deleted file mode 100644 (file)
index 98ed790..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef BSD_H
-#define BSD_H
-
-/*=============================================================================
- * Proto types
- */
-
-extern RETSIGTYPE dummy(HANDLER_ARG(int sig));
-extern int deliver_it(aClient *cptr, const char *str, int len);
-
-extern int writecalls;
-extern int writeb[10];
-
-#endif
index abe7e1eb18cb0493abf64e294c112cdb8e55c00b..fa2d5d92443e79b5bd19566e67f591250d32612c 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_channel_h
+#define INCLUDED_channel_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"        /* NICKLEN */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
 
-#include "list.h"
-
-#ifndef CHANNEL_H
-#define CHANNEL_H
+struct SLink;
+struct Client;
 
-/*=============================================================================
+/*
  * General defines
  */
 
-#define MAXMODEPARAMS  6
-#define MODEBUFLEN     200
+#define MAXMODEPARAMS   6
+#define MODEBUFLEN      200
 
-#define KEYLEN         23
-#define TOPICLEN       160
-#define CHANNELLEN     200
-#define MAXBANS                30
-#define MAXBANLENGTH   1024
+#define KEYLEN          23
+#define CHANNELLEN      200
+#define MAXBANS         30
+#define MAXBANLENGTH    1024
 
-/*=============================================================================
+/*
  * Macro's
  */
 
-#define ChannelExists(n)       (FindChannel(n) != NullChn)
-#define NullChn ((aChannel *)0)
-#define CREATE 1               /* whether a channel should be
-                                * created or just tested for existance */
-
-#define CHFL_CHANOP            0x0001  /* Channel operator */
-#define CHFL_VOICE             0x0002  /* the power to speak */
-#define CHFL_DEOPPED           0x0004  /* Is de-opped by a server */
-#define CHFL_SERVOPOK          0x0008  /* Server op allowed */
-#define CHFL_ZOMBIE            0x0010  /* Kicked from channel */
-#define CHFL_BAN               0x0020  /* ban channel flag */
-#define CHFL_BAN_IPMASK                0x0040  /* ban mask is an IP-number mask */
-#define CHFL_BAN_OVERLAPPED    0x0080  /* ban overlapped, need bounce */
-#define CHFL_OVERLAP   (CHFL_CHANOP|CHFL_VOICE)
-#define CHFL_BURST_JOINED      0x0100  /* Just joined by net.junction */
-#define CHFL_BURST_BAN         0x0200  /* Ban part of last BURST */
-#define CHFL_BURST_BAN_WIPEOUT 0x0400  /* Ban will be wiped at end of BURST */
-#define CHFL_BANVALID          0x0800  /* CHFL_BANNED bit is valid */
-#define CHFL_BANNED            0x1000  /* Channel member is banned */
-#define CHFL_SILENCE_IPMASK    0x2000  /* silence mask is an IP-number mask */
+#define ChannelExists(n)        (0 != FindChannel(n))
+
+#define CHFL_CHANOP             0x0001  /* Channel operator */
+#define CHFL_VOICE              0x0002  /* the power to speak */
+#define CHFL_DEOPPED            0x0004  /* Is de-opped by a server */
+#define CHFL_SERVOPOK           0x0008  /* Server op allowed */
+#define CHFL_ZOMBIE             0x0010  /* Kicked from channel */
+#define CHFL_BAN                0x0020  /* ban channel flag */
+#define CHFL_BAN_IPMASK         0x0040  /* ban mask is an IP-number mask */
+#define CHFL_BAN_OVERLAPPED     0x0080  /* ban overlapped, need bounce */
+#define CHFL_BURST_JOINED       0x0100  /* Just joined by net.junction */
+#define CHFL_BURST_BAN          0x0200  /* Ban part of last BURST */
+#define CHFL_BURST_BAN_WIPEOUT  0x0400  /* Ban will be wiped at end of BURST */
+#define CHFL_BANVALID           0x0800  /* CHFL_BANNED bit is valid */
+#define CHFL_BANNED             0x1000  /* Channel member is banned */
+#define CHFL_SILENCE_IPMASK     0x2000  /* silence mask is an IP-number mask */
+
+#define CHFL_OVERLAP         (CHFL_CHANOP | CHFL_VOICE)
+#define CHFL_BANVALIDMASK    (CHFL_BANVALID | CHFL_BANNED)
+#define CHFL_VOICED_OR_OPPED (CHFL_CHANOP | CHFL_VOICE)
 
 /* Channel Visibility macros */
 
-#define MODE_CHANOP    CHFL_CHANOP
-#define MODE_VOICE     CHFL_VOICE
-#define MODE_PRIVATE   0x0004
-#define MODE_SECRET    0x0008
-#define MODE_MODERATED 0x0010
+#define MODE_CHANOP     CHFL_CHANOP
+#define MODE_VOICE      CHFL_VOICE
+#define MODE_PRIVATE    0x0004
+#define MODE_SECRET     0x0008
+#define MODE_MODERATED  0x0010
 #define MODE_TOPICLIMIT 0x0020
 #define MODE_INVITEONLY 0x0040
 #define MODE_NOPRIVMSGS 0x0080
-#define MODE_KEY       0x0100
-#define MODE_BAN       0x0200
-#define MODE_LIMIT     0x0400
-#define MODE_SENDTS    0x0800  /* TS was 0 during a local user /join; send
-                                * temporary TS; can be removed when all 2.10 */
-#define MODE_LISTED    0x10000
+#define MODE_KEY        0x0100
+#define MODE_BAN        0x0200
+#define MODE_LIMIT      0x0400
+#define MODE_SENDTS     0x0800  /* TS was 0 during a local user /join; send
+                                 * temporary TS; can be removed when all 2.10 */
+#define MODE_LISTED     0x10000
 
 /*
  * mode flags which take another parameter (With PARAmeterS)
  */
-#define MODE_WPARAS    (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT)
+#define MODE_WPARAS     (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY|MODE_LIMIT)
 
-#define HoldChannel(x)         (!(x))
+#define HoldChannel(x)          (!(x))
 /* name invisible */
-#define SecretChannel(x)       ((x) && ((x)->mode.mode & MODE_SECRET))
+#define SecretChannel(x)        ((x) && ((x)->mode.mode & MODE_SECRET))
 /* channel not shown but names are */
-#define HiddenChannel(x)       ((x) && ((x)->mode.mode & MODE_PRIVATE))
+#define HiddenChannel(x)        ((x) && ((x)->mode.mode & MODE_PRIVATE))
 /* channel visible */
-#define ShowChannel(v,c)       (PubChannel(c) || IsMember((v),(c)))
-#define PubChannel(x)          ((!x) || ((x)->mode.mode & \
-                                   (MODE_PRIVATE | MODE_SECRET)) == 0)
-#define is_listed(x)           ((x)->mode.mode & MODE_LISTED)
-
-#define IsLocalChannel(name)   (*(name) == '&')
-#define IsModelessChannel(name)        (*(name) == '+')
-#define IsChannelName(name)    (*(name) == '#' || \
-                               IsModelessChannel(name) || IsLocalChannel(name))
+#define ShowChannel(v,c)        (PubChannel(c) || find_channel_member((v),(c)))
+#define PubChannel(x)           ((!x) || ((x)->mode.mode & \
+                                    (MODE_PRIVATE | MODE_SECRET)) == 0)
+#define is_listed(x)            ((x)->mode.mode & MODE_LISTED)
 
-/* Check if a sptr is an oper, and chptr is a local channel. */
-
-#define IsOperOnLocalChannel(sptr,chname) ((IsAnOper(sptr)) \
-                                          && (IsLocalChannel(chname)))
-
-#ifdef OPER_WALK_THROUGH_LMODES
-  /* used in can_join to determine if an oper forced a join on a channel */
-  #define MAGIC_OPER_OVERRIDE 1000
-#endif
+#define IsLocalChannel(name)    (*(name) == '&')
+#define IsModelessChannel(name) (*(name) == '+')
+#define IsChannelName(name)     (*(name) == '#' || \
+                                IsModelessChannel(name) || IsLocalChannel(name))
 
+/*
+ * Check if a sptr is an oper, and chptr is a local channel.
+ */
+#define IsOperOnLocalChannel(sptr,chname) \
+                ((IsAnOper(sptr)) && (IsLocalChannel(chname)))
 
+typedef enum ChannelGetType {
+  CGT_NO_CREATE,
+  CGT_CREATE
+} ChannelGetType;
 
 /* used in SetMode() in channel.c and m_umode() in s_msg.c */
 
 #define MODE_ADD       0x40000000
 #define MODE_DEL       0x20000000
 
-/*=============================================================================
+/*
+ * Maximum acceptable lag time in seconds: A channel younger than
+ * this is not protected against hacking admins.
+ * Mainly here to check if the TS clocks really sync (otherwise this
+ * will start causing HACK notices.
+ * This value must be the same on all servers.
+ *
+ * This value has been increased to 1 day in order to distinguish this
+ * "normal" type of HACK wallops / desyncs, from possiblity still
+ * existing bugs.
+ */
+#define TS_LAG_TIME 86400
+
+/*
+ * A Magic TS that is used for channels that are created by JOIN,
+ * a channel with this TS accepts all TS without complaining that
+ * it might receive later via MODE or CREATE.
+ */
+#define MAGIC_REMOTE_JOIN_TS 1270080000
+
+ #ifdef OPER_WALK_THROUGH_LMODES
+   /* used in can_join to determine if an oper forced a join on a channel */
+   #define MAGIC_OPER_OVERRIDE 1000
+ #endif
+
+
+extern const char* const PartFmt1;
+extern const char* const PartFmt2;
+extern const char* const PartFmt1serv;
+extern const char* const PartFmt2serv;
+
+
+/*
  * Structures
  */
 
-struct SMode {
+struct Membership {
+  struct Client*     user;
+  struct Channel*    channel;
+  struct Membership* next_member;
+  struct Membership* prev_member;
+  struct Membership* next_channel;
+  struct Membership* prev_channel;
+  unsigned int       status;
+};
+
+#define IsZombie(x)         ((x)->status & CHFL_ZOMBIE)
+#define IsDeopped(x)        ((x)->status & CHFL_DEOPPED)
+#define IsBanned(x)         ((x)->status & CHFL_BANNED)
+#define IsBanValid(x)       ((x)->status & CHFL_BANVALID)
+#define IsChanOp(x)         ((x)->status & CHFL_CHANOP)
+#define HasVoice(x)         ((x)->status & CHFL_VOICE)
+#define IsServOpOk(x)       ((x)->status & CHFL_SERVOPOK)
+#define IsBurstJoined(x)    ((x)->status & CHFL_BURST_JOINED)
+#define IsVoicedOrOpped(x)  ((x)->status & CHFL_VOICED_OR_OPPED)
+
+#define SetBanned(x)        ((x)->status |= CHFL_BANNED)
+#define SetBanValid(x)      ((x)->status |= CHFL_BANVALID)
+#define SetDeopped(x)       ((x)->status |= CHFL_DEOPPED)
+#define SetServOpOk(x)      ((x)->status |= CHFL_SERVOPOK)
+#define SetBurstJoined(x)   ((x)->status |= CHFL_BURST_JOINED)
+#define SetZombie(x)        ((x)->status |= CHFL_ZOMBIE)
+
+#define ClearBanned(x)      ((x)->status &= ~CHFL_BANNED)
+#define ClearBanValid(x)    ((x)->status &= ~CHFL_BANVALID)
+#define ClearDeopped(x)     ((x)->status &= ~CHFL_DEOPPED)
+#define ClearServOpOk(x)    ((x)->status &= ~CHFL_SERVOPOK)
+#define ClearBurstJoined(x) ((x)->status &= ~CHFL_BURST_JOINED)
+
+
+struct Mode {
   unsigned int mode;
   unsigned int limit;
   char key[KEYLEN + 1];
 };
 
 struct Channel {
-  struct Channel *nextch, *prevch, *hnextch;
-  Mode mode;
-  time_t creationtime;
-  char topic[TOPICLEN + 1];
-  char topic_nick[NICKLEN + 1];
-  time_t topic_time;
-  unsigned int users;
-  struct SLink *members;
-  struct SLink *invites;
-  struct SLink *banlist;
-  char chname[1];
+  struct Channel*    next;
+  struct Channel*    prev;
+  struct Channel*    hnext;
+  time_t             creationtime;
+  time_t             topic_time;
+  unsigned int       users;
+  struct Membership* members;
+  struct SLink*      invites;
+  struct SLink*      banlist;
+  struct Mode        mode;
+  char               topic[TOPICLEN + 1];
+  char               topic_nick[NICKLEN + 1];
+  char               chname[1];
 };
 
 struct ListingArgs {
@@ -153,33 +230,61 @@ struct ListingArgs {
   struct Channel *chptr;
 };
 
-/*=============================================================================
+extern struct Channel* GlobalChannelList;
+extern int             LocalChanOperMode;
+
+/*
  * Proto types
  */
+extern void clean_channelname(char* name);
+extern void channel_modes(struct Client *cptr, char *mbuf, char *pbuf,
+                          struct Channel *chptr);
+extern int set_mode(struct Client* cptr, struct Client* sptr,
+                    struct Channel* chptr, int parc, char* parv[],
+                    char* mbuf, char* pbuf, char* npbuf, int* badop);
+extern void send_hack_notice(struct Client *cptr, struct Client *sptr,
+                             int parc, char *parv[], int badop, int mtype);
+extern struct Channel *get_channel(struct Client *cptr,
+                                   char *chname, ChannelGetType flag);
+extern struct Membership* find_member_link(struct Channel * chptr,
+                                           const struct Client* cptr);
+extern int sub1_from_channel(struct Channel* chptr);
+extern int can_join(struct Client *sptr, struct Channel *chptr, char *key);
+extern void add_user_to_channel(struct Channel* chptr, struct Client* who,
+                                unsigned int flags);
+extern void cancel_mode(struct Client *sptr, struct Channel *chptr, char m,
+                        const char *param, int *count);
+extern void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
+                                 int *send_itp, char is_a_ban, int mode);
+extern int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
+                     int change, int firsttime);
+extern struct SLink *next_removed_overlapped_ban(void);
+extern void cancel_mode(struct Client *sptr, struct Channel *chptr, char m,
+                        const char *param, int *count);
+extern void make_zombie(struct Membership* member, struct Client* who,
+                        struct Client* cptr, struct Client* sptr,
+                        struct Channel* chptr);
+extern struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing);
+void add_invite(struct Client *cptr, struct Channel *chptr);
+int number_of_zombies(struct Channel *chptr);
 
-extern int m_names(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern Link *IsMember(aClient *cptr, aChannel *chptr);
-extern void remove_user_from_channel(aClient *sptr, aChannel *chptr);
-extern int is_chan_op(aClient *cptr, aChannel *chptr);
-extern int is_zombie(aClient *cptr, aChannel *chptr);
-extern int has_voice(aClient *cptr, aChannel *chptr);
-extern int can_send(aClient *cptr, aChannel *chptr);
-extern void send_channel_modes(aClient *cptr, aChannel *chptr);
-extern int m_mode(aClient *cptr, aClient *sptr, int parc, char *parv[]);
+extern const char* find_no_nickchange_channel(struct Client* cptr);
+extern struct Membership* IsMember(struct Client *cptr, struct Channel *chptr);
+extern struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr);
+extern int member_can_send_to_channel(struct Membership* member);
+extern int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr);
+
+extern void remove_user_from_channel(struct Client *sptr, struct Channel *chptr);
+extern void remove_user_from_all_channels(struct Client* cptr);
+
+extern int is_chan_op(struct Client *cptr, struct Channel *chptr);
+extern int is_zombie(struct Client *cptr, struct Channel *chptr);
+extern int has_voice(struct Client *cptr, struct Channel *chptr);
+extern void send_channel_modes(struct Client *cptr, struct Channel *chptr);
 extern char *pretty_mask(char *mask);
-extern void del_invite(aClient *cptr, aChannel *chptr);
-extern void list_next_channels(aClient *cptr, int nr);
-extern int m_join(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_create(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_destruct(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_burst(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_part(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_topic(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_invite(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_list(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern void send_user_joins(aClient *cptr, aClient *user);
-
-extern aChannel *channel;
-
-#endif /* CHANNEL_H */
+extern void del_invite(struct Client *cptr, struct Channel *chptr);
+extern void list_next_channels(struct Client *cptr, int nr);
+extern void send_user_joins(struct Client *cptr, struct Client *user);
+
+
+#endif /* INCLUDED_channel_h */
index 97e483234ea556a9c1c8e5646bc445d77001e8fa..b95dc358c9b56a716f9923a05c82e116e75ea3c8 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_class_h
+#define INCLUDED_class_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
 
-#ifndef CLASS_H
-#define CLASS_H
+struct Client;
+struct ConfItem;
 
-/*=========================================================================
+/*
  * Structures
  */
-
 struct ConfClass {
   unsigned int conClass;
   unsigned int conFreq;
@@ -35,48 +42,48 @@ struct ConfClass {
   struct ConfClass *next;
 };
 
-/*=============================================================================
+/*
  * Macro's
  */
 
-#define ConClass(x)    ((x)->conClass)
-#define ConFreq(x)     ((x)->conFreq)
-#define PingFreq(x)    ((x)->pingFreq)
-#define MaxLinks(x)    ((x)->maxLinks)
-#define MaxSendq(x)    ((x)->maxSendq)
-#define Links(x)       ((x)->links)
+#define ConClass(x)     ((x)->conClass)
+#define ConFreq(x)      ((x)->conFreq)
+#define PingFreq(x)     ((x)->pingFreq)
+#define MaxLinks(x)     ((x)->maxLinks)
+#define MaxSendq(x)     ((x)->maxSendq)
+#define Links(x)        ((x)->links)
 
-#define ConfLinks(x)   ((x)->confClass->links)
+#define ConfLinks(x)    ((x)->confClass->links)
 #define ConfMaxLinks(x) ((x)->confClass->maxLinks)
-#define ConfClass(x)   ((x)->confClass->conClass)
-#define ConfConFreq(x) ((x)->confClass->conFreq)
+#define ConfClass(x)    ((x)->confClass->conClass)
+#define ConfConFreq(x)  ((x)->confClass->conFreq)
 #define ConfPingFreq(x) ((x)->confClass->pingFreq)
-#define ConfSendq(x)   ((x)->confClass->maxSendq)
+#define ConfSendq(x)    ((x)->confClass->maxSendq)
 
-#define FirstClass()   classes
-#define NextClass(x)   ((x)->next)
+#define FirstClass()    classes
+#define NextClass(x)    ((x)->next)
 
-#define MarkDelete(x)  do { MaxLinks(x) = (unsigned int)-1; } while(0)
+#define MarkDelete(x)   do { MaxLinks(x) = (unsigned int)-1; } while(0)
 #define IsMarkedDelete(x) (MaxLinks(x) == (unsigned int)-1)
 
-/*=============================================================================
+/*
  * Proto types
  */
 
-extern aConfClass *find_class(unsigned int cclass);
-extern aConfClass *make_class(void);
-extern void free_class(aConfClass * tmp);
-extern unsigned int get_con_freq(aConfClass * clptr);
-extern unsigned int get_client_ping(aClient *acptr);
-extern unsigned int get_conf_class(aConfItem *aconf);
-extern unsigned int get_client_class(aClient *acptr);
+extern struct ConfClass *find_class(unsigned int cclass);
+extern struct ConfClass *make_class(void);
+extern void free_class(struct ConfClass * tmp);
+extern unsigned int get_con_freq(struct ConfClass * clptr);
+extern unsigned int get_client_ping(struct Client *acptr);
+extern unsigned int get_conf_class(struct ConfItem *aconf);
+extern unsigned int get_client_class(struct Client *acptr);
 extern void add_class(unsigned int conclass, unsigned int ping,
     unsigned int confreq, unsigned int maxli, size_t sendq);
 extern void check_class(void);
 extern void initclass(void);
-extern void report_classes(aClient *sptr);
-extern size_t get_sendq(aClient *cptr);
+extern void report_classes(struct Client *sptr);
+extern size_t get_sendq(struct Client* cptr);
 
-extern aConfClass *classes;
+extern struct ConfClass *classes;
 
-#endif /* CLASS_H */
+#endif /* INCLUDED_class_h */
diff --git a/include/client.h b/include/client.h
new file mode 100644 (file)
index 0000000..1e74687
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * IRC - Internet Relay Chat, include/client.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_client_h
+#define INCLUDED_client_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>          /* time_t, size_t */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>         /* in_addr */
+#define INCLUDED_netinet_in_h
+#endif
+#ifndef INCLUDED_dbuf_h
+#include "dbuf.h"
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"
+#endif
+#ifndef INCLUDED_ircd_handler_h
+#include "ircd_handler.h"
+#endif
+
+struct ConfItem;
+struct Listener;
+struct ListingArgs;
+struct SLink;
+struct Server;
+struct User;
+struct Whowas;
+struct DNSReply;
+struct hostent;
+
+/*-----------------------------------------------------------------------------
+ * Macros
+ */
+#define CLIENT_LOCAL_SIZE sizeof(struct Client)
+#define CLIENT_REMOTE_SIZE offsetof(struct Client, count)
+
+/*
+ * Structures
+ *
+ * Only put structures here that are being used in a very large number of
+ * source files. Other structures go in the header file of there corresponding
+ * source file, or in the source file itself (when only used in that file).
+ */
+
+struct Client {
+  struct Client* next;          /* link in GlobalClientList */
+  struct Client* prev;          /* link in GlobalClientList */
+  struct Client* hnext;         /* link in hash table bucket or this */
+  struct Client* from;          /* == self, if Local Client, *NEVER* NULL! */
+  struct User*   user;          /* ...defined, if this is a User */
+  struct Server* serv;          /* ...defined, if this is a server */
+  struct Whowas* whowas;        /* Pointer to ww struct to be freed on quit */
+  char           yxx[4];        /* Numeric Nick: YMM if this is a server,
+                                   XX0 if this is a user */
+  /*
+   * XXX - move these to local part for next release
+   * (lasttime, since)
+   */
+  time_t         lasttime;      /* last time data read from socket */
+  time_t         since;         /* last time we parsed something, flood control */
+
+  time_t         firsttime;     /* time client was created */
+  time_t         lastnick;      /* TimeStamp on nick */
+  int            marker;        /* /who processing marker */
+  unsigned int   flags;         /* client flags */
+  unsigned int   hopcount;      /* number of servers to this 0 = local */
+  struct in_addr ip;            /* Real ip# NOT defined for remote servers! */
+  short          status;        /* Client type */
+  unsigned char  local;         /* local or remote client */
+  char name[HOSTLEN + 1];       /* Unique name of the client, nick or host */
+  char username[USERLEN + 1];   /* username here now for auth stuff */
+  char info[REALLEN + 1];       /* Free form additional client information */
+  /*
+   *  The following fields are allocated only for local clients
+   *  (directly connected to *this* server with a socket.
+   *  The first of them *MUST* be the "count"--it is the field
+   *  to which the allocation is tied to! *Never* refer to
+   *  these fields, if (from != self).
+   */
+  unsigned int count;            /* Amount of data in buffer, DON'T PUT
+                                    variables ABOVE this one! */
+  int                 fd;        /* >= 0, for local clients */
+  int                 error;     /* last socket level error for client */
+  unsigned int        snomask;   /* mask for server messages */
+  time_t              nextnick;  /* Next time a nick change is allowed */
+  time_t              nexttarget; /* Next time a target change is allowed */
+  unsigned int        cookie;    /* Random number the user must PONG */
+  struct DBuf         sendQ;     /* Outgoing message queue--if socket full */
+  struct DBuf         recvQ;     /* Hold for data incoming yet to be parsed */
+  unsigned int        sendM;     /* Statistics: protocol messages send */
+  unsigned int        sendK;     /* Statistics: total k-bytes send */
+  unsigned int        receiveM;  /* Statistics: protocol messages received */
+  unsigned int        receiveK;  /* Statistics: total k-bytes received */
+  unsigned short      sendB;     /* counters to count upto 1-k lots of bytes */
+  unsigned short      receiveB;  /* sent and received. */
+  struct Listener*    listener;  /* listening client which we accepted from */
+  struct SLink*       confs;     /* Configuration record associated */
+  HandlerType         handler;   /* message index into command table for parsing */
+  struct DNSReply*    dns_reply; /* DNS reply used during client registration */
+  struct ListingArgs* listing;
+  size_t              max_sendq; /* cached max send queue for client */
+  unsigned short      lastsq;    /* # 2k blocks when sendqueued called last */
+  unsigned short      port;      /* and the remote port# too :-) */
+  unsigned char       targets[MAXTARGETS]; /* Hash values of current targets */
+  char sock_ip[SOCKIPLEN + 1];  /* this is the ip address as a string */
+  char sockhost[HOSTLEN + 1];   /* This is the host name from the socket and
+                                   after which the connection was accepted. */
+  char passwd[PASSWDLEN + 1];
+  char buffer[BUFSIZE];         /* Incoming message buffer; or the error that
+                                   caused this clients socket to be `dead' */
+};
+
+
+#define STAT_CONNECTING         0x001 /* connecting to another server */
+#define STAT_HANDSHAKE          0x002 /* pass - server sent */
+#define STAT_ME                 0x004 /* this server */
+#define STAT_UNKNOWN            0x008 /* unidentified connection */
+#define STAT_UNKNOWN_USER       0x010 /* Connect to client port */
+#define STAT_UNKNOWN_SERVER     0x020 /* Connect to server port */
+#define STAT_SERVER             0x040
+#define STAT_USER               0x080
+
+/*
+ * status macros.
+ */
+#define IsRegistered(x)         ((x)->status & (STAT_SERVER | STAT_USER))
+#define IsConnecting(x)         ((x)->status == STAT_CONNECTING)
+#define IsHandshake(x)          ((x)->status == STAT_HANDSHAKE)
+#define IsMe(x)                 ((x)->status == STAT_ME)
+#define IsUnknown(x)            ((x)->status & \
+        (STAT_UNKNOWN | STAT_UNKNOWN_USER | STAT_UNKNOWN_SERVER))
+
+#define IsServerPort(x)         ((x)->status == STAT_UNKNOWN_SERVER )
+#define IsUserPort(x)           ((x)->status == STAT_UNKNOWN_USER )
+#define IsClient(x)             ((x)->status & \
+        (STAT_HANDSHAKE | STAT_ME | STAT_UNKNOWN |\
+         STAT_UNKNOWN_USER | STAT_UNKNOWN_SERVER | STAT_SERVER | STAT_USER))
+
+#define IsTrusted(x)            ((x)->status & \
+        (STAT_CONNECTING | STAT_HANDSHAKE | STAT_ME | STAT_SERVER))
+
+#define IsServer(x)             ((x)->status == STAT_SERVER)
+#define IsUser(x)               ((x)->status == STAT_USER)
+
+
+#define SetConnecting(x)        ((x)->status = STAT_CONNECTING)
+#define SetHandshake(x)         ((x)->status = STAT_HANDSHAKE)
+#define SetServer(x)            ((x)->status = STAT_SERVER)
+#define SetMe(x)                ((x)->status = STAT_ME)
+#define SetUser(x)              ((x)->status = STAT_USER)
+
+#define MyConnect(x)    ((x)->from == (x))
+#define MyUser(x)       (MyConnect(x) && IsUser(x))
+#define MyOper(x)       (MyConnect(x) && IsOper(x))
+#define Protocol(x)     ((x)->serv->prot)
+
+#define PARSE_AS_SERVER(x) ((x)->status & \
+            (STAT_SERVER | STAT_CONNECTING | STAT_HANDSHAKE))
+
+/*
+ * FLAGS macros
+ */
+#define FLAGS_PINGSENT   0x0001 /* Unreplied ping sent */
+#define FLAGS_DEADSOCKET 0x0002 /* Local socket is dead--Exiting soon */
+#define FLAGS_KILLED     0x0004 /* Prevents "QUIT" from being sent for this */
+#define FLAGS_OPER       0x0008 /* Operator */
+#define FLAGS_LOCOP      0x0010 /* Local operator -- SRB */
+#define FLAGS_INVISIBLE  0x0020 /* makes user invisible */
+#define FLAGS_WALLOP     0x0040 /* send wallops to them */
+#define FLAGS_SERVNOTICE 0x0080 /* server notices such as kill */
+#define FLAGS_BLOCKED    0x0100 /* socket is in a blocked condition */
+#define FLAGS_CLOSING    0x0400 /* set when closing to suppress errors */
+#define FLAGS_UPING      0x0800 /* has active UDP ping request */
+#define FLAGS_CHKACCESS  0x1000 /* ok to check clients access if set */
+#define FLAGS_LOCAL     0x00010000      /* set for local clients */
+#define FLAGS_GOTID     0x00020000      /* successful ident lookup achieved */
+#define FLAGS_DOID      0x00040000      /* I-lines say must use ident return */
+#define FLAGS_NONL      0x00080000      /* No \n in buffer */
+#define FLAGS_TS8       0x00100000      /* Why do you want to know? */
+#define FLAGS_MAP       0x00800000      /* Show server on the map */
+#define FLAGS_JUNCTION  0x01000000      /* Junction causing the net.burst */
+#define FLAGS_DEAF      0x02000000      /* Makes user deaf */
+#define FLAGS_CHSERV    0x04000000      /* Disallow KICK or MODE -o on the user;
+                                           don't display channels in /whois */
+#define FLAGS_BURST     0x08000000      /* Server is receiving a net.burst */
+#define FLAGS_BURST_ACK 0x10000000      /* Server is waiting for eob ack */
+#define FLAGS_DEBUG     0x20000000      /* send global debug/anti-hack info */
+#define FLAGS_IPCHECK   0x40000000      /* Added or updated IPregistry data */
+
+#define SEND_UMODES \
+    (FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_DEAF|FLAGS_CHSERV|FLAGS_DEBUG)
+#define ALL_UMODES (SEND_UMODES|FLAGS_SERVNOTICE|FLAGS_LOCOP)
+#define FLAGS_ID (FLAGS_DOID|FLAGS_GOTID)
+
+/*
+ * flags macros.
+ */
+#define DoAccess(x)             ((x)->flags & FLAGS_CHKACCESS)
+#define IsAnOper(x)             ((x)->flags & (FLAGS_OPER|FLAGS_LOCOP))
+#define IsBlocked(x)            ((x)->flags & FLAGS_BLOCKED)
+#define IsBurst(x)              ((x)->flags & FLAGS_BURST)
+#define IsBurstAck(x)           ((x)->flags & FLAGS_BURST_ACK)
+#define IsBurstOrBurstAck(x)    ((x)->flags & (FLAGS_BURST|FLAGS_BURST_ACK))
+#define IsChannelService(x)     ((x)->flags & FLAGS_CHSERV)
+#define IsDead(x)               ((x)->flags & FLAGS_DEADSOCKET)
+#define IsDeaf(x)               ((x)->flags & FLAGS_DEAF)
+#define IsIPChecked(x)          ((x)->flags & FLAGS_IPCHECK)
+#define IsIdented(x)            ((x)->flags & FLAGS_GOTID)
+#define IsInvisible(x)          ((x)->flags & FLAGS_INVISIBLE)
+#define IsJunction(x)           ((x)->flags & FLAGS_JUNCTION)
+#define IsLocOp(x)              ((x)->flags & FLAGS_LOCOP)
+#define IsLocal(x)              ((x)->flags & FLAGS_LOCAL)
+#define IsOper(x)               ((x)->flags & FLAGS_OPER)
+#define IsUPing(x)              ((x)->flags & FLAGS_UPING)
+#define NoNewLine(x)            ((x)->flags & FLAGS_NONL)
+#define SendDebug(x)            ((x)->flags & FLAGS_DEBUG)
+#define SendServNotice(x)       ((x)->flags & FLAGS_SERVNOTICE)
+#define SendWallops(x)          ((x)->flags & FLAGS_WALLOP)
+
+#define IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
+
+#define SetAccess(x)            ((x)->flags |= FLAGS_CHKACCESS)
+#define SetBurst(x)             ((x)->flags |= FLAGS_BURST)
+#define SetBurstAck(x)          ((x)->flags |= FLAGS_BURST_ACK)
+#define SetChannelService(x)    ((x)->flags |= FLAGS_CHSERV)
+#define SetDeaf(x)              ((x)->flags |= FLAGS_DEAF)
+#define SetDebug(x)             ((x)->flags |= FLAGS_DEBUG)
+#define SetGotId(x)             ((x)->flags |= FLAGS_GOTID)
+#define SetIPChecked(x)         ((x)->flags |= FLAGS_IPCHECK)
+#define SetInvisible(x)         ((x)->flags |= FLAGS_INVISIBLE)
+#define SetJunction(x)          ((x)->flags |= FLAGS_JUNCTION)
+#define SetLocOp(x)             ((x)->flags |= FLAGS_LOCOP)
+#define SetOper(x)              ((x)->flags |= FLAGS_OPER)
+#define SetUPing(x)             ((x)->flags |= FLAGS_UPING)
+#define SetWallops(x)           ((x)->flags |= FLAGS_WALLOP)
+
+#define ClearAccess(x)          ((x)->flags &= ~FLAGS_CHKACCESS)
+#define ClearBurst(x)           ((x)->flags &= ~FLAGS_BURST)
+#define ClearBurstAck(x)        ((x)->flags &= ~FLAGS_BURST_ACK)
+#define ClearChannelService(x)  ((x)->flags &= ~FLAGS_CHSERV)
+#define ClearDeaf(x)            ((x)->flags &= ~FLAGS_DEAF)
+#define ClearDebug(x)           ((x)->flags &= ~FLAGS_DEBUG)
+#define ClearIPChecked(x)       ((x)->flags &= ~FLAGS_IPCHECK)
+#define ClearInvisible(x)       ((x)->flags &= ~FLAGS_INVISIBLE)
+#define ClearLocOp(x)           ((x)->flags &= ~FLAGS_LOCOP)
+#define ClearOper(x)            ((x)->flags &= ~FLAGS_OPER)
+#define ClearUPing(x)           ((x)->flags &= ~FLAGS_UPING)
+#define ClearWallops(x)         ((x)->flags &= ~FLAGS_WALLOP)
+
+/* server notice stuff */
+
+#define SNO_ADD         1
+#define SNO_DEL         2
+#define SNO_SET         3
+                                /* DON'T CHANGE THESE VALUES ! */
+                                /* THE CLIENTS DEPEND ON IT  ! */
+#define SNO_OLDSNO      0x1     /* unsorted old messages */
+#define SNO_SERVKILL    0x2     /* server kills (nick collisions) */
+#define SNO_OPERKILL    0x4     /* oper kills */
+#define SNO_HACK2       0x8     /* desyncs */
+#define SNO_HACK3       0x10    /* temporary desyncs */
+#define SNO_UNAUTH      0x20    /* unauthorized connections */
+#define SNO_TCPCOMMON   0x40    /* common TCP or socket errors */
+#define SNO_TOOMANY     0x80    /* too many connections */
+#define SNO_HACK4       0x100   /* Uworld actions on channels */
+#define SNO_GLINE       0x200   /* glines */
+#define SNO_NETWORK     0x400   /* net join/break, etc */
+#define SNO_IPMISMATCH  0x800   /* IP mismatches */
+#define SNO_THROTTLE    0x1000  /* host throttle add/remove notices */
+#define SNO_OLDREALOP   0x2000  /* old oper-only messages */
+#define SNO_CONNEXIT    0x4000  /* client connect/exit (ugh) */
+
+#define SNO_ALL         0x7fff  /* Don't make it larger then significant,
+                                 * that looks nicer */
+
+#define SNO_USER        (SNO_ALL & ~SNO_OPER)
+
+#define SNO_DEFAULT (SNO_NETWORK|SNO_OPERKILL|SNO_GLINE)
+#define SNO_OPERDEFAULT (SNO_DEFAULT|SNO_HACK2|SNO_HACK4|SNO_THROTTLE|SNO_OLDSNO)
+#define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP)
+#define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH)
+
+typedef enum ShowIPType {
+  HIDE_IP,
+  SHOW_IP,
+  MASK_IP
+} ShowIPType;
+
+extern const char* get_client_name(const struct Client* sptr, int showip);
+
+
+#endif /* INCLUDED_client_h */
+
diff --git a/include/common.h b/include/common.h
deleted file mode 100644 (file)
index beff780..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * IRC - Internet Relay Chat, include/common.h
- * Copyright (C) 1998 Andrea Cocito
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /*
-    All the code in common.h/common.c is taken from the NTL
-    (Nemesi's Tools Library), adapted for ircu's character set 
-    and thereafter released under GNU GPL, from there comes the
-    NTL_ prefix of all macro and object names.
-    Removed isXdigit() to leave space to other char sets in the
-    bitmap, should give the same results as isxdigit() on any
-    implementation and isn't used in IRC anyway.
-  */
-
-#ifndef COMMON_H
-#define COMMON_H
-
-/*=============================================================================
- * System's headers needed in this header file
- */
-
-#include "sys.h"
-#include <limits.h>
-
-/*=============================================================================
- * Macros and constants for internal use, 
- * WARNING: match.c depends on these macros, don't change them
- *          without looking at that part of the code too !
- */
-
-#define NTL_ALNUM 0x0001       /*    (NTL_ALPHA|NTL_DIGIT)               */
-#define NTL_ALPHA 0x0002       /*    (NTL_LOWER|NTL_UPPER)               */
-#define NTL_CNTRL 0x0004       /*    \000 - \037 == 0x00 - 0x1F          */
-#define NTL_DIGIT 0x0008       /*    0123456789                          */
-#define NTL_GRAPH 0x0010       /*    (NTL_ALNUM|NTL_PUNCT)               */
-#define NTL_LOWER 0x0020       /*    abcdefghijklmnopqrstuvwxyz{|}~      */
-#define NTL_PRINT 0x0040       /*    (NTL_GRAPH|' ')                     */
-#define NTL_PUNCT 0x0080       /*    !"#$%&'()*+,-./:;<=>?@_`            */
-#define NTL_SPACE 0x0100       /*    \011\012\013\014\015\040            */
-#define NTL_UPPER 0x0200       /*    ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^      */
-#define NTL_IRCCH 0x0400       /*    Channel's names charset             */
-#define NTL_IRCCL 0x0800       /*    Force toLower() in ch-name          */
-#define NTL_IRCNK 0x1000       /*    Nick names charset, aka isvalid()   */
-#define NTL_IRCUI 0x2000       /*    UserIDs charset, IRCHN plus tilde   */
-#define NTL_IRCHN 0x4000       /*    Hostnames charset (weak, RFC 1033)  */
-#define NTL_IRCIP 0x8000       /*    Numeric IPs charset (DIGIT and .)   */
-#define NTL_EOL  0x10000       /*    \r\n                                */
-
-/*=============================================================================
- * Structures
- */
-
-/*=============================================================================
- * Externally visible function-like macros
- */
-
-#define DupString(x, y)   (strcpy((x = (char *)RunMalloc(strlen(y) + 1)), y))
-
-#define toLower(c)        (NTL_tolower_tab[(c)-CHAR_MIN])
-#define toUpper(c)        (NTL_toupper_tab[(c)-CHAR_MIN])
-
-/* Char classification pseudo-functions, when others are needed add them */
-#define isAlnum(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_ALNUM)
-#define isAlpha(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_ALPHA)
-#define isDigit(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_DIGIT)
-#define isLower(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_LOWER)
-#define isSpace(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_SPACE)
-#define isUpper(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_UPPER)
-#define isCntrl(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_CNTRL)
-
-#define isIrcCh(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_IRCCH)
-#define isIrcCl(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_IRCCL)
-#define isIrcNk(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_IRCNK)
-#define isIrcUi(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_IRCUI)
-#define isIrcHn(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_IRCHN)
-#define isIrcIp(c)        (NTL_char_attrib[(c)-CHAR_MIN] & NTL_IRCIP)
-#define isEol(c)          (NTL_char_attrib[(c)-CHAR_MIN] & NTL_EOL)
-
-/* String classification pseudo-functions, when others are needed add them,
-   strIsXxxxx(s) is true when IsXxxxx(c) is true for every char in s */
-
-#define strIsAlnum(s)     (strChattr(s) & NTL_ALNUM)
-#define strIsAlpha(s)     (strChattr(s) & NTL_ALPHA)
-#define strIsDigit(s)     (strChattr(s) & NTL_DIGIT)
-#define strIsLower(s)     (strChattr(s) & NTL_LOWER)
-#define strIsSpace(s)     (strChattr(s) & NTL_SPACE)
-#define strIsUpper(s)     (strChattr(s) & NTL_UPPER)
-
-#define strIsIrcCh(s)     (strChattr(s) & NTL_IRCCH)
-#define strIsIrcCl(s)     (strChattr(s) & NTL_IRCCL)
-#define strIsIrcNk(s)     (strChattr(s) & NTL_IRCNK)
-#define strIsIrcUi(s)     (strChattr(s) & NTL_IRCUI)
-#define strIsIrcHn(s)     (strChattr(s) & NTL_IRCHN)
-#define strIsIrcIp(s)     (strChattr(s) & NTL_IRCIP)
-
-/*=============================================================================
- * Externally visible static memory stuff
- */
-#ifdef MAKETABLES
-extern char NTL_tolower_tab[]; /* 256 bytes */
-extern char NTL_toupper_tab[]; /* 256 bytes */
-extern unsigned int NTL_char_attrib[]; /* 256 ints = 0.5 to 2 kilobytes */
-#else
-extern const char NTL_tolower_tab[];   /* 256 bytes */
-extern const char NTL_toupper_tab[];   /* 256 bytes */
-extern const unsigned int NTL_char_attrib[];   /* 256 ints = 0.5 to 2 kilobytes */
-#endif
-
-/*=============================================================================
- * Critical small functions to inline even in separate compilation
- * when FORCEINLINE is defined (provided you have a compiler that supports
- * `inline').
- */
-
-#define NTL_HDR_strChattr   int strChattr(const char *s)
-
-#define NTL_SRC_strChattr   register const char *rs = s; \
-                            register int x = ~0; \
-                            while(*rs) \
-                              x &= NTL_char_attrib[*rs++ - CHAR_MIN]; \
-                            return x;
-
-#define NTL_HDR_strCasediff int strCasediff(const char *a, const char *b)
-
-#define NTL_SRC_strCasediff register const char *ra = a; \
-                            register const char *rb = b; \
-                            while(toLower(*ra) == toLower(*rb++)) \
-                              if(!*ra++) \
-                                return 0; \
-                            return 1;
-
-#ifndef FORCEINLINE
-extern NTL_HDR_strChattr;
-extern NTL_HDR_strCasediff;
-#else /* FORCEINLINE */
-/* *INDENT-OFF* */
-#ifdef __cplusplus
-inline NTL_HDR_strChattr { NTL_SRC_strChattr }
-inline NTL_HDR_strCasediff { NTL_SRC_strCasediff }
-#else
-static __inline__ NTL_HDR_strChattr { NTL_SRC_strChattr }
-static __inline__ NTL_HDR_strCasediff { NTL_SRC_strCasediff }
-#endif
-/* *INDENT-ON* */
-#endif /* FORCEINLINE */
-
-/*=============================================================================
- * Proto types of other externally visible functions
- */
-
-extern int strnChattr(const char *s, const size_t n);
-extern int strCasecmp(const char *a, const char *b);
-extern int strnCasecmp(const char *a, const char *b, const size_t n);
-
-#endif /* COMMON_H */
index d436378b279bf79af6b421a6c0bf3461797de896..38a7a89d0ffa0b95883a12dd44bf139ca688f11c 100644 (file)
@@ -1,7 +1,12 @@
-#ifndef CRULE_H
-#define CRULE_H
+/*
+ * crule.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_crule_h
+#define INCLUDED_crule_h
 
-/*=============================================================================
+/*
  * Proto types
  */
 
@@ -9,4 +14,4 @@ extern void crule_free(char **elem);
 extern int crule_eval(char *rule);
 extern char *crule_parse(char *rule);
 
-#endif /* CRULE_H */
+#endif /* INCLUDED_crule_h */
index 03b45d1e0efe0d574e4da70986869bac33bb003b..570d500d6ff885d36cc74ee8890cec43cff41046 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
 #ifndef INCLUDED_dbuf_h
 #define INCLUDED_dbuf_h
 #ifndef INCLUDED_sys_types_h
-#include <sys/types.h>         /* size_t */
+#include <sys/types.h>          /* size_t */
 #define INCLUDED_sys_types_h
 #endif
 
 /*
  * These two globals should be considered read only
  */
-extern int DBufAllocCount;     /* GLOBAL - count of dbufs allocated */
-extern int DBufUsedCount;      /* GLOBAL - count of dbufs in use */
+extern int DBufAllocCount;      /* GLOBAL - count of dbufs allocated */
+extern int DBufUsedCount;       /* GLOBAL - count of dbufs in use */
 
 struct DBufBuffer;
 
 struct DBuf {
-  size_t length;               /* Current number of bytes stored */
-  struct DBufBuffer *head;     /* First data buffer, if length > 0 */
-  struct DBufBuffer *tail;     /* last data buffer, if length > 0 */
+  size_t length;                /* Current number of bytes stored */
+  struct DBufBuffer *head;      /* First data buffer, if length > 0 */
+  struct DBufBuffer *tail;      /* last data buffer, if length > 0 */
 };
 
 /*
diff --git a/include/fda.h b/include/fda.h
new file mode 100644 (file)
index 0000000..51022eb
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * fda.c - Free Debug Allocator
+ * Copyright (C) 1997 Thomas Helvey <tomh@inxpress.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef INCLUDED_fda_h
+#define INCLUDED_fda_h
+
+#if !defined(NDEBUG)
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>      /* size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern size_t fda_get_byte_count(void);
+extern size_t fda_get_block_count(void);
+extern size_t fda_sizeof(const void* p);
+extern void   fda_clear_refs(void);
+extern void   fda_set_ref(const void* p);
+extern void   fda_assert_refs(void);
+extern int    fda_enum_locations(void (*enumfn)(const char*, int, int));
+extern int    fda_enum_leaks(void (*enumfn)(const char*, int, size_t, void*));
+extern void   fda_dump_hash(void (*enumfn)(int, int));
+extern void   fda_set_byte_limit(size_t nbytes);
+extern int    valid_ptr(const void* p, size_t size);
+
+extern void* fda_malloc(size_t size, const char* file, int line);
+extern void* fda_realloc(void* p, size_t size, const char* file, int line);
+extern void* fda_calloc(size_t nelems, size_t size, const char* file, int line);
+extern char* fda_strdup(const char* src, const char* file, int line);
+extern void  fda_free(void* p);
+
+#if defined(FDA_REDEFINE_MALLOC)
+#define malloc(s)     fda_malloc((s), __FILE__, __LINE__)
+#define realloc(p, s) fda_realloc((p), (s), __FILE__, __LINE__)
+#define calloc(n, s)  fda_calloc((n), (s), __FILE__, __LINE__)
+#define strdup(s)     fda_strdup((s), __FILE__, __LINE__)
+#define free(p)       fda_free((p))
+#endif
+
+extern void fda_set_lowmem_handler(void (*fn)(void));
+extern void fda_set_nomem_handler(void (*fn)(void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined(NDEBUG) */
+#endif /* INCLUDED_fda_h */
index ad7ad7a4340ac98b9adc4d3c0c175b48912cc70e..f3c5300079183b3d23944fc4345b2aa2ee5cc6e4 100644 (file)
@@ -1,14 +1,17 @@
+/*
+ * fileio.h
+ *
+ * $Id$
+ */
 #ifndef INCLUDED_fileio_h
 #define INCLUDED_fileio_h
 
 #ifndef INCLUDED_sys_types_h
-#include <sys/types.h>         /* size_t */
+#include <sys/types.h>          /* size_t */
 #define INCLUDED_sys_types_h
 #endif
-#ifndef INCLUDED_sys_stat_h
-#include <sys/stat.h>          /* struct stat */
-#define INCLUDED_sys_stat_h
-#endif
+
+struct stat;
 
 /*
  * FileBuf is a mirror of the ANSI FILE struct, but it works for any
diff --git a/include/gline.h b/include/gline.h
new file mode 100644 (file)
index 0000000..3e709a1
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef INCLUDED_gline_h
+#define INCLUDED_gline_h
+/*
+ * IRC - Internet Relay Chat, include/gline.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ * Copyright (C) 1996 -1997 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+
+struct Client;
+
+/*
+ * gflags
+ */
+#define GLINE_ACTIVE    1
+#define GLINE_IPMASK    2
+#define GLINE_LOCAL     4
+
+#define GlineIsActive(g)    ((g)->gflags & GLINE_ACTIVE)
+#define GlineIsIpMask(g)    ((g)->gflags & GLINE_IPMASK)
+#define GlineIsLocal(g)     ((g)->gflags & GLINE_LOCAL)
+
+#define SetActive(g)        ((g)->gflags |= GLINE_ACTIVE)
+#define ClearActive(g)      ((g)->gflags &= ~GLINE_ACTIVE)
+#define SetGlineIsIpMask(g) ((g)->gflags |= GLINE_IPMASK)
+#define SetGlineIsLocal(g)  ((g)->gflags |= GLINE_LOCAL)
+
+struct Gline {
+  struct Gline*  next;
+  struct Gline*  prev;
+  char*          host;
+  char*          reason;
+  char*          name;
+  time_t         expire;
+  unsigned int   gflags;
+};
+
+extern struct Gline* GlobalGlineList;
+extern struct Gline* BadChanGlineList;
+
+extern void gline_remove_expired(time_t now);
+
+extern void add_gline(struct Client *sptr, int ip_mask,
+                      char *host, char *comment, char *user,
+                      time_t expire, int local);
+extern struct Gline* make_gline(int is_ipmask, char *host, char *reason,
+                                char *name, time_t expire);
+extern struct Gline* find_gline(struct Client *cptr, struct Gline **pgline);
+extern void free_gline(struct Gline *gline, struct Gline *prev);
+
+#ifdef BADCHAN
+extern int bad_channel(const char* name);
+extern void bad_channel_remove_expired(time_t now);
+#endif
+
+#endif /* INCLUDED_gline_h */
diff --git a/include/h.h b/include/h.h
deleted file mode 100644 (file)
index c8d9f95..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * IRC - Internet Relay Chat, include/h.h
- * Copyright (C) 1996 - 1997 Carlo Wood
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef H_H
-#define H_H
-
-/* Typedefs */
-
-typedef struct Client aClient;
-typedef struct Server aServer;
-typedef struct User anUser;
-typedef struct Channel aChannel;
-typedef struct SMode Mode;
-typedef struct ConfItem aConfItem;
-typedef struct Message aMessage;
-typedef struct MessageTree aMessageTree;
-typedef struct Gline aGline;
-typedef struct ListingArgs aListingArgs;
-typedef struct MotdItem aMotdItem;
-typedef struct trecord atrecord;
-typedef unsigned int snomask_t;
-typedef struct ConfClass aConfClass;
-typedef struct hashentry aHashEntry;
-typedef struct SLink Link;
-typedef struct DSlink Dlink;
-typedef struct Whowas aWhowas;
-
-#include "s_debug.h"
-
-#endif /* H_H */
diff --git a/include/handlers.h b/include/handlers.h
new file mode 100644 (file)
index 0000000..c032b16
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * IRC - Internet Relay Chat, include/handlers.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_handlers_h
+#define INCLUDED_handlers_h
+
+/*
+ * m_functions execute protocol messages on this server:
+ * int m_func(struct Client* cptr, struct Client* sptr, int parc, char* parv[]);
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+struct Client;
+
+
+extern int m_admin(struct Client*, struct Client*, int, char*[]);
+extern int m_away(struct Client*, struct Client*, int, char*[]);
+extern int m_cnotice(struct Client*, struct Client*, int, char*[]);
+extern int m_cprivmsg(struct Client*, struct Client*, int, char*[]);
+extern int m_help(struct Client*, struct Client*, int, char*[]);
+extern int m_ignore(struct Client*, struct Client*, int, char*[]);
+extern int m_info(struct Client*, struct Client*, int, char*[]);
+extern int m_invite(struct Client*, struct Client*, int, char*[]);
+extern int m_ison(struct Client*, struct Client*, int, char*[]);
+extern int m_join(struct Client*, struct Client*, int, char*[]);
+extern int m_kick(struct Client*, struct Client*, int, char*[]);
+extern int m_links(struct Client*, struct Client*, int, char*[]);
+extern int m_list(struct Client*, struct Client*, int, char*[]);
+extern int m_lusers(struct Client*, struct Client*, int, char*[]);
+extern int m_map(struct Client*, struct Client*, int, char*[]);
+extern int m_mode(struct Client*, struct Client*, int, char*[]);
+extern int m_motd(struct Client*, struct Client*, int, char*[]);
+extern int m_names(struct Client*, struct Client*, int, char*[]);
+extern int m_nick(struct Client*, struct Client*, int, char*[]);
+extern int m_not_oper(struct Client*, struct Client*, int, char*[]);
+extern int m_notice(struct Client*, struct Client*, int, char*[]);
+extern int m_notice(struct Client*, struct Client*, int, char*[]);
+extern int m_oper(struct Client*, struct Client*, int, char*[]);
+extern int m_part(struct Client*, struct Client*, int, char*[]);
+extern int m_pass(struct Client*, struct Client*, int, char*[]);
+extern int m_ping(struct Client*, struct Client*, int, char*[]);
+extern int m_pong(struct Client*, struct Client*, int, char*[]);
+extern int m_private(struct Client*, struct Client*, int, char*[]);
+extern int m_privmsg(struct Client*, struct Client*, int, char*[]);
+extern int m_proto(struct Client*, struct Client*, int, char*[]);
+extern int m_quit(struct Client*, struct Client*, int, char*[]);
+extern int m_registered(struct Client*, struct Client*, int, char*[]);
+extern int m_silence(struct Client*, struct Client*, int, char*[]);
+extern int m_stats(struct Client*, struct Client*, int, char*[]);
+extern int m_time(struct Client*, struct Client*, int, char*[]);
+extern int m_topic(struct Client*, struct Client*, int, char*[]);
+extern int m_trace(struct Client*, struct Client*, int, char*[]);
+extern int m_unregistered(struct Client*, struct Client*, int, char*[]);
+extern int m_unsupported(struct Client*, struct Client*, int, char*[]);
+extern int m_user(struct Client*, struct Client*, int, char*[]);
+extern int m_userhost(struct Client*, struct Client*, int, char*[]);
+extern int m_userip(struct Client*, struct Client*, int, char*[]);
+extern int m_version(struct Client*, struct Client*, int, char*[]);
+extern int m_wallchops(struct Client*, struct Client*, int, char*[]);
+extern int m_who(struct Client*, struct Client*, int, char*[]);
+extern int m_whois(struct Client*, struct Client*, int, char*[]);
+extern int m_whowas(struct Client*, struct Client*, int, char*[]);
+extern int mo_close(struct Client*, struct Client*, int, char*[]);
+extern int mo_connect(struct Client*, struct Client*, int, char*[]);
+extern int mo_die(struct Client*, struct Client*, int, char*[]);
+extern int mo_gline(struct Client*, struct Client*, int, char*[]);
+extern int mo_info(struct Client*, struct Client*, int, char*[]);
+extern int mo_kill(struct Client*, struct Client*, int, char*[]);
+extern int mo_notice(struct Client*, struct Client*, int, char*[]);
+extern int mo_oper(struct Client*, struct Client*, int, char*[]);
+extern int mo_privmsg(struct Client*, struct Client*, int, char*[]);
+extern int mo_rehash(struct Client*, struct Client*, int, char*[]);
+extern int mo_restart(struct Client*, struct Client*, int, char*[]);
+extern int mo_rping(struct Client*, struct Client*, int, char*[]);
+extern int mo_settime(struct Client*, struct Client*, int, char*[]);
+extern int mo_squit(struct Client*, struct Client*, int, char*[]);
+extern int mo_stats(struct Client*, struct Client*, int, char*[]);
+extern int mo_trace(struct Client*, struct Client*, int, char*[]);
+extern int mo_wallops(struct Client*, struct Client*, int, char*[]);
+extern int mr_error(struct Client*, struct Client*, int, char*[]);
+extern int mr_pong(struct Client*, struct Client*, int, char*[]);
+extern int mr_server(struct Client*, struct Client*, int, char*[]);
+extern int ms_admin(struct Client*, struct Client*, int, char*[]);
+extern int ms_away(struct Client*, struct Client*, int, char*[]);
+extern int ms_burst(struct Client*, struct Client*, int, char*[]);
+extern int ms_connect(struct Client*, struct Client*, int, char*[]);
+extern int ms_create(struct Client*, struct Client*, int, char*[]);
+extern int ms_destruct(struct Client*, struct Client*, int, char*[]);
+extern int ms_desynch(struct Client*, struct Client*, int, char*[]);
+extern int ms_end_of_burst(struct Client*, struct Client*, int, char*[]);
+extern int ms_end_of_burst_ack(struct Client*, struct Client*, int, char*[]);
+extern int ms_error(struct Client*, struct Client*, int, char*[]);
+extern int ms_gline(struct Client*, struct Client*, int, char*[]);
+extern int ms_info(struct Client*, struct Client*, int, char*[]);
+extern int ms_invite(struct Client*, struct Client*, int, char*[]);
+extern int ms_join(struct Client*, struct Client*, int, char*[]);
+extern int ms_kick(struct Client*, struct Client*, int, char*[]);
+extern int ms_kill(struct Client*, struct Client*, int, char*[]);
+extern int ms_links(struct Client*, struct Client*, int, char*[]);
+extern int ms_lusers(struct Client*, struct Client*, int, char*[]);
+extern int ms_mode(struct Client*, struct Client*, int, char*[]);
+extern int ms_motd(struct Client*, struct Client*, int, char*[]);
+extern int ms_names(struct Client*, struct Client*, int, char*[]);
+extern int ms_nick(struct Client*, struct Client*, int, char*[]);
+extern int ms_notice(struct Client*, struct Client*, int, char*[]);
+extern int ms_oper(struct Client*, struct Client*, int, char*[]);
+extern int ms_part(struct Client*, struct Client*, int, char*[]);
+extern int ms_ping(struct Client*, struct Client*, int, char*[]);
+extern int ms_pong(struct Client*, struct Client*, int, char*[]);
+extern int ms_privmsg(struct Client*, struct Client*, int, char*[]);
+extern int ms_quit(struct Client*, struct Client*, int, char*[]);
+extern int ms_rping(struct Client*, struct Client*, int, char*[]);
+extern int ms_rpong(struct Client*, struct Client*, int, char*[]);
+extern int ms_server(struct Client*, struct Client*, int, char*[]);
+extern int ms_settime(struct Client*, struct Client*, int, char*[]);
+extern int ms_silence(struct Client*, struct Client*, int, char*[]);
+extern int ms_squit(struct Client*, struct Client*, int, char*[]);
+extern int ms_stats(struct Client*, struct Client*, int, char*[]);
+extern int ms_topic(struct Client*, struct Client*, int, char*[]);
+extern int ms_trace(struct Client*, struct Client*, int, char*[]);
+extern int ms_version(struct Client*, struct Client*, int, char*[]);
+extern int ms_wallchops(struct Client*, struct Client*, int, char*[]);
+extern int ms_wallops(struct Client*, struct Client*, int, char*[]);
+
+
+#endif /* INCLUDED_handlers_h */
+
index 47149bbddf9365f9d901636cbb74f855ddef61b8..79f882774fc5a96445cbc259f251bc98b2ef01d8 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
 
-#ifndef HASH_H
-#define HASH_H
+#ifndef INCLUDED_hash_h
+#define INCLUDED_hash_h
 
-#include "s_serv.h"            /* For STAT_* values and StatusMask() macro */
+struct Client;
+struct Channel;
 
-/*=============================================================================
+/*
  * general defines
  */
 
 /* Now client and channel hash table must be of the same size */
-#define HASHSIZE               32000
+#define HASHSIZE                32000
 
-/*=============================================================================
+/*
  * Structures
  */
 
-/*=============================================================================
+/*
  * Macros for internal use
  */
 
-/*=============================================================================
+/*
  * Externally visible pseudofunctions (macro interface to internal functions)
  */
 
 /* Raw calls, expect a core if you pass a NULL or zero-length name */
-#define SeekChannel(name)      hSeekChannel((name))
-#define SeekClient(name)       hSeekClient((name), ~StatusMask(STAT_PING))
-#define SeekUser(name)         hSeekClient((name), StatusMask(STAT_USER))
-#define SeekServer(name)       hSeekClient((name), StatusMask(STAT_ME) | \
-                                                    StatusMask(STAT_SERVER) )
+#define SeekChannel(name)       hSeekChannel((name))
+#define SeekClient(name)        hSeekClient((name), ~0)
+#define SeekUser(name)          hSeekClient((name), (STAT_USER))
+#define SeekServer(name)        hSeekClient((name), (STAT_ME | STAT_SERVER))
 
 /* Safer macros with sanity check on name, WARNING: these are _macros_,
    no side effects allowed on <name> ! */
-#define FindChannel(name)      (BadPtr((name))?NULL:SeekChannel(name))
-#define FindClient(name)       (BadPtr((name))?NULL:SeekClient(name))
-#define FindUser(name)         (BadPtr((name))?NULL:SeekUser(name))
-#define FindServer(name)       (BadPtr((name))?NULL:SeekServer(name))
+#define FindChannel(name)       (BadPtr((name)) ? 0 : SeekChannel(name))
+#define FindClient(name)        (BadPtr((name)) ? 0 : SeekClient(name))
+#define FindUser(name)          (BadPtr((name)) ? 0 : SeekUser(name))
+#define FindServer(name)        (BadPtr((name)) ? 0 : SeekServer(name))
 
-/*=============================================================================
+/*
  * Proto types
  */
 
-extern void hash_init(void);   /* Call me on startup */
-extern int hAddClient(aClient *cptr);
-extern int hAddChannel(aChannel *chptr);
-extern int hRemClient(aClient *cptr);
-extern int hChangeClient(aClient *cptr, char *newname);
-extern int hRemChannel(aChannel *chptr);
-extern aClient *hSeekClient(char *name, int TMask);
-extern aChannel *hSeekChannel(char *name);
+extern void hash_init(void);    /* Call me on startup */
+extern int hAddClient(struct Client *cptr);
+extern int hAddChannel(struct Channel *chptr);
+extern int hRemClient(struct Client *cptr);
+extern int hChangeClient(struct Client *cptr, const char *newname);
+extern int hRemChannel(struct Channel *chptr);
+extern struct Client *hSeekClient(const char *name, int TMask);
+extern struct Channel *hSeekChannel(const char *name);
 
-extern int m_hash(aClient *cptr, aClient *sptr, int parc, char *parv[]);
+extern int m_hash(struct Client *cptr, struct Client *sptr, int parc, char *parv[]);
 
-extern int isNickJuped(char *nick);
-extern int addNickJupes(char *nicks);
+extern int isNickJuped(const char *nick);
+extern int addNickJupes(const char *nicks);
 extern void clearNickJupes(void);
 
-#endif /* HASH_H */
+#endif /* INCLUDED_hash_h */
index f9340434fa52672e4564936bf6fdedc8a0e59396..950c07388c94e48ea6298862925245737dad74ff 100644 (file)
@@ -1,54 +1,61 @@
-#ifndef IRCD_H
-#define IRCD_H
-
-/*=============================================================================
- * Macro's
+/*
+ * ircd.h
+ *
+ * $Id$
  */
+#ifndef INCLUDED_ircd_h
+#define INCLUDED_ircd_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_struct_h
+#include "struct.h"           /* struct Client */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>        /* size_t, time_t */
+#endif
 
-#define TStime() (now + TSoffset)
+
+/*
+ * Macros
+ */
+#define TStime() (CurrentTime + TSoffset)
+#define OLDEST_TS 780000000    /* Any TS older than this is bogus */
 #define BadPtr(x) (!(x) || (*(x) == '\0'))
 
 /* Miscellaneous defines */
 
-#define UDP_PORT       "7007"
-#define MINOR_PROTOCOL "09"
-#define MAJOR_PROTOCOL "10"
-#define BASE_VERSION   "u2.10"
+#define UDP_PORT        "7007"
+#define MINOR_PROTOCOL  "09"
+#define MAJOR_PROTOCOL  "10"
+#define BASE_VERSION    "u2.10"
 
 /* Flags for bootup options (command line flags) */
 
-#define BOOT_CONSOLE   1
-#define BOOT_QUICK     2
-#define BOOT_DEBUG     4
-#define BOOT_INETD     8
-#define BOOT_TTY       16
-#define BOOT_AUTODIE   32
+#define BOOT_QUICK  1
+#define BOOT_DEBUG  2
+#define BOOT_TTY    4
 
-/*=============================================================================
+/*
  * Proto types
  */
 
-#ifdef PROFIL
-extern RETSIGTYPE s_monitor(HANDLER_ARG(int sig));
-#endif
-extern RETSIGTYPE s_die(HANDLER_ARG(int sig));
-extern RETSIGTYPE s_restart(HANDLER_ARG(int sig));
-
-extern void restart(char *mesg);
-extern void server_reboot(void);
-
-extern aClient me;
-extern time_t now;
-extern aClient *client;
-extern time_t TSoffset;
-extern unsigned int bootopt;
-extern time_t nextdnscheck;
-extern time_t nextconnect;
-extern int dorehash;
-extern time_t nextping;
-extern unsigned short int portnum;
-extern char *configfile;
-extern int debuglevel;
-extern char *debugmode;
-
-#endif /* IRCD_H */
+extern void server_die(const char* message);
+extern void server_restart(const char* message);
+
+extern struct Client  me;
+extern time_t         CurrentTime;
+extern struct Client* GlobalClientList;
+extern time_t         TSoffset;
+extern unsigned int   bootopt;
+extern time_t         nextdnscheck;
+extern time_t         nextconnect;
+extern int            GlobalRehashFlag;      /* 1 if SIGHUP is received */
+extern int            GlobalRestartFlag;     /* 1 if SIGINT is received */
+extern time_t         nextping;
+extern char*          configfile;
+extern int            debuglevel;
+extern char*          debugmode;
+
+#endif /* INCLUDED_ircd_h */
+
diff --git a/include/ircd_alloc.h b/include/ircd_alloc.h
new file mode 100644 (file)
index 0000000..9960293
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_alloc.h
+ * Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
+ *                   
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Commentary by Bleep (Thomas Helvey)
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_alloc_h
+#define INCLUDED_ircd_alloc_h
+
+/*
+ * memory resource allocation and test functions
+ */
+typedef void (*OutOfMemoryHandler)(void);
+extern void set_nomem_handler(OutOfMemoryHandler handler);
+
+#if defined(NDEBUG)
+/* 
+ * RELEASE: allocation functions
+ */
+#ifndef INCLUDED_stdlib_h
+#include <stdlib.h>       /* free */
+#define INCLUDED_stdlib_h
+#endif
+
+#define MyFree(x) do { free((x)); (x) = 0; } while(0)
+
+extern void* MyMalloc(size_t size);
+extern void* MyCalloc(size_t nelem, size_t size);
+extern void* MyRealloc(void* p, size_t size);
+
+#else /* !defined(NDEBUG) */
+/*
+ * DEBUG: allocation functions
+ */
+#ifndef INCLUDED_fda_h
+#include "fda.h"
+#endif
+
+#define MyMalloc(s)     fda_malloc((s), __FILE__, __LINE__)
+#define MyCalloc(n, s)  fda_calloc((n), (s), __FILE__, __LINE__)
+#define MyFree(p)       fda_free((p))
+#define MyRealloc(p, s) fda_realloc((p), (s), __FILE__, __LINE__)
+
+#endif /* !defined(NDEBUG) */
+
+#endif /* INCLUDED_ircd_alloc_h */
+
diff --git a/include/ircd_chattr.h b/include/ircd_chattr.h
new file mode 100644 (file)
index 0000000..3421fb6
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_chattr.h
+ * Copyright (C) 1998 Andrea Cocito
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ */
+/*
+ * All the code in common.h/common.c is taken from the NTL
+ * (Nemesi's Tools Library), adapted for ircu's character set
+ * and thereafter released under GNU GPL, from there comes the
+ * NTL_ prefix of all macro and object names.
+ * Removed isXdigit() to leave space to other char sets in the
+ * bitmap, should give the same results as isxdigit() on any
+ * implementation and isn't used in IRC anyway.
+ */
+#ifndef INCLUDED_ircd_chattr_h
+#define INCLUDED_ircd_chattr_h
+#ifndef INCLUDED_limits_h
+#include <limits.h>
+#define INCLUDED_limits_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+/*
+ * Character attribute macros
+ */
+#define NTL_ALNUM   0x0001  /* (NTL_ALPHA | NTL_DIGIT)             */
+#define NTL_ALPHA   0x0002  /* (NTL_LOWER | NTL_UPPER)             */
+#define NTL_CNTRL   0x0004  /* \000 - \037 == 0x00 - 0x1F          */
+#define NTL_DIGIT   0x0008  /* 0123456789                          */
+#define NTL_GRAPH   0x0010  /* (NTL_ALNUM | NTL_PUNCT)             */
+#define NTL_LOWER   0x0020  /* abcdefghijklmnopqrstuvwxyz{|}~      */
+#define NTL_PRINT   0x0040  /* (NTL_GRAPH | ' ')                   */
+#define NTL_PUNCT   0x0080  /* !"#$%&'()*+,-./:;<=>?@_`            */
+#define NTL_SPACE   0x0100  /* \011\012\013\014\015\040            */
+#define NTL_UPPER   0x0200  /* ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^      */
+#define NTL_IRCCH   0x0400  /* Channel's names charset             */
+#define NTL_IRCCL   0x0800  /* Force toLower() in ch-name          */
+#define NTL_IRCNK   0x1000  /* Nick names charset, aka isvalid()   */
+#define NTL_IRCUI   0x2000  /* UserIDs charset, IRCHN plus tilde   */
+#define NTL_IRCHN   0x4000  /* Hostnames charset (weak, RFC 1033)  */
+#define NTL_IRCIP   0x8000  /* Numeric IPs charset (DIGIT and .)   */
+#define NTL_EOL    0x10000  /* \r\n                                */
+#define NTL_KTIME  0x20000  /* Valid character for a k:line time   */
+#define NTL_CHPFX  0x40000  /* channel prefix char # & +           */
+
+/*
+ * Tables used for translation and classification macros
+ */
+extern const char ToLowerTab_8859_1[];
+extern const char ToUpperTab_8859_1[];
+extern const unsigned int  IRCD_CharAttrTab[];
+
+/*
+ * Translation macros for channel name case translation
+ * NOTE: Channel names are supposed to be lower case insensitive for
+ * ISO 8859-1 character sets.
+ */
+#define ToLower(c)        (ToLowerTab_8859_1[(c) - CHAR_MIN])
+#define ToUpper(c)        (ToUpperTab_8859_1[(c) - CHAR_MIN])
+
+/*
+ * Character classification macros
+ * NOTE: The IsUpper and IsLower macros do not apply to the complete
+ * ISO 8859-1 character set, unlike the ToUpper and ToLower macros above.
+ * IsUpper and IsLower only apply for comparisons of the US ASCII subset.
+ */
+#define IsAlnum(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_ALNUM)
+#define IsAlpha(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_ALPHA)
+#define IsDigit(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_DIGIT)
+#define IsLower(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_LOWER)
+#define IsSpace(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_SPACE)
+#define IsUpper(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_UPPER)
+#define IsCntrl(c)         (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CNTRL)
+
+#define IsChannelChar(c)   (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCCH)
+#define IsChannelLower(c)  (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCCL)
+#define IsChannelPrefix(c) (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_CHPFX)
+#define IsNickChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCNK)
+#define IsUserChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCUI)
+#define IsHostChar(c)      (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCHN)
+#define IsIPChar(c)        (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_IRCIP)
+#define IsEol(c)           (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_EOL)
+#define IsKTimeChar(c)     (IRCD_CharAttrTab[(c) - CHAR_MIN] & NTL_KTIME)
+
+
+#endif /* INCLUDED_ircd_chattr_h */
diff --git a/include/ircd_defs.h b/include/ircd_defs.h
new file mode 100644 (file)
index 0000000..07e05e5
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_defs.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Commentary by Bleep (Thomas Helvey)
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_defs_h
+#define INCLUDED_ircd_defs_h
+/*
+ * Definitions used everywhere in the server
+ * NOTE: Changing any of these definitions is equivalent to a protocol
+ * revision. Every server on a given network must also use the same sizes.
+ */
+
+/*
+ * NICKLEN is the maximum length allowed for a nickname
+ */
+#define NICKLEN         9
+/*
+ * USERLEN is the maximum length allowed of a user name including an optional
+ * leading '~' if the user name has not been authenticated by an auth (RFC 931)
+ * server query.
+ */
+#define USERLEN         10
+/*
+ * HOSTLEN is exactly long enough to hold one (1) segment of FQDN or hostname.
+ * This is due to an historical misinterpretation of RFC 1034.
+ * 3.1. Name space specifications and terminology
+ *
+ * The domain name space is a tree structure.  Each node and leaf on the
+ * tree corresponds to a resource set (which may be empty).  The domain
+ * system makes no distinctions between the uses of the interior nodes and
+ * leaves, and this memo uses the term "node" to refer to both.
+ *
+ * Each node has a label, which is zero to 63 octets in length.  Brother
+ * nodes may not have the same label, although the same label can be used
+ * for nodes which are not brothers.  One label is reserved, and that is
+ * the null (i.e., zero length) label used for the root.
+ *
+ * This has proven not to be a problem in the past as connections with FQDN's
+ * of greater than 63 characters are rejected by the server, and most FQDN's
+ * are shorter. It is possible to have a valid FQDN longer than 63 characters.
+ */
+#define HOSTLEN         63
+/*
+ * REALLEN is the maximum length for user supplied information about a client
+ * connection (gcos). This information is set at client/server registration
+ * time.
+ */
+#define REALLEN         50
+/*
+ * PASSWDLEN is the maximum length for a password used for connecting servers
+ * and clients.
+ */
+#define PASSWDLEN       20
+/*
+ * SOCKIPLEN is the length of a dotted quad ip address "XXX.XXX.XXX.XXX"
+ */
+#define SOCKIPLEN 15
+/*
+ * TOPICLEN is the maximum length for channel topics, kill comments,
+ * and quit comments
+ */
+#define TOPICLEN        160
+/*
+ * BUFSIZE is exactly long enough to hold one protocol message (RFC 1459)
+ * including the line termination (\r\n).
+ */
+#define BUFSIZE         512     /* WARNING: *DONT* CHANGE THIS!!!! */
+
+#define MAXTARGETS      20
+#define STARTTARGETS    10
+#define RESERVEDTARGETS 12
+
+#endif /* INCLUDED_ircd_defs_h */
+
diff --git a/include/ircd_handler.h b/include/ircd_handler.h
new file mode 100644 (file)
index 0000000..6201811
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_handler.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_handler_h
+#define INCLUDED_ircd_handler_h
+
+struct Client;
+
+/*
+ * MessageHandler
+ */
+typedef enum HandlerType {
+  UNREGISTERED_HANDLER,
+  CLIENT_HANDLER,
+  SERVER_HANDLER,
+  OPER_HANDLER,
+  SERVICE_HANDLER,
+  LAST_HANDLER_TYPE
+} HandlerType;
+
+/*
+ * MessageHandler function
+ * Params:
+ * struct Client* cptr   - connection message originated from
+ * struct Client* sptr   - source of message, may be different from cptr
+ * int            parc   - parameter count
+ * char*          parv[] - parameter vector
+ */
+typedef int (*MessageHandler)(struct Client*, struct Client*, int, char*[]);
+
+
+#endif /* INCLUDED_ircd_handler_h */
+
diff --git a/include/ircd_log.h b/include/ircd_log.h
new file mode 100644 (file)
index 0000000..64294b2
--- /dev/null
@@ -0,0 +1,48 @@
+/* - Internet Relay Chat, include/ircd_log.h
+ *   Copyright (C) 1999 Thomas Helvey
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_log_h
+#define INCLUDED_ircd_log_h
+
+struct Client;
+
+enum LogLevel {
+  L_CRIT,
+  L_ERROR,
+  L_WARNING,
+  L_NOTICE,
+  L_TRACE,
+  L_INFO,
+  L_DEBUG,
+  L_LAST_LEVEL
+};
+
+extern void open_log(const char* process_name);
+extern void close_log(void);
+extern void set_log_level(int level);
+extern int  get_log_level(void);
+extern void ircd_log(int priority, const char* fmt, ...);
+
+extern void ircd_log_kill(const struct Client* victim,
+                          const struct Client* killer,
+                          const char*          inpath,
+                          const char*          path);
+
+#endif /* INCLUDED_ircd_log_h */
diff --git a/include/ircd_osdep.h b/include/ircd_osdep.h
new file mode 100644 (file)
index 0000000..db9b023
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * ircd_osdep.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_osdep_h
+#define INCLUDED_ircd_osdep_h
+
+struct Client;
+struct sockaddr_in;
+
+typedef enum IOResult {
+  IO_FAILURE = -1,
+  IO_BLOCKED = 0,
+  IO_SUCCESS = 1
+} IOResult;
+
+/*
+ * NOTE: osdep.c files should never need to know the actual size of a
+ * Client struct. When passed as a parameter, the pointer just needs
+ * to be forwarded to the enumeration function.
+ */
+typedef void (*EnumFn)(struct Client*, const char* msg);
+
+extern int os_disable_options(int fd);
+extern int os_get_rusage(struct Client* cptr, int uptime, EnumFn enumerator);
+extern int os_get_sockerr(int fd);
+extern int os_get_sockname(int fd, struct sockaddr_in* sin_out);
+extern int os_get_peername(int fd, struct sockaddr_in* sin_out);
+extern IOResult os_recv_nonb(int fd, char* buf, unsigned int length,
+                        unsigned int* length_out);
+extern IOResult os_send_nonb(int fd, const char* buf, unsigned int length,
+                        unsigned int* length_out);
+extern IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int len,
+                                 unsigned int* length_out,
+                                 struct sockaddr_in* from_out);
+extern int os_connect_nonb(int fd, const struct sockaddr_in* sin);
+extern int os_set_fdlimit(unsigned int max_descriptors);
+extern int os_set_listen(int fd, int backlog);
+extern int os_set_nonblocking(int fd);
+extern int os_set_reuseaddr(int fd);
+extern int os_set_sockbufs(int fd, unsigned int size);
+
+#endif /* INCLUDED_ircd_osdep_h */
+
diff --git a/include/ircd_relay.h b/include/ircd_relay.h
new file mode 100644 (file)
index 0000000..b34c864
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef INCLUDED_IRCD_RELAY_H
+#define INCLUDED_IRCD_RELAY_H
+/*
+ * IRC - Internet Relay Chat, include/ircd_relay.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+struct Client;
+
+extern void relay_channel_message(struct Client* sptr, const char* name, const char* text);
+extern void relay_channel_notice(struct Client* sptr, const char* name, const char* text);
+extern void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text);
+extern void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text);
+extern void relay_masked_message(struct Client* sptr, const char* mask, const char* text);
+extern void relay_masked_notice(struct Client* sptr, const char* mask, const char* text);
+extern void relay_private_message(struct Client* sptr, const char* name, const char* text);
+extern void relay_private_notice(struct Client* sptr, const char* name, const char* text);
+
+extern void server_relay_channel_message(struct Client* sptr, const char* name, const char* text);
+extern void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text);
+extern void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text);
+extern void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text);
+extern void server_relay_private_message(struct Client* sptr, const char* name, const char* text);
+extern void server_relay_private_notice(struct Client* sptr, const char* name, const char* text);
+
+#endif /* INCLUDED_IRCD_RELAY_H */
diff --git a/include/ircd_reply.h b/include/ircd_reply.h
new file mode 100644 (file)
index 0000000..62e7c51
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * IRC - Internet Relay Chat, include/ircd_reply.h
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_reply_h
+#define INCLUDED_ircd_reply_h
+
+struct Client;
+struct ConfItem;
+
+extern int need_more_params(struct Client* cptr, const char* cmd);
+extern int send_error_to_client(struct Client* cptr, int error, ...);
+extern int send_admin_info(struct Client* sptr, const struct ConfItem* data);
+
+#endif /* INCLUDED_ircd_reply_h */
+
diff --git a/include/ircd_signal.h b/include/ircd_signal.h
new file mode 100644 (file)
index 0000000..fc214fd
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * ircd_signal.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_signal_h
+#define INCLUDED_ircd_signal_h
+
+extern void setup_signals(void);
+
+#endif /* INCLUDED_ircd_signal_h */
+
diff --git a/include/ircd_string.h b/include/ircd_string.h
new file mode 100644 (file)
index 0000000..8056404
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * ircd_string.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_string_h
+#define INCLUDED_ircd_string_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_ircd_chattr_h
+#include "ircd_chattr.h"
+#endif
+
+/*
+ * Macros
+ */
+#define EmptyString(x) (!(x) || !(*x))
+
+extern char*       ircd_strncpy(char* dest, const char* src, size_t len);
+extern int         ircd_strcmp(const char *a, const char *b);
+extern int         ircd_strncmp(const char *a, const char *b, size_t n);
+extern int         unique_name_vector(char* names, char token, char** vector, int size);
+extern int         token_vector(char* names, char token, char** vector, int size);
+extern const char* ircd_ntoa(const char* addr);
+extern const char* ircd_ntoa_r(char* buf, const char* addr);
+extern char*       host_from_uh(char* buf, const char* userhost, size_t len);
+extern char*       ircd_strtok(char** save, char* str, char* fs);
+
+extern char*       sprintf_irc(char* str, const char* format, ...); 
+
+extern char*       canonize(char* buf);
+
+#define DupString(x, y)  (strcpy((x = (char*) MyMalloc(strlen(y) + 1)), y))
+
+
+/* String classification pseudo-functions, when others are needed add them,
+   strIsXxxxx(s) is true when IsXxxxx(c) is true for every char in s */
+
+#define strIsAlnum(s)     (strChattr(s) & NTL_ALNUM)
+#define strIsAlpha(s)     (strChattr(s) & NTL_ALPHA)
+#define strIsDigit(s)     (strChattr(s) & NTL_DIGIT)
+#define strIsLower(s)     (strChattr(s) & NTL_LOWER)
+#define strIsSpace(s)     (strChattr(s) & NTL_SPACE)
+#define strIsUpper(s)     (strChattr(s) & NTL_UPPER)
+
+#define strIsIrcCh(s)     (strChattr(s) & NTL_IRCCH)
+#define strIsIrcCl(s)     (strChattr(s) & NTL_IRCCL)
+#define strIsIrcNk(s)     (strChattr(s) & NTL_IRCNK)
+#define strIsIrcUi(s)     (strChattr(s) & NTL_IRCUI)
+#define strIsIrcHn(s)     (strChattr(s) & NTL_IRCHN)
+#define strIsIrcIp(s)     (strChattr(s) & NTL_IRCIP)
+
+/*
+ * Critical small functions to inline even in separate compilation
+ * when FORCEINLINE is defined (provided you have a compiler that supports
+ * `inline').
+ */
+
+#define NTL_HDR_strChattr   unsigned int strChattr(const char *s)
+
+#define NTL_SRC_strChattr   const char *rs = s; \
+                            unsigned int x = ~0; \
+                            while(*rs) \
+                              x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN]; \
+                            return x;
+
+/*
+ * XXX - bleah should return 1 if different 0 if the same
+ */
+#define NTL_HDR_strCasediff int strCasediff(const char *a, const char *b)
+
+#define NTL_SRC_strCasediff const char *ra = a; \
+                            const char *rb = b; \
+                            while(ToLower(*ra) == ToLower(*rb++)) \
+                              if(!*ra++) \
+                                return 0; \
+                            return 1;
+
+#ifndef FORCEINLINE
+extern NTL_HDR_strChattr;
+extern NTL_HDR_strCasediff;
+
+#else /* FORCEINLINE */
+#ifdef __cplusplus
+inline NTL_HDR_strChattr { NTL_SRC_strChattr }
+inline NTL_HDR_strCasediff { NTL_SRC_strCasediff }
+#else
+static __inline__ NTL_HDR_strChattr { NTL_SRC_strChattr }
+static __inline__ NTL_HDR_strCasediff { NTL_SRC_strCasediff }
+#endif
+#endif /* FORCEINLINE */
+
+/*
+ * Proto types of other externally visible functions
+ */
+extern int strnChattr(const char *s, const size_t n);
+
+#endif /* INCLUDED_ircd_string_h */
+
diff --git a/include/ircd_xopen.h b/include/ircd_xopen.h
new file mode 100644 (file)
index 0000000..3d10488
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * ircd_xopen.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_ircd_xopen_h
+#define INCLUDED_ircd_xopen_h
+
+extern const char* ircd_crypt(const char* key, const char* salt);
+
+#endif /* INCLUDED_ircd_xopen_h */
+
index e1899aa396139b2cd025aa6adcc5114a587c0e54..509de683b419b81a7404318428870bd797e95c3e 100644 (file)
@@ -1,22 +1,27 @@
-#ifndef LIST_H
-#define LIST_H
-
-/*=============================================================================
- * General defines
+/*
+ * list.h
+ *
+ * $Id$
  */
+#ifndef INCLUDED_list_h
+#define INCLUDED_list_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* time_t, size_t */
+#define INCLUDED_sys_types_h
+#endif
 
-/*=============================================================================
- * Macro's
- */
+struct Client;
+struct Channel;
+struct ConfItem;
 
-/* ============================================================================
+/* 
  * Structures
  */
 
 struct SLink {
   struct SLink *next;
   union {
-    aClient *cptr;
+    struct Client *cptr;
     struct Channel *chptr;
     struct ConfItem *aconf;
     char *cp;
@@ -29,45 +34,34 @@ struct SLink {
   unsigned int flags;
 };
 
-struct DSlink {
-  struct DSlink *next;
-  struct DSlink *prev;
+struct DLink {
+  struct DLink*  next;
+  struct DLink*  prev;
   union {
-    aClient *cptr;
-    struct Channel *chptr;
-    struct ConfItem *aconf;
-    char *cp;
+    struct Client*  cptr;
+    struct Channel* chptr;
+    char*           ch;
   } value;
 };
 
-/*=============================================================================
+/*
  * Proto types
  */
 
-extern void free_link(Link *lp);
-extern Link *make_link(void);
-extern Link *find_user_link(Link *lp, aClient *ptr);
-extern void initlists(void);
-extern void outofmemory(void);
-extern aClient *make_client(aClient *from, int status);
-extern void free_client(aClient *cptr);
-extern struct User *make_user(aClient *cptr);
-extern struct Server *make_server(aClient *cptr);
-extern void free_user(struct User *user, aClient *cptr);
-extern void remove_client_from_list(aClient *cptr);
-extern void add_client_to_list(aClient *cptr);
-extern Dlink *add_dlink(Dlink **lpp, aClient *cp);
-extern void remove_dlink(Dlink **lpp, Dlink *lp);
+extern void free_link(struct SLink *lp);
+extern struct SLink *make_link(void);
+extern struct SLink *find_user_link(struct SLink *lp, struct Client *ptr);
+extern void init_list(void);
+extern struct Client *make_client(struct Client *from, int status);
+extern void free_client(struct Client *cptr);
+extern struct Server *make_server(struct Client *cptr);
+extern void remove_client_from_list(struct Client *cptr);
+extern void add_client_to_list(struct Client *cptr);
+extern struct DLink *add_dlink(struct DLink **lpp, struct Client *cp);
+extern void remove_dlink(struct DLink **lpp, struct DLink *lp);
 extern struct ConfItem *make_conf(void);
 extern void delist_conf(struct ConfItem *aconf);
 extern void free_conf(struct ConfItem *aconf);
-extern aGline *make_gline(int is_ipmask, char *host, char *reason, char *name,
-    time_t expire);
-extern aGline *find_gline(aClient *cptr, aGline **pgline);
-extern void free_gline(aGline *agline, aGline *pgline);
-extern void send_listinfo(aClient *cptr, char *name);
-#ifdef BADCHAN
-extern int bad_channel(char *name);
-#endif
+extern void send_listinfo(struct Client *cptr, char *name);
 
-#endif /* LIST_H */
+#endif /* INCLUDED_list_h */
diff --git a/include/listener.h b/include/listener.h
new file mode 100644 (file)
index 0000000..8ba11e7
--- /dev/null
@@ -0,0 +1,67 @@
+/* - Internet Relay Chat, include/listener.h
+ *   Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_listener_h
+#define INCLUDED_listener_h
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"       /* HOSTLEN */
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>       /* size_t, broken BSD system headers */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>      /* in_addr */
+#define INCLUDED_netinet_in_h
+#endif
+
+struct Client;
+
+struct Listener {
+  struct Listener* next;               /* list node pointer */
+  int              fd;                 /* file descriptor */
+  int              port;               /* listener IP port */
+  int              ref_count;          /* number of connection references */
+  unsigned char    active;             /* current state of listener */
+  unsigned char    hidden;             /* hidden in stats output for clients */
+  unsigned char    server;             /* 1 if port is a server listener */
+  int              index;              /* index into poll array */
+  time_t           last_accept;        /* last time listener accepted */
+  struct in_addr   addr;               /* virtual address or INADDR_ANY */
+  struct in_addr   mask;               /* listener hostmask */
+};
+
+extern struct Listener* ListenerPollList; /* GLOBAL - listener list */
+
+extern void        accept_connection(struct Listener* listener);
+extern void        add_listener(int port, const char* vaddr_ip, 
+                                const char* mask, int is_server, 
+                                int is_hidden);
+extern void        close_listener(struct Listener* listener);
+extern void        close_listeners(void);
+extern void        count_listener_memory(int* count_out, size_t* size_out);
+extern const char* get_listener_name(const struct Listener* listener);
+extern void        mark_listeners_closing(void);
+extern void        show_ports(struct Client* client, int show_hidden,
+                              int port, int count);
+extern void        release_listener(struct Listener* listener);
+
+#endif /* INCLUDED_listener_h */
+
index 5d539d787ced3c9a64dcac81cd9777f38c35c379..3b039f2ae47cf8cb7dda313e49acacc261489214 100644 (file)
@@ -1,10 +1,17 @@
-#ifndef MAP_H
-#define MAP_H
+/*
+ * map.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_map_h
+#define INCLUDED_map_h
+
+struct Client;
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern int m_map(aClient *cptr, aClient *sptr, int parc, char *parv[]);
+void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length);
 
-#endif /* MAP_H */
+#endif /* INCLUDED_map_h */
index 7a328a74d1af1fc89dc17725a4603871e30d7c7d..22a95b50b4269720d4f209d62ae324f4634c6bff 100644 (file)
@@ -1,27 +1,36 @@
-#ifndef MATCH_H
-#define MATCH_H
-
-/*=============================================================================
- * System headers used by this header file
+/*
+ * match.h
+ *
+ * $Id$
  */
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+#ifndef INCLUDED_match_h
+#define INCLUDED_match_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* XXX - broken BSD system headers */
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>        /* struct in_addr */
+#define INCLUDED_netinet_in_h
+#endif
 
-/*=============================================================================
+/*
  * Structures
  */
-
 struct in_mask {
   struct in_addr bits;
   struct in_addr mask;
   int fall;
 };
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
+/*
+ * XXX - match returns 0 if a match is found. Smelly interface
+ * needs to be fixed. --Bleep
+ */
 extern int mmatch(const char *old_mask, const char *new_mask);
 extern int match(const char *ma, const char *na);
 extern char *collapse(char *pattern);
@@ -32,4 +41,4 @@ extern int matchdecomp(char *mask, const char *cmask);
 extern int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen);
 extern int matchcompIP(struct in_mask *imask, const char *mask);
 
-#endif /* MATCH_H */
+#endif /* INCLUDED_match_h */
index b6bf59c1f3e3657410f8953637886bbf7793136f..da70d4236f3ac18ff0ee5ceeedc787bee790c0e2 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_msg_h
+#define INCLUDED_msg_h
+#ifndef INCLUDED_ircd_handler_h
+#include "ircd_handler.h"
+#endif
 
-#ifndef MSG_H
-#define MSG_H
+struct Client;
 
-/*=============================================================================
+/*
  * General defines
  */
 
-#define MAXPARA           15
+#define MAXPARA    15
 
 /*-----------------------------------------------------------------------------
- * Macro's
+ * Macros
  */
 
 /*
 
 /* *INDENT-OFF* */
 
-#define MSG_PRIVATE            "PRIVMSG"       /* PRIV */
-#define TOK_PRIVATE            "P"
-#define CLASS_PRIVATE          LEVEL_PROPAGATE
-
-#define MSG_WHO                        "WHO"           /* WHO  -> WHOC */
-#define TOK_WHO                        "H"
-#define CLASS_WHO              LEVEL_QUERY
+#define MSG_PRIVATE             "PRIVMSG"       /* PRIV */
+#define TOK_PRIVATE             "P"
 
-#define MSG_WHOIS              "WHOIS"         /* WHOI */
-#define TOK_WHOIS              "W"
-#define CLASS_WHOIS            LEVEL_QUERY
+#define MSG_WHO                 "WHO"           /* WHO  -> WHOC */
+#define TOK_WHO                 "H"
 
-#define MSG_WHOWAS             "WHOWAS"        /* WHOW */
-#define TOK_WHOWAS             "X"
-#define CLASS_WHOWAS           LEVEL_QUERY
+#define MSG_WHOIS               "WHOIS"         /* WHOI */
+#define TOK_WHOIS               "W"
 
-#define MSG_USER               "USER"          /* USER */
-#define TOK_USER               "USER"
-#define CLASS_USER             LEVEL_CLIENT
+#define MSG_WHOWAS              "WHOWAS"        /* WHOW */
+#define TOK_WHOWAS              "X"
 
-#define MSG_NICK               "NICK"          /* NICK */
-#define TOK_NICK               "N"
-#define CLASS_NICK             LEVEL_CLIENT
+#define MSG_USER                "USER"          /* USER */
+#define TOK_USER                "USER"
 
-#define MSG_SERVER             "SERVER"        /* SERV */
-#define TOK_SERVER             "S"
-#define CLASS_SERVER           LEVEL_MAP
+#define MSG_NICK                "NICK"          /* NICK */
+#define TOK_NICK                "N"
 
-#define MSG_LIST               "LIST"          /* LIST */
-#define TOK_LIST               "LIST"
-#define CLASS_LIST             LEVEL_QUERY
+#define MSG_SERVER              "SERVER"        /* SERV */
+#define TOK_SERVER              "S"
 
-#define MSG_TOPIC              "TOPIC"         /* TOPI */
-#define TOK_TOPIC              "T"
-#define CLASS_TOPIC            LEVEL_PROPAGATE
+#define MSG_LIST                "LIST"          /* LIST */
+#define TOK_LIST                "LIST"
 
-#define MSG_INVITE             "INVITE"        /* INVI */
-#define TOK_INVITE             "I"
-#define CLASS_INVITE           LEVEL_MODE
+#define MSG_TOPIC               "TOPIC"         /* TOPI */
+#define TOK_TOPIC               "T"
 
-#define MSG_VERSION            "VERSION"       /* VERS */
-#define TOK_VERSION            "V"
-#define CLASS_VERSION          LEVEL_QUERY
+#define MSG_INVITE              "INVITE"        /* INVI */
+#define TOK_INVITE              "I"
 
-#define MSG_QUIT               "QUIT"          /* QUIT */
-#define TOK_QUIT               "Q"
-#define CLASS_QUIT             LEVEL_CLIENT
+#define MSG_VERSION             "VERSION"       /* VERS */
+#define TOK_VERSION             "V"
 
-#define MSG_SQUIT              "SQUIT"         /* SQUI */
-#define TOK_SQUIT              "SQ"
-#define CLASS_SQUIT            LEVEL_MAP
+#define MSG_QUIT                "QUIT"          /* QUIT */
+#define TOK_QUIT                "Q"
 
-#define MSG_KILL               "KILL"          /* KILL */
-#define TOK_KILL               "D"
-#define CLASS_KILL             LEVEL_CLIENT
+#define MSG_SQUIT               "SQUIT"         /* SQUI */
+#define TOK_SQUIT               "SQ"
 
-#define MSG_INFO               "INFO"          /* INFO */
-#define TOK_INFO               "F"
-#define CLASS_INFO             LEVEL_QUERY
+#define MSG_KILL                "KILL"          /* KILL */
+#define TOK_KILL                "D"
 
-#define MSG_LINKS              "LINKS"         /* LINK */
-#define TOK_LINKS              "LI"
-#define CLASS_LINKS            LEVEL_QUERY
+#define MSG_INFO                "INFO"          /* INFO */
+#define TOK_INFO                "F"
 
-#define MSG_STATS              "STATS"         /* STAT */
-#define TOK_STATS              "R"
-#define CLASS_STATS            LEVEL_QUERY
+#define MSG_LINKS               "LINKS"         /* LINK */
+#define TOK_LINKS               "LI"
 
-#define MSG_HELP               "HELP"          /* HELP */
-#define TOK_HELP               "HELP"
-#define CLASS_HELP             LEVEL_QUERY
+#define MSG_STATS               "STATS"         /* STAT */
+#define TOK_STATS               "R"
 
-#define MSG_ERROR              "ERROR"         /* ERRO */
-#define TOK_ERROR              "Y"
-#define CLASS_ERROR            LEVEL_PROPAGATE
+#define MSG_HELP                "HELP"          /* HELP */
+#define TOK_HELP                "HELP"
 
-#define MSG_AWAY               "AWAY"          /* AWAY */
-#define TOK_AWAY               "A"
-#define CLASS_AWAY             LEVEL_PROPAGATE
+#define MSG_ERROR               "ERROR"         /* ERRO */
+#define TOK_ERROR               "Y"
 
-#define MSG_CONNECT            "CONNECT"       /* CONN */
-#define TOK_CONNECT            "CO"
-#define CLASS_CONNECT          LEVEL_PROPAGATE
+#define MSG_AWAY                "AWAY"          /* AWAY */
+#define TOK_AWAY                "A"
 
-#define MSG_UPING              "UPING"         /* UPIN */
-#define TOK_UPING              "UP"
-#define CLASS_UPING            LEVEL_PROPAGATE
+#define MSG_CONNECT             "CONNECT"       /* CONN */
+#define TOK_CONNECT             "CO"
 
-#define MSG_MAP                        "MAP"           /* MAP  */
-#define TOK_MAP                        "MAP"
-#define CLASS_MAP              LEVEL_QUERY
+#define MSG_MAP                 "MAP"           /* MAP  */
+#define TOK_MAP                 "MAP"
 
-#define MSG_PING               "PING"          /* PING */
-#define TOK_PING               "G"
-#define CLASS_PING             LEVEL_PROPAGATE
+#define MSG_PING                "PING"          /* PING */
+#define TOK_PING                "G"
 
-#define MSG_PONG               "PONG"          /* PONG */
-#define TOK_PONG               "Z"
-#define CLASS_PONG             LEVEL_CLIENT
+#define MSG_PONG                "PONG"          /* PONG */
+#define TOK_PONG                "Z"
 
-#define MSG_OPER               "OPER"          /* OPER */
-#define TOK_OPER               "OPER"
-#define CLASS_OPER             LEVEL_PROPAGATE
+#define MSG_OPER                "OPER"          /* OPER */
+#define TOK_OPER                "OPER"
 
-#define MSG_PASS               "PASS"          /* PASS */
-#define TOK_PASS               "PA"
-#define CLASS_PASS             LEVEL_CLIENT
+#define MSG_PASS                "PASS"          /* PASS */
+#define TOK_PASS                "PA"
 
-#define MSG_WALLOPS            "WALLOPS"       /* WALL */
-#define TOK_WALLOPS            "WA"
-#define CLASS_WALLOPS          LEVEL_PROPAGATE
+#define MSG_WALLOPS             "WALLOPS"       /* WALL */
+#define TOK_WALLOPS             "WA"
 
 #define MSG_DESYNCH             "DESYNCH"       /* DESY */
 #define TOK_DESYNCH             "DS"
-#define CLASS_DESYNCH           LEVEL_PROPAGATE
 
-#define MSG_TIME               "TIME"          /* TIME */
-#define TOK_TIME               "TI"
-#define CLASS_TIME             LEVEL_QUERY
+#define MSG_TIME                "TIME"          /* TIME */
+#define TOK_TIME                "TI"
 
-#define MSG_SETTIME            "SETTIME"       /* SETT */
-#define TOK_SETTIME            "SE"
-#define CLASS_SETTIME          LEVEL_PROPAGATE
+#define MSG_SETTIME             "SETTIME"       /* SETT */
+#define TOK_SETTIME             "SE"
 
-#define MSG_RPING              "RPING"         /* RPIN */
-#define TOK_RPING              "RI"
-#define CLASS_RPING            LEVEL_PROPAGATE
+#define MSG_RPING               "RPING"         /* RPIN */
+#define TOK_RPING               "RI"
 
-#define MSG_RPONG              "RPONG"         /* RPON */
-#define TOK_RPONG              "RO"
-#define CLASS_RPONG            LEVEL_PROPAGATE
+#define MSG_RPONG               "RPONG"         /* RPON */
+#define TOK_RPONG               "RO"
 
-#define MSG_NAMES              "NAMES"         /* NAME */
-#define TOK_NAMES              "E"
-#define CLASS_NAMES            LEVEL_QUERY
+#define MSG_NAMES               "NAMES"         /* NAME */
+#define TOK_NAMES               "E"
 
-#define MSG_ADMIN              "ADMIN"         /* ADMI */
-#define TOK_ADMIN              "AD"
-#define CLASS_ADMIN            LEVEL_QUERY
+#define MSG_ADMIN               "ADMIN"         /* ADMI */
+#define TOK_ADMIN               "AD"
 
-#define MSG_TRACE              "TRACE"         /* TRAC */
-#define TOK_TRACE              "TR"
-#define CLASS_TRACE            LEVEL_PROPAGATE
+#define MSG_TRACE               "TRACE"         /* TRAC */
+#define TOK_TRACE               "TR"
 
-#define MSG_NOTICE             "NOTICE"        /* NOTI */
-#define TOK_NOTICE             "O"
-#define CLASS_NOTICE           LEVEL_PROPAGATE
+#define MSG_NOTICE              "NOTICE"        /* NOTI */
+#define TOK_NOTICE              "O"
 
-#define MSG_WALLCHOPS          "WALLCHOPS"     /* WC */
-#define TOK_WALLCHOPS          "WC"
-#define CLASS_WALLCHOPS                LEVEL_PROPAGATE
+#define MSG_WALLCHOPS           "WALLCHOPS"     /* WC */
+#define TOK_WALLCHOPS           "WC"
 
-#define MSG_CPRIVMSG           "CPRIVMSG"      /* CPRI */
-#define TOK_CPRIVMSG           "CP"
-#define CLASS_CPRIVMSG         LEVEL_CLIENT
+#define MSG_CPRIVMSG            "CPRIVMSG"      /* CPRI */
+#define TOK_CPRIVMSG            "CP"
 
-#define MSG_CNOTICE            "CNOTICE"       /* CNOT */
-#define TOK_CNOTICE            "CN"
-#define CLASS_CNOTICE          LEVEL_CLIENT
+#define MSG_CNOTICE             "CNOTICE"       /* CNOT */
+#define TOK_CNOTICE             "CN"
 
-#define MSG_JOIN               "JOIN"          /* JOIN */
-#define TOK_JOIN               "J"
-#define CLASS_JOIN             LEVEL_CHANNEL
+#define MSG_JOIN                "JOIN"          /* JOIN */
+#define TOK_JOIN                "J"
 
-#define MSG_PART               "PART"          /* PART */
-#define TOK_PART               "L"
-#define CLASS_PART             LEVEL_CHANNEL
+#define MSG_PART                "PART"          /* PART */
+#define TOK_PART                "L"
 
-#define MSG_LUSERS             "LUSERS"        /* LUSE */
-#define TOK_LUSERS             "LU"
-#define CLASS_LUSERS           LEVEL_QUERY
+#define MSG_LUSERS              "LUSERS"        /* LUSE */
+#define TOK_LUSERS              "LU"
 
-#define MSG_MOTD               "MOTD"          /* MOTD */
-#define TOK_MOTD               "MO"
-#define CLASS_MOTD             LEVEL_QUERY
+#define MSG_MOTD                "MOTD"          /* MOTD */
+#define TOK_MOTD                "MO"
 
-#define MSG_MODE               "MODE"          /* MODE */
-#define TOK_MODE               "M"
-#define CLASS_MODE             LEVEL_MODE
+#define MSG_MODE                "MODE"          /* MODE */
+#define TOK_MODE                "M"
 
-#define MSG_KICK               "KICK"          /* KICK */
-#define TOK_KICK               "K"
-#define CLASS_KICK             LEVEL_CHANNEL
+#define MSG_KICK                "KICK"          /* KICK */
+#define TOK_KICK                "K"
 
-#define MSG_USERHOST           "USERHOST"      /* USER -> USRH */
-#define TOK_USERHOST           "USERHOST"
-#define CLASS_USERHOST         LEVEL_QUERY
+#define MSG_USERHOST            "USERHOST"      /* USER -> USRH */
+#define TOK_USERHOST            "USERHOST"
 
-#define MSG_USERIP             "USERIP"        /* USER -> USIP */
-#define TOK_USERIP             "USERIP"
-#define CLASS_USERIP           LEVEL_QUERY
+#define MSG_USERIP              "USERIP"        /* USER -> USIP */
+#define TOK_USERIP              "USERIP"
 
-#define MSG_ISON               "ISON"          /* ISON */
-#define TOK_ISON               "ISON"
-#define CLASS_ISON             LEVEL_QUERY
+#define MSG_ISON                "ISON"          /* ISON */
+#define TOK_ISON                "ISON"
 
-#define MSG_SQUERY             "SQUERY"        /* SQUE */
-#define TOK_SQUERY             "SQUERY"
-#define CLASS_SQUERY           LEVEL_QUERY
+#define MSG_SQUERY              "SQUERY"        /* SQUE */
+#define TOK_SQUERY              "SQUERY"
 
-#define MSG_SERVLIST           "SERVLIST"      /* SERV -> SLIS */
-#define TOK_SERVLIST           "SERVSET"
-#define CLASS_SERVLIST         LEVEL_QUERY
+#define MSG_SERVLIST            "SERVLIST"      /* SERV -> SLIS */
+#define TOK_SERVLIST            "SERVSET"
 
-#define MSG_SERVSET            "SERVSET"       /* SERV -> SSET */
-#define TOK_SERVSET            "SERVSET"
-#define CLASS_SERVSET          LEVEL_CLIENT
+#define MSG_SERVSET             "SERVSET"       /* SERV -> SSET */
+#define TOK_SERVSET             "SERVSET"
 
-#define MSG_REHASH             "REHASH"        /* REHA */
-#define TOK_REHASH             "REHASH"
-#define CLASS_REHASH           LEVEL_MAP
+#define MSG_REHASH              "REHASH"        /* REHA */
+#define TOK_REHASH              "REHASH"
 
-#define MSG_RESTART            "RESTART"       /* REST */
-#define TOK_RESTART            "RESTART"
-#define CLASS_RESTART          LEVEL_MAP
+#define MSG_RESTART             "RESTART"       /* REST */
+#define TOK_RESTART             "RESTART"
 
-#define MSG_CLOSE              "CLOSE"         /* CLOS */
-#define TOK_CLOSE              "CLOSE"
-#define CLASS_CLOSE            LEVEL_CLIENT
+#define MSG_CLOSE               "CLOSE"         /* CLOS */
+#define TOK_CLOSE               "CLOSE"
 
-#define MSG_DIE                        "DIE"           /* DIE  */
-#define TOK_DIE                        "DIE"
-#define CLASS_DIE              LEVEL_MAP
+#define MSG_DIE                 "DIE"           /* DIE  */
+#define TOK_DIE                 "DIE"
 
-#define MSG_HASH               "HASH"          /* HASH */
-#define TOK_HASH               "HASH"
-#define CLASS_HASH             LEVEL_QUERY
+#define MSG_HASH                "HASH"          /* HASH */
+#define TOK_HASH                "HASH"
 
-#define MSG_DNS                        "DNS"           /* DNS  -> DNSS */
-#define TOK_DNS                        "DNS"
-#define CLASS_DNS              LEVEL_QUERY
+#define MSG_DNS                 "DNS"           /* DNS  -> DNSS */
+#define TOK_DNS                 "DNS"
 
-#define MSG_SILENCE            "SILENCE"       /* SILE */
-#define TOK_SILENCE            "U"
-#define CLASS_SILENCE          LEVEL_PROPAGATE
+#define MSG_SILENCE             "SILENCE"       /* SILE */
+#define TOK_SILENCE             "U"
 
-#define MSG_GLINE              "GLINE"         /* GLIN */
-#define TOK_GLINE              "GL"
-#define CLASS_GLINE            LEVEL_CLIENT
+#define MSG_GLINE               "GLINE"         /* GLIN */
+#define TOK_GLINE               "GL"
 
-#define MSG_BURST              "BURST"         /* BURS */
-#define TOK_BURST              "B"
-#define CLASS_BURST            LEVEL_CHANNEL
+#define MSG_BURST               "BURST"         /* BURS */
+#define TOK_BURST               "B"
 
-#define MSG_CREATE             "CREATE"        /* CREA */
-#define TOK_CREATE             "C"
-#define CLASS_CREATE           LEVEL_CHANNEL
+#define MSG_CREATE              "CREATE"        /* CREA */
+#define TOK_CREATE              "C"
 
-#define MSG_DESTRUCT           "DESTRUCT"      /* DEST */
-#define TOK_DESTRUCT           "DE"
-#define CLASS_DESTRUCT         LEVEL_CHANNEL
+#define MSG_DESTRUCT            "DESTRUCT"      /* DEST */
+#define TOK_DESTRUCT            "DE"
 
-#define MSG_END_OF_BURST       "END_OF_BURST"  /* END_ */
-#define TOK_END_OF_BURST       "EB"
-#define CLASS_END_OF_BURST     LEVEL_MAP
+#define MSG_END_OF_BURST        "END_OF_BURST"  /* END_ */
+#define TOK_END_OF_BURST        "EB"
 
-#define MSG_END_OF_BURST_ACK   "EOB_ACK"       /* EOB_ */
-#define TOK_END_OF_BURST_ACK   "EA"
-#define CLASS_END_OF_BURST_ACK LEVEL_MAP
+#define MSG_END_OF_BURST_ACK    "EOB_ACK"       /* EOB_ */
+#define TOK_END_OF_BURST_ACK    "EA"
 
-/* *INDENT-ON* */
+#define MSG_PROTO               "PROTO"         /* PROTO */
+#define TOK_PROTO               "PROTO"         /* PROTO */
 
-/*=============================================================================
+
+/*
  * Constants
  */
-#define   MFLG_SLOW              0x01  /* Command can be executed roughly    *
-                                        * once per 2 seconds.                */
-#define   MFLG_UNREG             0x02  /* Command available to unregistered  *
-                                        * clients.                           */
+#define   MFLG_SLOW              0x01   /* Command can be executed roughly    *
+                                         * once per 2 seconds.                */
+#define   MFLG_UNREG             0x02   /* Command available to unregistered  *
+                                         * clients.                           */
+#define   MFLG_IGNORE            0x04   /* silently ignore command from
+                                         * unregistered clients */
 
-/*=============================================================================
+/*
  * Structures
  */
-
 struct Message {
-  unsigned int msgclass;
-  char *cmd;
-  char *tok;
-  int (*func) (aClient *cptr, aClient *sptr, int parc, char *parv[]);
-  /* cptr = Connected client ptr
-     sptr = Source client ptr
-     parc = parameter count
-     parv = parameter variable array */
-  unsigned int count;
+  char *cmd;                  /* command string */
+  char *tok;                  /* token (shorter command string) */
+  unsigned int count;         /* number of times message used */
   unsigned int parameters;
-  unsigned char flags;         /* bit 0 set means that this command is allowed
-                                  to be used only on the average of once per 2
-                                  seconds -SRB */
-  unsigned int bytes;
-};
-
-struct MessageTree {
-  char *final;
-  struct Message *msg;
-  struct MessageTree *pointers[26];
+  unsigned int flags;           /* bit 0 set means that this command is allowed
+                                   to be used only on the average of once per 2
+                                   seconds -SRB */
+  unsigned int bytes;         /* bytes received for this message */
+  /*
+   * cptr = Connected client ptr
+   * sptr = Source client ptr
+   * parc = parameter count
+   * parv = parameter variable array
+   */
+  /* handlers:
+   * UNREGISTERED, CLIENT, SERVER, OPER, SERVICE, LAST
+   */
+  MessageHandler handlers[LAST_HANDLER_TYPE];
 };
 
-/*=============================================================================
- * Proto types
- */
-
 extern struct Message msgtab[];
 
-#endif /* MSG_H */
+#endif /* INCLUDED_msg_h */
index 06b3337ad12f792f0f995ad99e7ec9b9721f2ad6..a908f0838c4713a07714d6d3c18839ceeab1a7f4 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_numeric_h
+#define INCLUDED_numeric_h
 
-#ifndef NUMERIC_H
-#define NUMERIC_H
+typedef struct Numeric {
+  int         value;
+  const char* format;
+  const char* str;
+} Numeric;
 
-/*=============================================================================
- * Macro's
+/*
+ * Prototypes
  */
+extern char* err_str(int numeric);
+extern char* rpl_str(int numeric);
+extern const struct Numeric* get_error_numeric(int err);
+
 
 /*
  * Reserve numerics 000-099 for server-client connections where the client
  * is local to the server. If any server is passed a numeric in this range
  * from another server then it is remapped to 100-199. -avalon
  */
-#define RPL_WELCOME           1
-#define RPL_YOURHOST          2
-#define RPL_CREATED           3
-#define RPL_MYINFO            4
-#define RPL_MAP                       5        /* Undernet extension */
-#define RPL_MAPMORE           6        /* Undernet extension */
-#define RPL_MAPEND            7        /* Undernet extension */
-#define RPL_SNOMASK           8        /* Undernet extension */
-#define RPL_STATMEMTOT        9        /* Undernet extension */
-#define RPL_STATMEM          10        /* Undernet extension */
+#define RPL_WELCOME            1
+#define RPL_YOURHOST           2
+#define RPL_CREATED            3
+#define RPL_MYINFO             4
+#define RPL_ISUPPORT           5        /* Undernet/Dalnet extension */
+     /* RPL_BOUNCE                         IRCnet extension */
+#define RPL_SNOMASK            8        /* Undernet extension */
+#define RPL_STATMEMTOT         9        /* Undernet extension */
+#define RPL_STATMEM           10        /* Undernet extension */
 /*      RPL_YOURCOOKIE        14           IRCnet extension */
+#define RPL_MAP               15        /* Undernet extension */
+#define RPL_MAPMORE           16        /* Undernet extension */
+#define RPL_MAPEND            17        /* Undernet extension */
+/*      RPL_ATTEMPTINGJUNC    50           aircd extension */
+/*      RPL_ATTEMPTINGREROUTE 51           aircd extension */
+
+/*
+ * Numberic replies from server commands.
+ * These are currently in the range 200-399.
+ */
+
+#define RPL_TRACELINK        200
+#define RPL_TRACECONNECTING  201
+#define RPL_TRACEHANDSHAKE   202
+#define RPL_TRACEUNKNOWN     203
+#define RPL_TRACEOPERATOR    204
+#define RPL_TRACEUSER        205
+#define RPL_TRACESERVER      206
+#define RPL_TRACENEWTYPE     208
+#define RPL_TRACECLASS       209
+/*      RPL_STATS            210 aircd extension, used instead of having
+                                 multiple stats numerics */
+/*      RPL_TRACERECONNECT   210 IRCnet extension */                                 
+#define RPL_STATSLINKINFO    211
+#define RPL_STATSCOMMANDS    212
+#define RPL_STATSCLINE       213
+#define RPL_STATSNLINE       214
+#define RPL_STATSILINE       215
+#define RPL_STATSKLINE       216
+#define RPL_STATSPLINE       217        /* Undernet extenstion */
+/*      RPL_STATSQLINE       217           Various */
+#define RPL_STATSYLINE       218
+#define RPL_ENDOFSTATS       219        /* See also RPL_STATSDLINE */
+/*      RPL_STATSPLINE       220           Hybrid - Because 217 was for
+                                           old Q: lines. */
+#define RPL_UMODEIS          221
+/*      RPL_STATSFLINE       224           Hybrid extension */
+/*      RPL_STATSDLINE       225           Hybrid extension */
+
+#define RPL_SERVICEINFO      231
+#define RPL_ENDOFSERVICES    232
+#define RPL_SERVICE          233
+#define RPL_SERVLIST         234
+#define RPL_SERVLISTEND      235
+
+/*      RPL_STATSIAUTH       239           IRCnet extension */
+/*      RPL_STATSVLINE       240           IRCnet extension */
+#define RPL_STATSLLINE       241
+#define RPL_STATSUPTIME      242
+#define RPL_STATSOLINE       243
+#define RPL_STATSHLINE       244
+/*      RPL_STATSSLINE       245           Reserved */
+#define RPL_STATSTLINE       246        /* Undernet extension */
+#define RPL_STATSGLINE       247        /* Undernet extension */
+/*      RPL_STATSXLINE       247           hybrid extension */                                        
+#define RPL_STATSULINE       248        /* Undernet extension */
+#define RPL_STATSDEBUG       249        /* Extension to RFC1459 */
+#define RPL_STATSCONN        250        /* Undernet extension */
+
+#define RPL_LUSERCLIENT      251
+#define RPL_LUSEROP          252
+#define RPL_LUSERUNKNOWN     253
+#define RPL_LUSERCHANNELS    254
+#define RPL_LUSERME          255
+#define RPL_ADMINME          256
+#define RPL_ADMINLOC1        257
+#define RPL_ADMINLOC2        258
+#define RPL_ADMINEMAIL       259
+
+#define RPL_TRACELOG         261
+#define RPL_TRACEPING        262        /* Extension to RFC1459 */
+                                        /* efnet: END_TRACE */
+/*      RPL_LOAD_THROTTLED   263           efnet/hybrid */
+
+/*      RPL_CURRENT_LOCAL    265           aircd/efnet/hybrid*/
+/*      RPL_CURRENT_GLOBAL   266           aircd/efnet/hybrid */
+/*      RPL_START_NETSTAT    267           aircd */
+/*      RPL_NETSTAT          268           aircd */
+/*      RPL_END_NETSTAT      269           aircd */
+
+#define RPL_SILELIST         271        /* Undernet extension */
+#define RPL_ENDOFSILELIST    272        /* Undernet extension */
+/*      RPL_NOTIFY           273           aircd */
+/*      RPL_END_NOTIFY       274           aircd */
+/*      RPL_STATSDELTA       274           IRCnet extension */
+#define RPL_STATSDLINE       275        /* Undernet extension */
+
+#define RPL_GLIST            280        /* Undernet extension */
+#define RPL_ENDOFGLIST       281        /* Undernet extension */
+
+/*      RPL_CHANINFO_HANDLE  285           aircd */
+/*      RPL_CHANINFO_USERS   286           aircd */
+/*      RPL_CHANINFO_CHOPS   287           aircd */
+/*      RPL_CHANINFO_VOICES  288           aircd */
+/*      RPL_CHANINFO_AWAY    289           aircd */
+/*      RPL_CHANINFO_OPERS   290           aircd */
+/*      RPL_CHANINFO_BANNED  291           aircd */
+/*      RPL_CHANINFO_BANS    292           aircd */
+/*      RPL_CHANINFO_INVITE  293           aircd */
+/*      RPL_CHANINFO_INVITES 294           aircd */
+/*      RPL_CHANINFO_KICK    295           aircd */
+/*      RPL_CHANINFO_KICKS   296           aircd */
+
+/*      RPL_END_CHANINFO     299           aircd */
+
+#define RPL_NONE             300
+#define RPL_AWAY             301
+#define RPL_USERHOST         302
+#define RPL_ISON             303
+#define RPL_TEXT             304
+#define RPL_UNAWAY           305
+#define RPL_NOWAWAY          306
+#define RPL_USERIP           307        /* Undernet extension */
+                                        /* NotAway, aircd */
+/*      RPL_NOTIFYACTION     308         aircd */
+/*      RPL_NICKTRACE        309         aircd */
+/*      RPL_DALNET_SOMETHING 310         Dalnet, unknown */                                        
+#define RPL_WHOISUSER        311        /* See also RPL_ENDOFWHOIS */
+#define RPL_WHOISSERVER      312
+#define RPL_WHOISOPERATOR    313
+#define RPL_WHOWASUSER       314        /* See also RPL_ENDOFWHOWAS */
+#define RPL_ENDOFWHO         315        /* See RPL_WHOREPLY/RPL_WHOSPCRPL */
+/*      RPL_WHOISCHANOP      316           removed from RFC1459 */
+#define RPL_WHOISIDLE        317
+#define RPL_ENDOFWHOIS       318        /* See RPL_WHOISUSER/RPL_WHOISSERVER/
+                                           RPL_WHOISOPERATOR/RPL_WHOISIDLE */
+#define RPL_WHOISCHANNELS    319
+/*      RPL_WHOIS_HIDDEN     320         Anothernet +h, ick! */
+#define RPL_LISTSTART        321
+#define RPL_LIST             322
+#define RPL_LISTEND          323
+#define RPL_CHANNELMODEIS    324
+/*      RPL_CHANNELPASSIS    325           IRCnet extension */
+/*      RPL_UNIQOPIS         325           IRCnet extension */
+/*      RPL_NOCHANPASS       326           IRCnet extension */
+/*      RPL_CHPASSUNKNOWN    327           IRCnet extension */
+/*      RPL_CHANNEL_URL      328           dalnet, anothernet */
+#define RPL_CREATIONTIME     329
+/*      RPL_WHOWAS_TIME      330               ? */
+#define RPL_NOTOPIC          331
+#define RPL_TOPIC            332
+#define RPL_TOPICWHOTIME     333        /* Undernet extension */
+#define RPL_LISTUSAGE        334        /* Undernet extension */
+/*      RPL_CHANPASSOK       338           IRCnet extension */
+/*      RPL_BADCHANPASS      339           IRCnet extension */
+
+#define RPL_INVITING         341
+/*      RPL_SUMMONING        342           removed from RFC1459 */
+
+#define RPL_INVITELIST       346        /* IRCnet, Undernet extension */
+#define RPL_ENDOFINVITELIST  347        /* IRCnet, Undernet extension */
+/*      RPL_EXCEPTLIST       348           IRCnet extension */
+/*      RPL_ENDOFEXCEPTLIST  349           IRCnet extension */
+
+#define RPL_VERSION          351
+#define RPL_WHOREPLY         352        /* See also RPL_ENDOFWHO */
+#define RPL_NAMREPLY         353        /* See also RPL_ENDOFNAMES */
+#define RPL_WHOSPCRPL        354        /* Undernet extension,
+                                           See also RPL_ENDOFWHO */
+
+#define RPL_KILLDONE         361
+#define RPL_CLOSING          362
+#define RPL_CLOSEEND         363
+#define RPL_LINKS            364
+#define RPL_ENDOFLINKS       365
+#define RPL_ENDOFNAMES       366        /* See RPL_NAMREPLY */
+#define RPL_BANLIST          367
+#define RPL_ENDOFBANLIST     368
+#define RPL_ENDOFWHOWAS      369
+
+#define RPL_INFO             371
+#define RPL_MOTD             372
+#define RPL_INFOSTART        373
+#define RPL_ENDOFINFO        374
+#define RPL_MOTDSTART        375
+#define RPL_ENDOFMOTD        376
+
+/*      RPL_KICKEXPIRED      377   aircd */
+/*      RPL_BANEXPIRED       378   aircd */
+/*      RPL_KICKLINKED       379   aircd */
+/*      RPL_BANLINKED        380   aircd */
+
+#define RPL_YOUREOPER        381
+#define RPL_REHASHING        382
+/*      RPL_NOWSERVICE       383        ? */
+#define RPL_MYPORTIS         384
+#define RPL_NOTOPERANYMORE   385        /* Extension to RFC1459 */
+
+#define RPL_TIME             391
+/*      RPL_START_USERS      392        ? */
+/*      RPL_USERS            393        ? */
+/*      RPL_END_USERS        394        ? */
+/*      RPL_NOUSERS          395        ? */
 
 /*
  * Errors are in the range from 400-599 currently and are grouped by what
  * commands they come from.
  */
-#define ERR_NOSUCHNICK      401
+#define ERR_FIRSTERROR       400
+#define ERR_NOSUCHNICK       401
 #define ERR_NOSUCHSERVER     402
 #define ERR_NOSUCHCHANNEL    403
 #define ERR_CANNOTSENDTOCHAN 404
 #define ERR_TOOMANYCHANNELS  405
 #define ERR_WASNOSUCHNICK    406
 #define ERR_TOOMANYTARGETS   407
-#define ERR_NOORIGIN        409
+/*      ERR_NOSUCHSERVICE    408  IRCnet */
+#define ERR_NOORIGIN         409
 
-#define ERR_NORECIPIENT             411
+#define ERR_NORECIPIENT      411
 #define ERR_NOTEXTTOSEND     412
-#define ERR_NOTOPLEVEL      413
+#define ERR_NOTOPLEVEL       413
 #define ERR_WILDTOPLEVEL     414
-
-#define ERR_QUERYTOOLONG     416       /* Undernet extension */
+     /* ERR_BADMASK          415           IRCnet extension */
+#define ERR_QUERYTOOLONG     416        /* Undernet extension */
+     /* ERR_TOOMANYMATCHES   416           IRCnet extension */
+/*      ERR_LENGTHTRUNCATED  319           aircd */
 
 #define ERR_UNKNOWNCOMMAND   421
-#define ERR_NOMOTD          422
-#define ERR_NOADMININFO             423
+#define ERR_NOMOTD           422
+#define ERR_NOADMININFO      423
 /*      ERR_FILEERROR        424           removed from RFC1459 */
 
 #define ERR_NONICKNAMEGIVEN  431
 #define ERR_ERRONEUSNICKNAME 432
 #define ERR_NICKNAMEINUSE    433
+/*      ERR_SERVICENAMEINUSE 434 ? */
+/*      ERR_SERVICECONFUSED  435 ? */
 #define ERR_NICKCOLLISION    436
-#define ERR_BANNICKCHANGE    437       /* Undernet extension */
-#define ERR_NICKTOOFAST             438        /* Undernet extension */
-#define ERR_TARGETTOOFAST    439       /* Undernet extension */
+#define ERR_BANNICKCHANGE    437        /* Undernet extension */
+     /* ERR_UNAVAILRESOURCE  437           IRCnet extension */
+#define ERR_NICKTOOFAST      438        /* Undernet extension */
+     /* ERR_DEAD             438           IRCnet reserved for later use */
+#define ERR_TARGETTOOFAST    439        /* Undernet extension */
 
 #define ERR_USERNOTINCHANNEL 441
 #define ERR_NOTONCHANNEL     442
 /*      ERR_USERSDISABLED    446           removed from RFC1459 */
 
 #define ERR_NOTREGISTERED    451
-/*      ERR_IDCOLLISION      452           IRCnet extension */
-/*      ERR_NICKLOST         453           IRCnet extension */
+/*      ERR_IDCOLLISION      452           IRCnet extension */
+/*      ERR_NICKLOST         453           IRCnet extension */
 
 #define ERR_NEEDMOREPARAMS   461
 #define ERR_ALREADYREGISTRED 462
 #define ERR_PASSWDMISMATCH   464
 #define ERR_YOUREBANNEDCREEP 465
 #define ERR_YOUWILLBEBANNED  466
-#define ERR_KEYSET          467        /* Undernet extension */
-#define ERR_INVALIDUSERNAME  468       /* Undernet extension */
+#define ERR_KEYSET           467        /* Undernet extension */
+#define ERR_INVALIDUSERNAME  468        /* Undernet extension */
 
+/*      ERR_KICKEDFROMCHAN   470         aircd */ 
 #define ERR_CHANNELISFULL    471
-#define ERR_UNKNOWNMODE             472
+#define ERR_UNKNOWNMODE      472
 #define ERR_INVITEONLYCHAN   473
 #define ERR_BANNEDFROMCHAN   474
 #define ERR_BADCHANNELKEY    475
-#define ERR_BADCHANMASK             476        /* Undernet extension */
+#define ERR_BADCHANMASK      476        /* Undernet extension */
 /*      ERR_NEEDREGGEDNICK   477           DalNet Extention */
-#define ERR_BANLISTFULL             478        /* Undernet extension */
+#define ERR_BANLISTFULL      478        /* Undernet extension */
 #define ERR_BADCHANNAME      479        /* EFNet extension */
-                                       /* 479 Undernet extension badchan*/
+                                        /* 479 Undernet extension badchan */
 #define ERR_NOPRIVILEGES     481
 #define ERR_CHANOPRIVSNEEDED 482
 #define ERR_CANTKILLSERVER   483
-#define ERR_ISCHANSERVICE    484       /* Undernet extension */
+#define ERR_ISCHANSERVICE    484        /* Undernet extension */
+/*      ERR_UNIQOPRIVSNEEDED 485           IRCnet extension */
 /*      ERR_CHANTOORECENT    487           IRCnet extension */
 /*      ERR_TSLESSCHAN       488           IRCnet extension */
-#define ERR_VOICENEEDED             489        /* Undernet extension */
+#define ERR_VOICENEEDED      489        /* Undernet extension */
 
-#define ERR_NOOPERHOST      491
+#define ERR_NOOPERHOST       491
+/*      ERR_NOSERVICEHOST    492 ? */
 
 #define ERR_ISOPERLCHAN      498        /* Undernet extension */
 
 #define ERR_UMODEUNKNOWNFLAG 501
 #define ERR_USERSDONTMATCH   502
+/*      ERR_GHOSTEDCLIENT    503           efnet */
 
-#define ERR_SILELISTFULL     511       /* Undernet extension */
-
-#define ERR_NOSUCHGLINE             512        /* Undernet extension */
-#define ERR_BADPING         513        /* Undernet extension */
-
-/*
- * Numberic replies from server commands.
- * These are currently in the range 200-399.
- */
-#define RPL_NONE            300
-#define RPL_AWAY            301
-#define RPL_USERHOST        302
-#define RPL_ISON            303
-#define RPL_TEXT            304
-#define RPL_UNAWAY          305
-#define RPL_NOWAWAY         306
-#define RPL_USERIP          307        /* Undernet extension */
-
-#define RPL_WHOISUSER       311        /* See also RPL_ENDOFWHOIS */
-#define RPL_WHOISSERVER             312
-#define RPL_WHOISOPERATOR    313
-
-#define RPL_WHOWASUSER      314        /* See also RPL_ENDOFWHOWAS */
-#define RPL_ENDOFWHO        315        /* See RPL_WHOREPLY/RPL_WHOSPCRPL */
-
-/*      RPL_WHOISCHANOP      316           removed from RFC1459 */
-
-#define RPL_WHOISIDLE       317
-
-#define RPL_ENDOFWHOIS      318        /* See RPL_WHOISUSER/RPL_WHOISSERVER/
-                                          RPL_WHOISOPERATOR/RPL_WHOISIDLE */
-#define RPL_WHOISCHANNELS    319
-
-#define RPL_LISTSTART       321
-#define RPL_LIST            322
-#define RPL_LISTEND         323
-#define RPL_CHANNELMODEIS    324
-/*      RPL_CHANNELPASSIS    325           IRCnet extension */
-/*      RPL_NOCHANPASS       326           IRCnet extension */
-/*      RPL_CHPASSUNKNOWN    327           IRCnet extension */
-#define RPL_CREATIONTIME     329
-
-#define RPL_NOTOPIC         331
-#define RPL_TOPIC           332
-#define RPL_TOPICWHOTIME     333       /* Undernet extension */
-#define RPL_LISTUSAGE       334        /* Undernet extension */
-/*      RPL_CHANPASSOK       338           IRCnet extension */
-/*      RPL_BADCHANPASS      339           IRCnet extension */
-
-#define RPL_INVITING        341
-/*      RPL_SUMMONING        342           removed from RFC1459 */
-/*      RPL_EXCEPTLIST       348           IRCnet extension */
-/*      RPL_ENDOFEXCEPTLIST  349           IRCnet extension */
-
-#define RPL_VERSION         351
-
-#define RPL_WHOREPLY        352        /* See also RPL_ENDOFWHO */
-#define RPL_NAMREPLY        353        /* See also RPL_ENDOFNAMES */
-#define RPL_WHOSPCRPL        354       /* Undernet extension,
-                                          See also RPL_ENDOFWHO */
-
-#define RPL_KILLDONE        361
-#define RPL_CLOSING         362
-#define RPL_CLOSEEND        363
-#define RPL_LINKS           364
-#define RPL_ENDOFLINKS      365
-#define RPL_ENDOFNAMES      366        /* See RPL_NAMREPLY */
-#define RPL_BANLIST         367
-#define RPL_ENDOFBANLIST     368
-#define RPL_ENDOFWHOWAS             369
-
-#define RPL_INFO            371
-#define RPL_MOTD            372
-#define RPL_INFOSTART       373
-#define RPL_ENDOFINFO       374
-#define RPL_MOTDSTART       375
-#define RPL_ENDOFMOTD       376
-
-#define RPL_YOUREOPER       381
-#define RPL_REHASHING       382
-#define RPL_MYPORTIS        384
-#define RPL_NOTOPERANYMORE   385       /* Extension to RFC1459 */
-
-#define RPL_TIME            391
-
-#define RPL_TRACELINK       200
-#define RPL_TRACECONNECTING  201
-#define RPL_TRACEHANDSHAKE   202
-#define RPL_TRACEUNKNOWN     203
-#define RPL_TRACEOPERATOR    204
-#define RPL_TRACEUSER       205
-#define RPL_TRACESERVER             206
-#define RPL_TRACENEWTYPE     208
-#define RPL_TRACECLASS      209
-
-#define RPL_STATSLINKINFO    211
-#define RPL_STATSCOMMANDS    212
-#define RPL_STATSCLINE      213
-#define RPL_STATSNLINE      214
-#define RPL_STATSILINE      215
-#define RPL_STATSKLINE      216
-#define RPL_STATSPLINE      217        /* Undernet extenstion */
-#define RPL_STATSYLINE      218
-#define RPL_ENDOFSTATS      219        /* See also RPL_STATSDLINE */
-
-#define RPL_UMODEIS         221
-
-#define RPL_SERVICEINFO             231
-#define RPL_ENDOFSERVICES    232
-#define RPL_SERVICE         233
-#define RPL_SERVLIST        234
-#define RPL_SERVLISTEND             235
-
-#define RPL_STATSLLINE      241
-#define RPL_STATSUPTIME             242
-#define RPL_STATSOLINE      243
-#define RPL_STATSHLINE      244
-/*      RPL_STATSSLINE       245           Reserved */
-#define RPL_STATSTLINE      246        /* Undernet extension */
-#define RPL_STATSGLINE      247        /* Undernet extension */
-#define RPL_STATSULINE      248        /* Undernet extension */
-#define RPL_STATSDEBUG      249        /* Extension to RFC1459 */
-#define RPL_STATSCONN       250        /* Undernet extension */
-
-#define RPL_LUSERCLIENT             251
-#define RPL_LUSEROP         252
-#define RPL_LUSERUNKNOWN     253
-#define RPL_LUSERCHANNELS    254
-#define RPL_LUSERME         255
-#define RPL_ADMINME         256
-#define RPL_ADMINLOC1       257
-#define RPL_ADMINLOC2       258
-#define RPL_ADMINEMAIL      259
-
-#define RPL_TRACELOG        261
-#define RPL_TRACEPING       262        /* Extension to RFC1459 */
-
-#define RPL_SILELIST        271        /* Undernet extension */
-#define RPL_ENDOFSILELIST    272       /* Undernet extension */
-
-/*      RPL_STATSDELTA       274           IRCnet extension */
-#define RPL_STATSDLINE      275        /* Undernet extension */
-
-#define RPL_GLIST           280        /* Undernet extension */
-#define RPL_ENDOFGLIST      281        /* Undernet extension */
+#define ERR_SILELISTFULL     511        /* Undernet extension */
+/*      ERR_NOTIFYFULL       512           aircd */
+#define ERR_NOSUCHGLINE      512        /* Undernet extension */
+#define ERR_BADPING          513        /* Undernet extension */
+#define ERR_INVALID_ERROR    514
 
-#endif /* NUMERIC_H */
+#endif /* INCLUDED_numeric_h */
index 5a435a453b9811ad395c508c96b8fd300bc31ac7..8b0e5f8e1fd0368b1fbd9ec05faa2d5ea1fef114 100644 (file)
@@ -15,8 +15,9 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
 #ifndef INCLUDED_numnicks_h
 #define INCLUDED_numnicks_h
 #ifndef INCLUDED_sys_types_h
 #define INCLUDED_sys_types_h
 #endif
 
-/*=============================================================================
+/*
  * General defines
  */
 
 /*
  * used for buffer size calculations in channel.c
  */
-#define NUMNICKLEN 5           /* strlen("YYXXX") */
+#define NUMNICKLEN 5            /* strlen("YYXXX") */
 
-/*=============================================================================
+/*
  * Macros
  */
 
  */
 #define NumServCap(c) (c)->yxx, (c)->serv->nn_capacity
 
-/*=============================================================================
+/*
  * Structures
  */
 struct Client;
 
-/*=============================================================================
+/*
  * Proto types
  */
-extern int SetRemoteNumNick(struct Client *cptr, const char *yxx);
-extern void SetLocalNumNick(struct Client *cptr);
-extern void RemoveYXXClient(struct Client *server, const char *yxx);
-extern void SetServerYXX(struct Client *cptr,
-    struct Client *server, const char *yxx);
-extern void ClearServerYXX(const struct Client *server);
-
-extern void SetYXXCapacity(struct Client *myself, size_t max_clients);
-extern void SetYXXServerName(struct Client *myself, unsigned int numeric);
+extern int  SetRemoteNumNick(struct Client* cptr, const char* yxx);
+extern void SetLocalNumNick(struct Client* cptr);
+extern void RemoveYXXClient(struct Client* server, const char* yxx);
+extern void SetServerYXX(struct Client* cptr, 
+                         struct Client* server, const char* yxx);
+extern void ClearServerYXX(const struct Client* server);
 
-extern int markMatchexServer(const char *cmask, int minlen);
-extern struct Client *find_match_server(char *mask);
-extern struct Client *findNUser(const char *yxx);
-extern struct Client *FindNServer(const char *numeric);
+extern void SetYXXCapacity(struct Client* myself, size_t max_clients);
+extern void SetYXXServerName(struct Client* myself, unsigned int numeric);
 
-extern unsigned int base64toint(const char *str);
-extern const char *inttobase64(char *buf, unsigned int v, size_t count);
+extern int            markMatchexServer(const char* cmask, int minlen);
+extern struct Client* find_match_server(char* mask);
+extern struct Client* findNUser(const char* yxx);
+extern struct Client* FindNServer(const char* numeric);
 
-#ifndef NO_PROTOCOL9
-extern const char *CreateNNforProtocol9server(const struct Client *server);
-#endif
+extern unsigned int   base64toint(const char* str);
+extern const char*    inttobase64(char* buf, unsigned int v, size_t count);
 
 #endif /* INCLUDED_numnicks_h */
+
index f16e549b6e7c6544998e2b16168d3b072d24bc47..03a69bca1e6c480cad7aad5acc3fc2890ce1c864 100644 (file)
@@ -1,67 +1,29 @@
-#ifndef OPERCMDS_H
-#define OPERCMDS_H
+/*
+ * opercmds.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_opercmds_h
+#define INCLUDED_opercmds_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
 
-/*=============================================================================
+struct Client;
+
+/*
  * General defines
  */
 
 /*-----------------------------------------------------------------------------
  * Macro's
  */
-
-#define GLINE_ACTIVE   1
-#define GLINE_IPMASK   2
-#define GLINE_LOCAL    4
-
 /*
- * G-line macros.
- */
-
-#define GlineIsActive(g)       ((g)->gflags & GLINE_ACTIVE)
-#define GlineIsIpMask(g)       ((g)->gflags & GLINE_IPMASK)
-#define GlineIsLocal(g)                ((g)->gflags & GLINE_LOCAL)
-
-#define SetActive(g)           ((g)->gflags |= GLINE_ACTIVE)
-#define ClearActive(g)         ((g)->gflags &= ~GLINE_ACTIVE)
-#define SetGlineIsIpMask(g)    ((g)->gflags |= GLINE_IPMASK)
-#define SetGlineIsLocal(g)     ((g)->gflags |= GLINE_LOCAL)
-
-/*=============================================================================
- * Structures
- */
-
-struct Gline {
-  struct Gline *next;
-  char *host;
-  char *reason;
-  char *name;
-  time_t expire;
-  unsigned int gflags;
-};
-
-/*=============================================================================
  * Proto types
  */
 
-#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
-extern int m_rehash(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-#endif
-#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
-extern int m_restart(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-#endif
-#if defined(OPER_DIE) || defined(LOCOP_DIE)
-extern int m_die(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-#endif
-extern int m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_connect(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_wallops(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_time(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_settime(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_rping(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_rpong(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_trace(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_close(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_gline(aClient *cptr, aClient *sptr, int parc, char *parv[]);
+extern void report_configured_links(struct Client* sptr, int mask);
+extern char *militime(char* sec, char* usec);
 
-#endif /* OPERCMDS_H */
+#endif /* INCLUDED_opercmds_h */
index 9c2c639030c714987321e60346973161b1a33e51..46f20560a09cabe3d1e210447fa09ebc6c91a2f3 100644 (file)
@@ -1,11 +1,22 @@
-#ifndef PACKET_H
-#define PACKET_H
+/*
+ * packet.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_packet_h
+#define INCLUDED_packet_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern int dopacket(aClient *cptr, char *buffer, int length);
-extern int client_dopacket(aClient *cptr, size_t length);
+extern int server_dopacket(struct Client* cptr, const char* buffer, int length);
+extern int client_dopacket(struct Client* cptr, size_t length);
 
-#endif /* PACKET_H */
+#endif /* INCLUDED_packet_h */
index f6ac2c27ed446be545e4807f884d2a87c9587761..888d6dedd580d58a7732f0a1b9ede366a0d4aefb 100644 (file)
@@ -1,12 +1,19 @@
-#ifndef PARSE_H
-#define PARSE_H
+/*
+ * parse.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_parse_h
+#define INCLUDED_parse_h
+
+struct Client;
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern int parse_client(aClient *cptr, char *buffer, char *bufend);
-extern int parse_server(aClient *cptr, char *buffer, char *bufend);
+extern int parse_client(struct Client *cptr, char *buffer, char *bufend);
+extern int parse_server(struct Client *cptr, char *buffer, char *bufend);
 extern void initmsgtree(void);
 
-#endif /* PARSE_H */
+#endif /* INCLUDED_parse_h */
index 531b25fda251d1202ffacf2eb79e891d6f9cca26..91bb69ff4e8008f66e153a4e7510061525bd4aea 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * PATCHes
  *
- * Only put here ADDED special stuff, for instance: ".mu3" or ".ban"
- * Please start the patchlevel with a '.'
+ * $Id$
  *
- * IMPORTANT: Since u2.9 there is a new format of this file. The reason
- * is that this way it shouldn't be needed anymore for the user to edit
- * this manually !!!
- * If you do, be sure you know what you are doing!
- *
- * For patch devellopers:
- * To make a diff of your patch, edit any of the below lines containing
- * a "" (an EMPTY string). Your patch will then succeed, with only an
- * offset, on the first empty place in the users patchlevel.h.
- * Do not change anyother line, the '\' are to make sure that the 'fuzz'
- * will stay 0. --Run
- */
-
-#define PATCH1 \
-               \
-               \
-               \
-               ".07"
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH2 \
-               \
-               \
-               \
-               ".bc"
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH3 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH4 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH5 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH6 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH7 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH8 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH9 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH10 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH11 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH12 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH13 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH14 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH15 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
  */
 
-#define PATCH16 \
-               \
-               \
-               \
-               ""
+#define PATCHLEVEL "06"
 
-/*
- * Deliberate empty lines
- */
-
-#define PATCH17 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH18 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH19 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH20 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH21 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH22 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH23 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH24 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH25 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH26 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH27 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH28 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH29 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH30 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#define PATCH31 \
-               \
-               \
-               \
-               ""
-
-/*
- * Deliberate empty lines
- */
-
-#ifdef TESTNET
-#define PATCH32 \
-               \
-               \
-               \
-               ".testnet"
-#else
-#define PATCH32 ""
-#endif
+#define RELEASE ".10.beta."
 
 /*
  * Deliberate empty lines
index 22a9c839ca81c20fff30dac76f8a3f6edda957f0..2fac50504ec655d6e63672e962cf7352eb414a54 100644 (file)
@@ -1,75 +1,88 @@
-#ifndef QUERYCMDS_H
-#define QUERYCMDS_H
+/*
+ * querycmds.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_querycmds_h
+#define INCLUDED_querycmds_h
+
+struct Client;
 
-/*=============================================================================
+/*
  * Structs
  */
 
-struct lusers_st {
+struct UserStatistics {
   /* Local connections: */
-  unsigned int unknowns;       /* IsUnknown() || IsConnecting() || IsHandshake() */
-  unsigned int local_servers;  /* IsServer() && MyConnect() */
-  unsigned int local_clients;  /* IsUser() && MyConnect() */
+  unsigned int unknowns;  /* IsUnknown() || IsConnecting() || IsHandshake() */
+  unsigned int local_servers;   /* IsServer() && MyConnect() */
+  unsigned int local_clients;   /* IsUser() && MyConnect() */
+
   /* Global counts: */
-  unsigned int servers;                /* IsServer() || IsMe() */
-  unsigned int clients;                /* IsUser() */
+  unsigned int servers;         /* IsServer() || IsMe() */
+  unsigned int clients;         /* IsUser() */
+
   /* Global user mode changes: */
-  unsigned int inv_clients;    /* IsUser() && IsInvisible() */
-  unsigned int opers;          /* IsUser() && IsOper() */
+  unsigned int inv_clients;     /* IsUser() && IsInvisible() */
+  unsigned int opers;           /* IsUser() && IsOper() */
+
   /* Misc: */
   unsigned int channels;
 };
 
-/*=============================================================================
+extern struct UserStatistics UserStats;
+
+/*
  * Macros
  */
 
 /* Macros for remote connections: */
-#define Count_newremoteclient(nrof)            (++nrof.clients)
-#define Count_newremoteserver(nrof)            (++nrof.servers)
-#define Count_remoteclientquits(nrof)          (--nrof.clients)
-#define Count_remoteserverquits(nrof)          (--nrof.servers)
+#define Count_newremoteclient(UserStats, cptr)  (++UserStats.clients, ++cptr->serv->clients)
+#define Count_newremoteserver(UserStats)  (++UserStats.servers)
+#if 0
+#define Count_remoteclientquits(UserStats)      (--UserStats.clients)
+#endif
+
+#define Count_remoteclientquits(UserStats,cptr)                \
+  do { \
+    --UserStats.clients; \
+    if (!IsServer(cptr)) \
+      --cptr->user->server->serv->clients; \
+  } while (0)
+
+#define Count_remoteserverquits(UserStats)      (--UserStats.servers)
 
 /* Macros for local connections: */
-#define Count_newunknown(nrof)                 (++nrof.unknowns)
-#define Count_unknownbecomesclient(cptr, nrof) \
+#define Count_newunknown(UserStats)                     (++UserStats.unknowns)
+#define Count_unknownbecomesclient(cptr, UserStats) \
   do { \
-    --nrof.unknowns; ++nrof.local_clients; ++nrof.clients; \
+    --UserStats.unknowns; ++UserStats.local_clients; ++UserStats.clients; \
     if (match("*" DOMAINNAME, cptr->sockhost) == 0) \
       ++current_load.local_count; \
-    if (nrof.local_clients > max_client_count) \
-      max_client_count = nrof.local_clients; \
-    if (nrof.local_clients + nrof.local_servers > max_connection_count) \
+    if (UserStats.local_clients > max_client_count) \
+      max_client_count = UserStats.local_clients; \
+    if (UserStats.local_clients + UserStats.local_servers > max_connection_count) \
     { \
-      max_connection_count = nrof.local_clients + nrof.local_servers; \
+      max_connection_count = UserStats.local_clients + UserStats.local_servers; \
       if (max_connection_count % 10 == 0) \
         sendto_ops("Maximum connections: %d (%d clients)", \
-           max_connection_count, max_client_count); \
+            max_connection_count, max_client_count); \
     } \
   } while(0)
-#define Count_unknownbecomesserver(nrof)       do { --nrof.unknowns; ++nrof.local_servers; ++nrof.servers; } while(0)
-#define Count_clientdisconnects(cptr, nrof) \
+#define Count_unknownbecomesserver(UserStats)   do { --UserStats.unknowns; ++UserStats.local_servers; ++UserStats.servers; } while(0)
+#define Count_clientdisconnects(cptr, UserStats) \
   do \
   { \
-    --nrof.local_clients; --nrof.clients; \
+    --UserStats.local_clients; --UserStats.clients; \
     if (match("*" DOMAINNAME, cptr->sockhost) == 0) \
       --current_load.local_count; \
   } while(0)
-#define Count_serverdisconnects(nrof)          do { --nrof.local_servers; --nrof.servers; } while(0)
-#define Count_unknowndisconnects(nrof)         (--nrof.unknowns)
+#define Count_serverdisconnects(UserStats)              do { --UserStats.local_servers; --UserStats.servers; } while(0)
+#define Count_unknowndisconnects(UserStats)             (--UserStats.unknowns)
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern int m_version(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_info(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_links(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_help(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_admin(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-
-extern struct lusers_st nrof;
 
-#endif /* QUERYCMDS_H */
+#endif /* INCLUDED_querycmds_h */
index af18a287b526b16b38b0b800cadbec231830a67b..998106265cb19b6493114e60bb4dc5ac34044216 100644 (file)
@@ -1,10 +1,15 @@
-#ifndef RANDOM_H
-#define RANDOM_H
+/*
+ * random.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_random_h
+#define INCLUDED_random_h
 
-/*=============================================================================
+/*
  * Proto types
  */
 
 extern unsigned int ircrandom(void);
 
-#endif /* RANDOM_H */
+#endif /* INCLUDED_random_h */
index b808652f2853b26ed188b58a5fea395eb63e330d..5869f29648596dba0d43ec7fc24851c9b43de22a 100644 (file)
@@ -1,37 +1,61 @@
-#ifndef RES_H
-#define RES_H
-
-#include <netinet/in.h>
-#include <netdb.h>
-#ifdef HPUX
-#ifndef h_errno
-extern int h_errno;
-#endif
-#endif
-#include "list.h"
-
-/*=============================================================================
- * General defines
+/*
+ * irc2.7.2/ircd/res.h (C)opyright 1992 Darren Reed.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_res_h
+#define INCLUDED_res_h
 
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>       /* time_t */
+#define INCLUDED_sys_types_h
 #endif
 
-/*=============================================================================
- * Proto types
+struct Client;
+struct hostent;
+
+struct DNSReply {
+  struct hostent* hp;        /* hostent struct  */
+  int             ref_count; /* reference count */
+};
+
+struct DNSQuery {
+  void* vptr;               /* pointer used by callback to identify request */
+  void (*callback)(void* vptr, struct DNSReply* reply); /* callback to call */
+};
+
+extern int ResolverFileDescriptor;  /* GLOBAL - file descriptor (s_bsd.c) */
+
+extern void get_res(void);
+extern struct DNSReply* gethost_byname(const char* name, 
+                                       const struct DNSQuery* req);
+extern struct DNSReply* gethost_byaddr(const char* name, 
+                                       const struct DNSQuery* req);
+extern int             init_resolver(void);
+extern void            restart_resolver(void);
+extern time_t          timeout_resolver(time_t now);
+/*
+ * delete_resolver_queries - delete all outstanding queries for the
+ * pointer arg, DO NOT call this from a resolver callback function the
+ * resolver will delete the query itself for the affected client.
  */
+extern void            delete_resolver_queries(const void* vptr);
+extern unsigned long   cres_mem(struct Client* cptr);
+extern int             m_dns(struct Client* cptr, struct Client* sptr,
+                             int parc, char* parv[]);
+extern int             resolver_read(void);
+extern void            resolver_read_multiple(int count);
+extern void            flush_resolver_cache(void);
+
+/*
+ * add_local_domain - append local domain suffix to hostnames that 
+ * don't contain a dot '.'
+ * name - string to append to
+ * len  - total length of the buffer
+ * name is modified only if there is enough space in the buffer to hold
+ * the suffix
+ */
+extern void add_local_domain(char* name, size_t len);
+
+#endif /* INCLUDED_res_h */
 
-extern int init_resolver(void);
-extern time_t timeout_query_list(void);
-extern void del_queries(char *cp);
-extern void add_local_domain(char *hname, int size);
-extern struct hostent *gethost_byname(char *name, Link *lp);
-extern struct hostent *gethost_byaddr(struct in_addr *addr, Link *lp);
-extern struct hostent *get_res(char *lp);
-extern time_t expire_cache(void);
-extern void flush_cache(void);
-extern int m_dns(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern size_t cres_mem(aClient *sptr);
-
-#endif /* RES_H */
index 5b393613af93115596473900cac0198449224692..3d9820df8e5fc03780f6cd8d05134c5ce8896895 100644 (file)
@@ -5,21 +5,43 @@
  *
  * Headerfile of runmalloc.c
  *
+ * $Id$
  */
+#ifndef INCLUDED_runmalloc_h
+#define INCLUDED_runmalloc_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* size_t */
+#define INCLUDED_sys_types_h
+#endif
+
+typedef void (*OutOfMemoryHandler)(void);
+
+extern void set_nomem_handler(OutOfMemoryHandler handler);
 
-#ifndef RUNMALLOC_H
-#define RUNMALLOC_H
+#if 0
+/* 
+ * we want to be able to test in DEBUGMODE without turning
+ * DEBUGMALLOC on, change in the config not in the code
+ */
+#if defined(DEBUGMODE) && !defined(DEBUGMALLOC)
+#define DEBUGMALLOC
+#endif
+#endif
 
 #ifdef DEBUGMALLOC
 
 #if defined(MEMMAGICNUMS) && !defined(MEMSIZESTATS)
 #define MEMSIZESTATS
 #endif
+
 #ifndef MEMLEAKSTATS
 #undef MEMTIMESTATS
 #endif
 
-/*=============================================================================
+/*
  * Proto types
  */
 
@@ -31,16 +53,19 @@ extern void *RunRealloc_memleak(void *ptr, size_t size,
     int line, const char *filename);
 struct Client;
 extern void report_memleak_stats(struct Client *sptr, int parc, char *parv[]);
-#define RunMalloc(x) RunMalloc_memleak(x, __LINE__, __FILE__)
-#define RunCalloc(x,y) RunCalloc_memleak(x,y, __LINE__, __FILE__)
-#define RunRealloc(x,y) RunRealloc_memleak(x,y, __LINE__, __FILE__)
-#else
-extern void *RunMalloc(size_t size);
-extern void *RunCalloc(size_t nmemb, size_t size);
-extern void *RunRealloc(void *ptr, size_t size);
-#endif
-extern int RunFree_test(void *ptr);
-extern void RunFree(void *ptr);
+#define MyMalloc(x) RunMalloc_memleak(x, __LINE__, __FILE__)
+#define MyCalloc(x,y) RunCalloc_memleak(x,y, __LINE__, __FILE__)
+#define MyRealloc(x,y) RunRealloc_memleak(x,y, __LINE__, __FILE__)
+
+#else /* !MEMLEAKSTATS */
+extern void *MyMalloc(size_t size);
+extern void *MyCalloc(size_t nmemb, size_t size);
+extern void *MyRealloc(void *ptr, size_t size);
+#endif /* MEMLEAKSTATS */
+
+extern int MyFree_test(void *ptr);
+extern void MyFree(void *ptr);
+
 #ifdef MEMSIZESTATS
 extern unsigned int get_alloc_cnt(void);
 extern size_t get_mem_size(void);
@@ -48,19 +73,22 @@ extern size_t get_mem_size(void);
 
 #else /* !DEBUGMALLOC */
 
+#ifndef INCLUDED_stdlib_h
 #include <stdlib.h>
+#define INCLUDED_stdlib_h
+#endif
 
 #undef MEMSIZESTATS
 #undef MEMMAGICNUMS
 #undef MEMLEAKSTATS
 #undef MEMTIMESTATS
 
+#define MyFree(x) do { free((x)); (x) = 0; } while(0)
 #define Debug_malloc(x)
-#define RunMalloc(x) malloc(x)
-#define RunCalloc(x,y) calloc(x,y)
-#define RunRealloc(x,y) realloc(x,y)
-#define RunFree(x) free(x)
+extern void* MyMalloc(size_t size);
+extern void* MyCalloc(size_t nelem, size_t size);
+extern void* MyRealloc(void* x, size_t size);
 
 #endif /* DEBUGMALLOC */
 
-#endif /* RUNMALLOC_H */
+#endif /* INCLUDED_runmalloc_h */
index c325432405ad6318ff170181d4f010a1744e8d1d..30feea0ac8a10ae8a6dac31954ed75f701656833 100644 (file)
@@ -1,12 +1,75 @@
-#ifndef S_AUTH_H
-#define S_AUTH_H
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/s_auth.h
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+#ifndef INCLUDED_s_auth_h
+#define INCLUDED_s_auth_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+
+struct Client;
+
+struct AuthRequest {
+  struct AuthRequest* next;      /* linked list node ptr */
+  struct AuthRequest* prev;      /* linked list node ptr */
+  struct Client*      client;    /* pointer to client struct for request */
+  unsigned int        flags;     /* current state of request */
+  int                 fd;        /* file descriptor for auth queries */
+  int                 index;     /* select / poll index */
+  time_t              timeout;   /* time when query expires */
+};
 
-/*=============================================================================
- * Proto types
+/*
+ * flag values for AuthRequest
+ * NAMESPACE: AM_xxx - Authentication Module
  */
+#define AM_AUTH_CONNECTING   0x01
+#define AM_AUTH_PENDING      0x02
+#define AM_DNS_PENDING       0x04
+
+#define SetDNSPending(x)     ((x)->flags |= AM_DNS_PENDING)
+#define ClearDNSPending(x)   ((x)->flags &= ~AM_DNS_PENDING)
+#define IsDNSPending(x)      ((x)->flags &  AM_DNS_PENDING)
+
+#define SetAuthConnect(x)    ((x)->flags |= AM_AUTH_CONNECTING)
+#define ClearAuthConnect(x)  ((x)->flags &= ~AM_AUTH_CONNECTING)
+#define IsAuthConnect(x)     ((x)->flags &  AM_AUTH_CONNECTING)
+
+#define SetAuthPending(x)    ((x)->flags |= AM_AUTH_PENDING)
+#define ClearAuthPending(x)  ((x)->flags &= AM_AUTH_PENDING)
+#define IsAuthPending(x)     ((x)->flags &  AM_AUTH_PENDING)
+
+#define ClearAuth(x)         ((x)->flags &= ~(AM_AUTH_PENDING | AM_AUTH_CONNECTING))
+#define IsDoingAuth(x)       ((x)->flags &  (AM_AUTH_PENDING | AM_AUTH_CONNECTING))
+
+
+extern struct AuthRequest* AuthPollList; /* GLOBAL - auth queries pending io */
+
+extern void start_auth(struct Client *);
+extern void timeout_auth_queries(time_t now);
+extern void read_auth_reply(struct AuthRequest* req);
+extern void send_auth_query(struct AuthRequest* req);
+extern void remove_auth_request(struct AuthRequest *req);
 
-extern void start_auth(aClient *cptr);
-extern void send_authports(aClient *cptr);
-extern void read_authports(aClient *cptr);
+#endif /* INCLUDED_s_auth_h */
 
-#endif /* S_AUTH_H */
index a81cf0a7150335b99a9266b566709fde3abdb11f..f7aae6e765cbba54612342859329d65a43b3c5f2 100644 (file)
-#ifndef S_BSD_H
-#define S_BSD_H
-
-#include <netdb.h>
-#include "s_conf.h"
-
-/*=============================================================================
- * Macro's
+/*
+ * s_bsd.h
+ *
+ * $Id$
  */
+#ifndef INCLUDED_s_bsd_h
+#define INCLUDED_s_bsd_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* size_t, time_t */
+#define INCLUDED_sys_types_h
+#endif
 
-#define FLAGS_PINGSENT  0x0001 /* Unreplied ping sent */
-#define FLAGS_DEADSOCKET 0x0002        /* Local socket is dead--Exiting soon */
-#define FLAGS_KILLED    0x0004 /* Prevents "QUIT" from being sent for this */
-#define FLAGS_OPER      0x0008 /* Operator */
-#define FLAGS_LOCOP     0x0010 /* Local operator -- SRB */
-#define FLAGS_INVISIBLE         0x0020 /* makes user invisible */
-#define FLAGS_WALLOP    0x0040 /* send wallops to them */
-#define FLAGS_SERVNOTICE 0x0080        /* server notices such as kill */
-#define FLAGS_BLOCKED   0x0100 /* socket is in a blocked condition */
-#define FLAGS_UNIX      0x0200 /* socket is in the unix domain, not inet */
-#define FLAGS_CLOSING   0x0400 /* set when closing to suppress errors */
-#define FLAGS_LISTEN    0x0800 /* used to mark clients which we listen() on */
-#define FLAGS_CHKACCESS         0x1000 /* ok to check clients access if set */
-#define FLAGS_DOINGDNS  0x2000 /* client is waiting for a DNS response */
-#define FLAGS_AUTH      0x4000 /* client is waiting on rfc931 response */
-#define FLAGS_WRAUTH    0x8000 /* set if we havent writen to ident server */
-#define FLAGS_LOCAL    0x00010000      /* set for local clients */
-#define FLAGS_GOTID    0x00020000      /* successful ident lookup achieved */
-#define FLAGS_DOID     0x00040000      /* I-lines say must use ident return */
-#define FLAGS_NONL     0x00080000      /* No \n in buffer */
-#define FLAGS_TS8              0x00100000      /* Why do you want to know? */
-#define FLAGS_PING     0x00200000      /* Socket needs to send udp pings */
-#define FLAGS_ASKEDPING        0x00400000      /* Client asked for udp ping */
-#define FLAGS_MAP      0x00800000      /* Show server on the map */
-#define FLAGS_JUNCTION 0x01000000      /* Junction causing the net.burst */
-#define FLAGS_DEAF     0x02000000      /* Makes user deaf */
-#define FLAGS_CHSERV   0x04000000      /* Disallow KICK or MODE -o on the user;
-                                          don't display channels in /whois */
-#define FLAGS_BURST    0x08000000      /* Server is receiving a net.burst */
-#define FLAGS_BURST_ACK        0x10000000      /* Server is waiting for eob ack */
-#define FLAGS_DEBUG    0x20000000      /* send global debug/anti-hack info */
-#define FLAGS_IPCHECK  0x40000000      /* Added or updated IPregistry data */
-
-#define SEND_UMODES \
-    (FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_DEAF|FLAGS_CHSERV|FLAGS_DEBUG)
-#define ALL_UMODES (SEND_UMODES|FLAGS_SERVNOTICE|FLAGS_LOCOP)
-#define FLAGS_ID (FLAGS_DOID|FLAGS_GOTID)
+struct Client;
+struct ConfItem;
+struct Listener;
+struct DNSReply;
 
 /*
- * flags macros.
+ * TCP window sizes
+ * Set server window to a large value for fat pipes,
+ * set client to a smaller size to allow TCP flow control
+ * to reduce flooding
  */
-#define IsOper(x)              ((x)->flags & FLAGS_OPER)
-#define IsLocOp(x)             ((x)->flags & FLAGS_LOCOP)
-#define IsInvisible(x)         ((x)->flags & FLAGS_INVISIBLE)
-#define IsDeaf(x)              ((x)->flags & FLAGS_DEAF)
-#define IsChannelService(x)    ((x)->flags & FLAGS_CHSERV)
-#define IsAnOper(x)            ((x)->flags & (FLAGS_OPER|FLAGS_LOCOP))
-#define IsPrivileged(x)                (IsAnOper(x) || IsServer(x))
-#define SendWallops(x)         ((x)->flags & FLAGS_WALLOP)
-#define SendDebug(x)            ((x)->flags & FLAGS_DEBUG)
-#define SendServNotice(x)      ((x)->flags & FLAGS_SERVNOTICE)
-#define IsUnixSocket(x)                ((x)->flags & FLAGS_UNIX)
-#define IsListening(x)         ((x)->flags & FLAGS_LISTEN)
-#define DoAccess(x)            ((x)->flags & FLAGS_CHKACCESS)
-#define IsLocal(x)             ((x)->flags & FLAGS_LOCAL)
-#define IsDead(x)              ((x)->flags & FLAGS_DEADSOCKET)
-#define IsJunction(x)          ((x)->flags & FLAGS_JUNCTION)
-#define IsBurst(x)             ((x)->flags & FLAGS_BURST)
-#define IsBurstAck(x)          ((x)->flags & FLAGS_BURST_ACK)
-#define IsBurstOrBurstAck(x)   ((x)->flags & (FLAGS_BURST|FLAGS_BURST_ACK))
-#define IsIPChecked(x)         ((x)->flags & FLAGS_IPCHECK)
-
-#define SetOper(x)             ((x)->flags |= FLAGS_OPER)
-#define SetLocOp(x)            ((x)->flags |= FLAGS_LOCOP)
-#define SetInvisible(x)                ((x)->flags |= FLAGS_INVISIBLE)
-#define SetWallops(x)          ((x)->flags |= FLAGS_WALLOP)
-#define SetDebug(x)             ((x)->flags |= FLAGS_DEBUG)
-#define SetUnixSock(x)         ((x)->flags |= FLAGS_UNIX)
-#define SetDNS(x)              ((x)->flags |= FLAGS_DOINGDNS)
-#define DoingDNS(x)            ((x)->flags & FLAGS_DOINGDNS)
-#define SetAccess(x)           ((x)->flags |= FLAGS_CHKACCESS)
-#define DoingAuth(x)           ((x)->flags & FLAGS_AUTH)
-#define NoNewLine(x)           ((x)->flags & FLAGS_NONL)
-#define DoPing(x)              ((x)->flags & FLAGS_PING)
-#define SetAskedPing(x)                ((x)->flags |= FLAGS_ASKEDPING)
-#define AskedPing(x)           ((x)->flags & FLAGS_ASKEDPING)
-#define SetJunction(x)         ((x)->flags |= FLAGS_JUNCTION)
-#define SetBurst(x)            ((x)->flags |= FLAGS_BURST)
-#define SetBurstAck(x)         ((x)->flags |= FLAGS_BURST_ACK)
-#define SetIPChecked(x)                ((x)->flags |= FLAGS_IPCHECK)
-
-#define ClearOper(x)           ((x)->flags &= ~FLAGS_OPER)
-#define ClearLocOp(x)          ((x)->flags &= ~FLAGS_LOCOP)
-#define ClearInvisible(x)      ((x)->flags &= ~FLAGS_INVISIBLE)
-#define ClearWallops(x)                ((x)->flags &= ~FLAGS_WALLOP)
-#define ClearDebug(x)           ((x)->flags &= ~FLAGS_DEBUG)
-#define ClearDNS(x)            ((x)->flags &= ~FLAGS_DOINGDNS)
-#define ClearAuth(x)           ((x)->flags &= ~FLAGS_AUTH)
-#define ClearAccess(x)         ((x)->flags &= ~FLAGS_CHKACCESS)
-#define ClearPing(x)           ((x)->flags &= ~FLAGS_PING)
-#define ClearAskedPing(x)      ((x)->flags &= ~FLAGS_ASKEDPING)
-#define ClearBurst(x)          ((x)->flags &= ~FLAGS_BURST)
-#define ClearBurstAck(x)       ((x)->flags &= ~FLAGS_BURST_ACK)
-
-/* used for async dns values */
-
-#define ASYNC_NONE     0
-#define ASYNC_CLIENT   1
-#define ASYNC_CONNECT  2
-#define ASYNC_CONF     3
-#define ASYNC_PING     4
-
-/* server notice stuff */
-
-#define SNO_ADD                1
-#define SNO_DEL                2
-#define SNO_SET                3
-                               /* DON'T CHANGE THESE VALUES ! */
-                               /* THE CLIENTS DEPEND ON IT  ! */
-#define SNO_OLDSNO     0x1     /* unsorted old messages */
-#define SNO_SERVKILL   0x2     /* server kills (nick collisions) */
-#define SNO_OPERKILL   0x4     /* oper kills */
-#define SNO_HACK2      0x8     /* desyncs */
-#define SNO_HACK3      0x10    /* temporary desyncs */
-#define SNO_UNAUTH     0x20    /* unauthorized connections */
-#define SNO_TCPCOMMON  0x40    /* common TCP or socket errors */
-#define SNO_TOOMANY    0x80    /* too many connections */
-#define SNO_HACK4      0x100   /* Uworld actions on channels */
-#define SNO_GLINE      0x200   /* glines */
-#define SNO_NETWORK    0x400   /* net join/break, etc */
-#define SNO_IPMISMATCH 0x800   /* IP mismatches */
-#define SNO_THROTTLE   0x1000  /* host throttle add/remove notices */
-#define SNO_OLDREALOP  0x2000  /* old oper-only messages */
-#define SNO_CONNEXIT   0x4000  /* client connect/exit (ugh) */
-
-#define SNO_ALL                0x7fff  /* Don't make it larger then significant,
-                                * that looks nicer */
-
-#define SNO_USER       (SNO_ALL & ~SNO_OPER)
-
-#define SNO_DEFAULT (SNO_NETWORK|SNO_OPERKILL|SNO_GLINE)
-#define SNO_OPERDEFAULT (SNO_DEFAULT|SNO_HACK2|SNO_HACK4|SNO_THROTTLE|SNO_OLDSNO)
-#define SNO_OPER (SNO_CONNEXIT|SNO_OLDREALOP)
-#define SNO_NOISY (SNO_SERVKILL|SNO_UNAUTH)
+#define SERVER_TCP_WINDOW 61440
+#define CLIENT_TCP_WINDOW 2048
 
+extern void report_error(const char* text, const char* who, int err);
 /*
- * simple defines to differentiate between a tty and socket for
- * add_connection()  -Simon
+ * text for report_error
  */
+extern const char* const BIND_ERROR_MSG;
+extern const char* const LISTEN_ERROR_MSG;
+extern const char* const NONB_ERROR_MSG;
+extern const char* const REUSEADDR_ERROR_MSG;
+extern const char* const SOCKET_ERROR_MSG;
+extern const char* const CONNLIMIT_ERROR_MSG;
+extern const char* const ACCEPT_ERROR_MSG;
+extern const char* const PEERNAME_ERROR_MSG;
+extern const char* const POLL_ERROR_MSG;
+extern const char* const SELECT_ERROR_MSG;
+extern const char* const CONNECT_ERROR_MSG;
+extern const char* const SETBUFS_ERROR_MSG;
+
+
+extern int            HighestFd;
+extern struct Client* LocalClientArray[MAXCONNECTIONS];
+extern int            OpenFileDescriptorCount;
 
-#define ADCON_TTY 0
-#define ADCON_SOCKET 1
+#ifdef VIRTUAL_HOST
+extern struct sockaddr_in vserv;
+#endif
 
-/*=============================================================================
+enum PollType {
+  PT_NONE,
+  PT_READ,
+  PT_WRITE
+};
+
+struct Pollable;
+
+typedef int (*PollReadyFn)(struct Pollable*);
+
+struct Pollable {
+  struct Pollable* next;
+  struct Pollable* prev;
+  int              fd;
+  int              index;
+  int              state;
+  PollReadyFn      r_handler;
+  PollReadyFn      w_handler;
+};
+  
+/*
  * Proto types
  */
-
-extern int setsnomask(aClient *cptr, snomask_t newmask, int what);
-extern snomask_t umode_make_snomask(snomask_t oldmask, char *arg, int what);
-extern int connect_server(aConfItem *aconf, aClient *by, struct hostent *hp);
-extern void report_error(char *text, aClient *cptr);
-extern int inetport(aClient *cptr, char *name, unsigned short int port);
-extern int add_listener(aConfItem *aconf);
-extern void close_listeners(void);
+extern size_t deliver_it(struct Client *cptr, const char *str, size_t len);
+extern int connect_server(struct ConfItem* aconf, struct Client* by,
+                          struct DNSReply* reply);
+extern void release_dns_reply(struct Client* cptr);
+extern int  net_close_unregistered_connections(struct Client* source);
 extern void init_sys(void);
-extern void write_pidfile(void);
-extern enum AuthorizationCheckResult check_client(aClient *cptr);
-extern int check_server(aClient *cptr);
-extern void close_connection(aClient *cptr);
-extern int get_sockerr(aClient *cptr);
-extern void set_non_blocking(int fd, aClient *cptr);
-extern aClient *add_connection(aClient *cptr, int fd, int type);
-extern int read_message(time_t delay);
-extern void get_my_name(aClient *cptr);
-extern int setup_ping(void);
-
-extern int highest_fd, resfd;
-extern unsigned int readcalls;
-extern aClient *loc_clients[MAXCONNECTIONS];
-#ifdef VIRTUAL_HOST
-extern struct sockaddr_in vserv;
-#endif
+extern void close_connection(struct Client *cptr);
+extern void add_connection(struct Listener* listener, int fd);
+extern int  read_message(time_t delay);
+extern int init_server_identity(void);
 
-#endif /* S_BSD_H */
+#endif /* INCLUDED_s_bsd_h */
index bedc3dc113219a136a38601672781688327b207d..7469bce569ced779cbc60f585b5bcc10682e43ec 100644 (file)
@@ -1,67 +1,79 @@
-#ifndef S_CONF_H
-#define S_CONF_H
+/*
+ * s_conf.h
+ *
+ * $Id$ 
+ */
+#ifndef INCLUDED_s_conf_h
+#define INCLUDED_s_conf_h
+#ifndef INCLUDED_time_h
+#include <time.h>              /* struct tm */
+#define INCLUDED_time_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>        /* struct in_addr */
+#define INCLUDED_netinet_in_h
+#endif
 
-#include "list.h"
-#include <netinet/in.h>
-#include <netdb.h>
+struct Client;
+struct SLink;
+struct TRecord;
+struct hostent;
 
-/*=============================================================================
+
+/*
  * General defines
  */
 
 /*-----------------------------------------------------------------------------
- * Macro's
+ * Macros
  */
 
-#define CONF_ILLEGAL           0x80000000
-#define CONF_MATCH             0x40000000
-#define CONF_CLIENT            0x0002
-#define CONF_CONNECT_SERVER    0x0004
-#define CONF_NOCONNECT_SERVER  0x0008
-#define CONF_LOCOP             0x0010
-#define CONF_OPERATOR          0x0020
-#define CONF_ME                        0x0040
-#define CONF_KILL              0x0080
-#define CONF_ADMIN             0x0100
-#ifdef R_LINES
-#define CONF_RESTRICT          0x0200
-#endif
-#define CONF_CLASS             0x0400
-#define CONF_LEAF              0x1000
-#define CONF_LISTEN_PORT       0x2000
-#define CONF_HUB               0x4000
-#define CONF_UWORLD            0x8000
-#define CONF_CRULEALL          0x00200000
-#define CONF_CRULEAUTO         0x00400000
-#define CONF_TLINES            0x00800000
-#define CONF_IPKILL            0x00010000
-
-#define CONF_OPS               (CONF_OPERATOR | CONF_LOCOP)
-#define CONF_SERVER_MASK       (CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER)
-#define CONF_CLIENT_MASK       (CONF_CLIENT | CONF_OPS | CONF_SERVER_MASK)
-#define CONF_CRULE             (CONF_CRULEALL | CONF_CRULEAUTO)
-#define CONF_KLINE             (CONF_KILL | CONF_IPKILL)
-
-#define IsIllegal(x)   ((x)->status & CONF_ILLEGAL)
-
-/*=============================================================================
+#define CONF_ILLEGAL            0x80000000
+#define CONF_MATCH              0x40000000
+#define CONF_CLIENT             0x0002
+#define CONF_SERVER             0x0004
+#define CONF_LOCOP              0x0010
+#define CONF_OPERATOR           0x0020
+#define CONF_ME                 0x0040
+#define CONF_KILL               0x0080
+#define CONF_ADMIN              0x0100
+#define CONF_CLASS              0x0400
+#define CONF_LEAF               0x1000
+#define CONF_LISTEN_PORT        0x2000
+#define CONF_HUB                0x4000
+#define CONF_UWORLD             0x8000
+#define CONF_CRULEALL           0x00200000
+#define CONF_CRULEAUTO          0x00400000
+#define CONF_TLINES             0x00800000
+#define CONF_IPKILL             0x00010000
+
+#define CONF_OPS                (CONF_OPERATOR | CONF_LOCOP)
+#define CONF_CLIENT_MASK        (CONF_CLIENT | CONF_OPS | CONF_SERVER)
+#define CONF_CRULE              (CONF_CRULEALL | CONF_CRULEAUTO)
+#define CONF_KLINE              (CONF_KILL | CONF_IPKILL)
+
+#define IsIllegal(x)    ((x)->status & CONF_ILLEGAL)
+
+/*
  * Structures
  */
 
 struct ConfItem {
-  unsigned int status;         /* If CONF_ILLEGAL, delete when no clients */
-  unsigned int clients;                /* Number of *LOCAL* clients using this */
-  struct in_addr ipnum;                /* ip number of host field */
-  char *host;
-  char *passwd;
-  char *name;
+  unsigned int       status;    /* If CONF_ILLEGAL, delete when no clients */
+  unsigned int       clients;   /* Number of *LOCAL* clients using this */
+  struct in_addr     ipnum;     /* ip number of host field */
+  char*              host;
+  char*              passwd;
+  char*              name;
   unsigned short int port;
-  time_t hold;                 /* Hold action until this time
-                                  (calendar time) */
-#ifndef VMSP
-  struct ConfClass *confClass; /* Class of connection */
-#endif
-  struct ConfItem *next;
+  time_t             hold;      /* Hold until this time (calendar time) */
+  int                dns_pending; /* a dns request is pending */
+  struct ConfClass*  confClass; /* Class of connection */
+  struct ConfItem*   next;
 };
 
 struct MotdItem {
@@ -69,11 +81,11 @@ struct MotdItem {
   struct MotdItem *next;
 };
 
-struct trecord {
+struct TRecord {
   char *hostmask;
   struct MotdItem *tmotd;
   struct tm tmotd_tm;
-  struct trecord *next;
+  struct TRecord *next;
 };
 
 enum AuthorizationCheckResult {
@@ -85,41 +97,46 @@ enum AuthorizationCheckResult {
   ACR_BAD_SOCKET
 };
 
-/*=============================================================================
+/*
+ * GLOBALS
+ */
+extern struct ConfItem* GlobalConfList;
+extern int              GlobalConfCount;
+extern struct tm        motd_tm;
+extern struct MotdItem* motd;
+extern struct MotdItem* rmotd;
+extern struct TRecord*  tdata;
+
+/*
  * Proto types
  */
+extern struct ConfItem* attach_confs_byhost(struct Client* cptr, 
+                                            const char* host, int statmask);
+extern struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host,
+                                         int statmask);
+extern struct ConfItem* find_conf_byname(struct SLink* lp, const char *name,
+                                         int statmask);
+extern struct ConfItem* conf_find_server(const char* name);
+const char* conf_eval_crule(struct ConfItem* conf);
 
-extern aConfItem *find_conf_host(Link *lp, char *host, int statmask);
-extern void det_confs_butmask(aClient *cptr, int mask);
-extern enum AuthorizationCheckResult attach_Iline(aClient *cptr,
-    struct hostent *hp, char *sockhost);
-extern aConfItem *count_cnlines(Link *lp);
-extern int detach_conf(aClient *cptr, aConfItem *aconf);
-extern enum AuthorizationCheckResult attach_conf(aClient *cptr,
-    aConfItem *aconf);
-extern aConfItem *find_admin(void);
-extern aConfItem *find_me(void);
-extern aConfItem *attach_confs(aClient *cptr, const char *name, int statmask);
-extern aConfItem *attach_confs_host(aClient *cptr, char *host, int statmask);
-extern aConfItem *find_conf_exact(char *name, char *user, char *host,
-    int statmask);
-extern aConfItem *find_conf_name(char *name, int statmask);
-extern aConfItem *find_conf(Link *lp, const char *name, int statmask);
-extern aConfItem *find_conf_ip(Link *lp, char *ip, char *user, int statmask);
-extern int rehash(aClient *cptr, int sig);
+extern void det_confs_butmask(struct Client *cptr, int mask);
+extern int attach_iline(struct Client *cptr);
+extern int detach_conf(struct Client *cptr, struct ConfItem *aconf);
+extern int attach_conf(struct Client *cptr, struct ConfItem *aconf);
+extern struct ConfItem* find_admin(void);
+extern struct ConfItem* find_me(void);
+extern struct ConfItem* find_conf_exact(const char* name, 
+                                        const char* user,
+                                        const char* host, int statmask);
+extern enum AuthorizationCheckResult conf_check_client(struct Client *cptr);
+extern int  conf_check_server(struct Client *cptr);
+extern struct ConfItem* find_conf_name(const char* name, int statmask);
+extern int rehash(struct Client *cptr, int sig);
 extern int initconf(int opt);
 extern void read_tlines(void);
-extern int find_kill(aClient *cptr);
-extern int find_restrict(aClient *cptr);
-extern int m_killcomment(aClient *sptr, char *parv, char *filename);
-extern aMotdItem *read_motd(char *motdfile);
-
-extern aConfItem *conf;
-extern aGline *gline;
-extern aGline *badchan;
-extern struct tm motd_tm;
-extern aMotdItem *motd;
-extern aMotdItem *rmotd;
-extern atrecord *tdata;
-
-#endif /* S_CONF_H */
+extern int find_kill(struct Client *cptr);
+extern int find_restrict(struct Client *cptr);
+extern int m_killcomment(struct Client *sptr, char *parv, char *filename);
+extern struct MotdItem* read_motd(const char* motdfile);
+
+#endif /* INCLUDED_s_conf_h */
index 8f93fca6fe184fac249966d3dde9996dd6575183..5bcc69bf647fd86f00b9228a157ca18d4fd4cb7c 100644 (file)
@@ -1,14 +1,26 @@
-#ifndef S_DEBUG_H
-#define S_DEBUG_H
-
+/*
+ * s_debug.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_s_debug_h
+#define INCLUDED_s_debug_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"       /* Needed for HOSTLEN */
+#endif
+#ifndef INCLUDED_stdarg_h
 #include <stdarg.h>
-#ifdef MSGLOG_ENABLED
-#include "struct.h"            /* Needed for HOSTLEN */
+#define INCLUDED_stdarg_h
 #endif
 
+struct Client;
+
 #ifdef DEBUGMODE
 
-/*=============================================================================
+/*
  * Macro's
  */
 
  * defined debugging levels
  */
 #define DEBUG_FATAL  0
-#define DEBUG_ERROR  1         /* report_error() and other
-                                  errors that are found */
+#define DEBUG_ERROR  1  /* report_error() and other errors that are found */
 #define DEBUG_NOTICE 3
-#define DEBUG_DNS    4         /* used by all DNS related routines - a *lot* */
-#define DEBUG_INFO   5         /* general usful info */
-#define DEBUG_NUM    6         /* numerics */
-#define DEBUG_SEND   7         /* everything that is sent out */
-#define DEBUG_DEBUG  8         /* anything to do with debugging,
-                                  ie unimportant :) */
-#define DEBUG_MALLOC 9         /* malloc/free calls */
-#define DEBUG_LIST  10         /* debug list use */
+#define DEBUG_DNS    4  /* used by all DNS related routines - a *lot* */
+#define DEBUG_INFO   5  /* general useful info */
+#define DEBUG_NUM    6  /* numerics */
+#define DEBUG_SEND   7  /* everything that is sent out */
+#define DEBUG_DEBUG  8  /* everything that is received */ 
+#define DEBUG_MALLOC 9  /* malloc/free calls */
+#define DEBUG_LIST  10  /* debug list use */
 
-/*=============================================================================
+/*
  * proto types
  */
 
 extern void vdebug(int level, const char *form, va_list vl);
-extern void debug(int level, const char *form, ...)
-    __attribute__ ((format(printf, 2, 3)));
-extern void send_usage(aClient *cptr, char *nick);
+extern void debug(int level, const char *form, ...);
+extern void send_usage(struct Client *cptr, char *nick);
 
 #else /* !DEBUGMODE */
 
@@ -47,110 +56,8 @@ extern void send_usage(aClient *cptr, char *nick);
 
 #endif /* !DEBUGMODE */
 
-extern void count_memory(aClient *cptr, char *nick);
+extern void open_debugfile(void);
+extern void count_memory(struct Client *cptr, char *nick);
 extern char serveropts[];
 
-/*=============================================================================
- * Message logging service
- */
-
-/*
- * Message levels: these are inclusive, i.e. a message that is LEVEL_MAP
- * affects also clients and channels and is propagated and needs a query of
- * some status, and therefore belongs to all the classes, in the same way
- * _every_ message is parsed so belongs to LEVEL_PARSED
- */
-
-/* Messages that affect servers' map */
-#define LEVEL_MAP      6
-
-/* Messages that affect clients existance */
-#define LEVEL_CLIENT   5
-
-/* Messages that affect channel existance */
-#define LEVEL_CHANNEL  4
-
-/* Messages that affect channel modes */
-#define LEVEL_MODE     3
-
-/* Messages that are only to be propagated somewhere */
-#define LEVEL_PROPAGATE 2
-
-/*
- * Messages that only perform queries
- * note how every message may need some status query over data structs
- * and at the same time every query might need to be propagated
- * somewhere... so the distinction between levels PROPAGATE and
- * QUERY is quite fuzzy
- */
-#define LEVEL_QUERY    1
-
-/* Messages that only perform queries */
-#define LEVEL_PARSED   0
-
-#ifdef MSGLOG_ENABLED
-
-/*=============================================================================
- * Macro's
- */
-
-#define LogMessage(x) Log_Message x
-#define StoreBuffer(x) Store_Buffer x
-
-/* Logging mask, selection on type of connection */
-#define LOG_PING       (0x8000 >> (8 + STAT_PING))
-#define LOG_LOG                (0x8000 >> (8 + STAT_LOG))
-#define LOG_CONNECTING (0x8000 >> (8 + STAT_CONNECTING))
-#define LOG_HANDSHAKE  (0x8000 >> (8 + STAT_HANDSHAKE))
-#define LOG_ME         (0x8000 >> (8 + STAT_ME))
-#define LOG_UNKNOWN    (0x8000 >> (8 + STAT_UNKNOWN))
-#define LOG_SERVER     (0x8000 >> (8 + STAT_SERVER))
-#define LOG_CLIENT     (0x8000 >> (8 + STAT_USER))
-
-/*
- * Define here the type of connection(s) that will be monitored.
- * Default is to log messages coming from any connection.
- */
-#define LOG_MASK_TYPE \
-    ( LOG_PING | LOG_LOG | LOG_CONNECTING | \
-      LOG_HANDSHAKE | LOG_ME | LOG_UNKNOWN | LOG_SERVER | LOG_CLIENT )
-
-/*=============================================================================
- * data structures
- */
-
-struct log_entry {
-  int cptr_status;
-  char cptr_name[HOSTLEN + 1];
-  char cptr_yxx[3];
-  int cptr_fd;
-
-  int sptr_status;
-  char sptr_name[HOSTLEN + 1];
-  char sptr_yxx[4];
-  char sptr_from_name[HOSTLEN + 1];
-
-  char buffer[512];
-
-  /* The following may be lost before log gets used,
-     anyhow they are only here for usage through gdb */
-
-  aClient *cptr;
-  aClient *sptr;
-};
-
-/*=============================================================================
- * proto types
- */
-
-extern void Log_Message(aClient *sptr, int msgclass);
-extern void Store_Buffer(char *buf, aClient *cptr);
-
-#else /* !MSGLOG_ENABLED */
-
-#define LogMessage(x)
-#define StoreBuffer(x)
-
-#endif /* !MSGLOG_ENABLED */
-
-#endif /* S_DEBUG_H */
+#endif /* INCLUDED_s_debug_h */
diff --git a/include/s_err.h b/include/s_err.h
deleted file mode 100644 (file)
index ee746ae..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef S_ERR_H
-#define S_ERR_H
-
-/*=============================================================================
- * Proto types
- */
-
-extern char *err_str(int numeric);
-extern char *rpl_str(int numeric);
-
-#endif /* S_ERR_H */
index e53b7dfcaf483b3b800b3db319e5d40649bb3873..7c82b170fdbf026e6478bc72e274b494e05977de 100644 (file)
@@ -1,71 +1,82 @@
-#ifndef S_MISC_H
-#define S_MISC_H
-
-/*=============================================================================
- * General defines
+/*
+ * s_misc.h
+ *
+ * $Id$
  */
+#ifndef INCLUDED_s_misc_h
+#define INCLUDED_s_misc_h
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>           /* va_list */
+#define INCLUDED_stdarg_h
+#endif
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>        /* time_t */
+#define INCLUDED_sys_types_h
+#endif
+
+
+struct Client;
+struct ConfItem;
 
 /*-----------------------------------------------------------------------------
- * Macro's
+ * Macros
  */
 
-#define CPTR_KILLED    -2
+#define CPTR_KILLED     -2
 
-/*=============================================================================
+/*
  * Structures
  */
 
-struct stats {
-  unsigned int is_cl;          /* number of client connections */
-  unsigned int is_sv;          /* number of server connections */
-  unsigned int is_ni;          /* connection but no idea who it was */
-  unsigned short int is_cbs;   /* bytes sent to clients */
-  unsigned short int is_cbr;   /* bytes received to clients */
-  unsigned short int is_sbs;   /* bytes sent to servers */
-  unsigned short int is_sbr;   /* bytes received to servers */
-  unsigned int is_cks;         /* k-bytes sent to clients */
-  unsigned int is_ckr;         /* k-bytes received to clients */
-  unsigned int is_sks;         /* k-bytes sent to servers */
-  unsigned int is_skr;         /* k-bytes received to servers */
-  time_t is_cti;               /* time spent connected by clients */
-  time_t is_sti;               /* time spent connected by servers */
-  unsigned int is_ac;          /* connections accepted */
-  unsigned int is_ref;         /* accepts refused */
-  unsigned int is_unco;                /* unknown commands */
-  unsigned int is_wrdi;                /* command going in wrong direction */
-  unsigned int is_unpf;                /* unknown prefix */
-  unsigned int is_empt;                /* empty message */
-  unsigned int is_num;         /* numeric message */
-  unsigned int is_kill;                /* number of kills generated on collisions */
-  unsigned int is_fake;                /* MODE 'fakes' */
-  unsigned int is_asuc;                /* successful auth requests */
-  unsigned int is_abad;                /* bad auth requests */
-  unsigned int is_udp;         /* packets recv'd on udp port */
-  unsigned int is_loc;         /* local connections made */
+struct ServerStatistics {
+  unsigned int is_cl;           /* number of client connections */
+  unsigned int is_sv;           /* number of server connections */
+  unsigned int is_ni;           /* connection but no idea who it was */
+  unsigned short int is_cbs;    /* bytes sent to clients */
+  unsigned short int is_cbr;    /* bytes received to clients */
+  unsigned short int is_sbs;    /* bytes sent to servers */
+  unsigned short int is_sbr;    /* bytes received to servers */
+  unsigned int is_cks;          /* k-bytes sent to clients */
+  unsigned int is_ckr;          /* k-bytes received to clients */
+  unsigned int is_sks;          /* k-bytes sent to servers */
+  unsigned int is_skr;          /* k-bytes received to servers */
+  time_t is_cti;                /* time spent connected by clients */
+  time_t is_sti;                /* time spent connected by servers */
+  unsigned int is_ac;           /* connections accepted */
+  unsigned int is_ref;          /* accepts refused */
+  unsigned int is_unco;         /* unknown commands */
+  unsigned int is_wrdi;         /* command going in wrong direction */
+  unsigned int is_unpf;         /* unknown prefix */
+  unsigned int is_empt;         /* empty message */
+  unsigned int is_num;          /* numeric message */
+  unsigned int is_kill;         /* number of kills generated on collisions */
+  unsigned int is_fake;         /* MODE 'fakes' */
+  unsigned int is_asuc;         /* successful auth requests */
+  unsigned int is_abad;         /* bad auth requests */
+  unsigned int is_loc;          /* local connections made */
+  unsigned int uping_recv;      /* UDP Pings received */
 };
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern int check_registered(aClient *sptr);
-extern int check_registered_user(aClient *sptr);
-extern int exit_client(aClient *cptr, aClient *bcptr,
-    aClient *sptr, char *comment);
+extern int check_registered(struct Client *sptr);
+extern int check_registered_user(struct Client *sptr);
+extern int exit_client(struct Client *cptr, struct Client *bcptr,
+    struct Client *sptr, char *comment);
 extern char *myctime(time_t value);
-extern char *get_client_name(aClient *sptr, int showip);
-extern int exit_client_msg(aClient *cptr, aClient *bcptr,
-    aClient *sptr, char *pattern, ...) __attribute__ ((format(printf, 4, 5)));
+extern int exit_client_msg(struct Client *cptr, struct Client *bcptr,
+                           struct Client *sptr, char *pattern, ...);
 extern void initstats(void);
 extern char *date(time_t clock);
-extern char *get_client_host(aClient *cptr);
-extern void get_sockhost(aClient *cptr, char *host);
-extern char *my_name_for_link(char *name, aConfItem *aconf);
-extern int vexit_client_msg(aClient *cptr, aClient *bcptr,
-    aClient *sptr, char *pattern, va_list vl);
-extern void checklist(void);
-extern void tstats(aClient *cptr, char *name);
+extern const char* get_client_host(const struct Client *cptr);
+extern void get_sockhost(struct Client *cptr, char *host);
+extern int vexit_client_msg(struct Client *cptr, struct Client *bcptr,
+    struct Client *sptr, char *pattern, va_list vl);
+extern void tstats(struct Client *cptr, char *name);
+
+extern struct ServerStatistics* ServerStats;
 
-extern struct stats *ircstp;
+#endif /* INCLUDED_s_misc_h */
 
-#endif /* S_MISC_H */
index 0c148b312a5d9b2661c1aa69cd748e5ef2a15f73..355b0c7ea39427180c1ccbafd398679097b8f672 100644 (file)
@@ -1,11 +1,18 @@
-#ifndef S_NUMERIC_H
-#define S_NUMERIC_H
+/*
+ * s_numeric.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_s_numeric_h
+#define INCLUDED_s_numeric_h
+
+struct Client;
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern int do_numeric(int numeric, int nnn, aClient *cptr, aClient *sptr,
+extern int do_numeric(int numeric, int nnn, struct Client *cptr, struct Client *sptr,
     int parc, char *parv[]);
 
-#endif /* S_NUMERIC_H */
+#endif /* INCLUDED_s_numeric_h */
diff --git a/include/s_ping.h b/include/s_ping.h
deleted file mode 100644 (file)
index 20ff1fd..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef S_PING_H
-#define S_PING_H
-
-/*=============================================================================
- * Proto types
- */
-
-extern int start_ping(aClient *cptr);
-extern void send_ping(aClient *cptr);
-extern void read_ping(aClient *cptr);
-extern int ping_server(aClient *cptr);
-extern int m_uping(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern void end_ping(aClient *cptr);
-extern void cancel_ping(aClient *sptr, aClient *acptr);
-
-#endif /* S_PING_H */
index 8d407975bdcdf79111fa78130cc1d2c3f15bb872..e0785730d3f8ae8233499a36c70c291474d849f2 100644 (file)
@@ -1,93 +1,29 @@
-#ifndef S_SERV_H
-#define S_SERV_H
-
-#include "struct.h"
-
-/*=============================================================================
- * General defines
+/*
+ * s_serv.h
+ *
+ * $Id$
  */
+#ifndef INCLUDED_s_serv_h
+#define INCLUDED_s_serv_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
 
-/*-----------------------------------------------------------------------------
- * Macro's
- */
+struct ConfItem;
+struct Client;
 
-#define STAT_PING              0
-#define STAT_LOG               1       /* logfile for -x */
-#define STAT_CONNECTING                2
-#define STAT_HANDSHAKE         3
-#define STAT_ME                        4
-#define STAT_UNKNOWN           5
-#define STAT_UNKNOWN_USER      6       /* Connect to client port */
-#define STAT_UNKNOWN_SERVER    7       /* Connect to server port */
-#define STAT_SERVER            8
-#define STAT_USER              9
 
-/* 
- * for when you wanna create a bitmask of status values
- */
-#define StatusMask(T) (1<<(T))
-#define IsStatMask(x, s) (StatusMask((x)->status) & (s))
+extern unsigned int max_connection_count;
+extern unsigned int max_client_count;
 
 /*
- * status macros.
+ * Prototypes
  */
-#define IsRegistered(x)                (IsStatMask(x, \
-                                       StatusMask(STAT_SERVER)|\
-                                       StatusMask(STAT_USER)))
-#define IsConnecting(x)                ((x)->status == STAT_CONNECTING)
-#define IsHandshake(x)         ((x)->status == STAT_HANDSHAKE)
-#define IsMe(x)                        ((x)->status == STAT_ME)
-#define IsUnknown(x)           (IsStatMask(x, \
-                                       StatusMask(STAT_UNKNOWN)|\
-                                       StatusMask(STAT_UNKNOWN_USER)|\
-                                       StatusMask(STAT_UNKNOWN_SERVER)))
-#define IsServerPort(x)                ((x)->status == STAT_UNKNOWN_SERVER )
-#define IsUserPort(x)          ((x)->status == STAT_UNKNOWN_USER )
-#define IsClient(x)            (IsStatMask(x, \
-                                       StatusMask(STAT_HANDSHAKE)|\
-                                       StatusMask(STAT_ME)|\
-                                       StatusMask(STAT_UNKNOWN)|\
-                                       StatusMask(STAT_UNKNOWN_USER)|\
-                                       StatusMask(STAT_UNKNOWN_SERVER)|\
-                                       StatusMask(STAT_SERVER)|\
-                                       StatusMask(STAT_USER)))
-#define IsTrusted(x)           (IsStatMask(x, \
-                                       StatusMask(STAT_PING)|\
-                                       StatusMask(STAT_LOG)|\
-                                       StatusMask(STAT_CONNECTING)|\
-                                       StatusMask(STAT_HANDSHAKE)|\
-                                       StatusMask(STAT_ME)|\
-                                       StatusMask(STAT_SERVER)))
-#ifdef DEBUGMODE               /* Coredump if we miss something... */
-#define IsServer(x)            ( ((x)->status == STAT_SERVER) && \
-                                  (((x)->serv) ? 1 : (*((char *) NULL) = 0)) )
-#define IsUser(x)              ( ((x)->status == STAT_USER) && \
-                                  (((x)->user) ? 1 : (*((char *) NULL) = 0)) )
-#else
-#define IsServer(x)            ((x)->status == STAT_SERVER)
-#define IsUser(x)              ((x)->status == STAT_USER)
-#endif
-#define IsLog(x)               ((x)->status == STAT_LOG)
-#define IsPing(x)              ((x)->status == STAT_PING)
-
-#define SetConnecting(x)       ((x)->status = STAT_CONNECTING)
-#define SetHandshake(x)                ((x)->status = STAT_HANDSHAKE)
-#define SetServer(x)           ((x)->status = STAT_SERVER)
-#define SetMe(x)               ((x)->status = STAT_ME)
-#define SetUser(x)             ((x)->status = STAT_USER)
-
-/*=============================================================================
- * Proto types
- */
-
-extern int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf);
-extern int m_error(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_end_of_burst(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_end_of_burst_ack(aClient *cptr, aClient *sptr,
-    int parc, char *parv[]);
-extern int m_desynch(aClient *cptr, aClient *sptr, int parc, char *parv[]);
+extern int exit_new_server(struct Client *cptr, struct Client *sptr,
+                           char *host, time_t timestamp, char *fmt, ...);
+extern int a_kills_b_too(struct Client *a, struct Client *b);
+extern int server_estab(struct Client *cptr, struct ConfItem *aconf);
 
-extern unsigned int max_connection_count, max_client_count;
 
-#endif /* S_SERV_H */
+#endif /* INCLUDED_s_serv_h */
index 47fee6c3f74a759d0b1f3e91208b91fd80a5bcf6..dd6c62001e59454d69ee7bcc00d239a8945c229c 100644 (file)
@@ -1,8 +1,20 @@
-#ifndef S_USER_H
-#define S_USER_H
+/*
+ * s_user.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_s_user_h
+#define INCLUDED_s_user_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+
+struct Client;
+struct User;
 
-/*=============================================================================
- * Macro's
+/*
+ * Macros
  */
 
 /*
 
 /* return values for hunt_server() */
 
-#define HUNTED_NOSUCH  (-1)    /* if the hunted server is not found */
-#define HUNTED_ISME    0       /* if this server should execute the command */
-#define HUNTED_PASS    1       /* if message passed onwards successfully */
+#define HUNTED_NOSUCH   (-1)    /* if the hunted server is not found */
+#define HUNTED_ISME     0       /* if this server should execute the command */
+#define HUNTED_PASS     1       /* if message passed onwards successfully */
 
 /* used when sending to #mask or $mask */
 
 #define MATCH_SERVER  1
 #define MATCH_HOST    2
 
-/*=============================================================================
- * Proto types
+#define COOKIE_VERIFIED 0xffffffff
+
+extern struct SLink *opsarray[];
+
+typedef char* (*InfoFormatter)(struct Client* who, char* buf);
+
+/*
+ * Prototypes
  */
+extern struct User* make_user(struct Client *cptr);
+extern void         free_user(struct User *user);
+extern int          register_user(struct Client* cptr, struct Client* sptr,
+                                  const char* nick, char* username);
 
-extern int m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int is_silenced(aClient *sptr, aClient *acptr);
-extern int hunt_server(int, aClient *cptr, aClient *sptr,
+extern void         user_count_memory(size_t* count_out, size_t* bytes_out);
+
+extern int user_set_away(struct User* user, char* message);
+extern int do_nick_name(char* nick);
+extern int set_nick_name(struct Client* cptr, struct Client* sptr,
+                         const char* nick, int parc, char* parv[]);
+extern void send_umode_out(struct Client* cptr, struct Client* sptr, int old);
+extern int whisper(struct Client* source, const char* nick,
+                   const char* channel, const char* text, int is_notice);
+extern void send_user_info(struct Client* to, char* names, int rpl,
+                           InfoFormatter fmt);
+extern int add_silence(struct Client* sptr, const char* mask);
+
+extern int set_user_mode(struct Client *cptr, struct Client *sptr,
+                         int parc, char *parv[]);
+extern int is_silenced(struct Client *sptr, struct Client *acptr);
+extern int hunt_server(int, struct Client *cptr, struct Client *sptr,
     char *command, int server, int parc, char *parv[]);
-extern aClient *next_client(aClient *next, char *ch);
-extern int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_private(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_wallchops(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_cprivmsg(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_cnotice(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_user(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_quit(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_away(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_ping(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_pong(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_pass(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_userhost(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_userip(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_ison(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern char *umode_str(aClient *cptr);
-extern void send_umode(aClient *cptr, aClient *sptr, int old, int sendmask);
-extern int del_silence(aClient *sptr, char *mask);
-extern int m_silence(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern void set_snomask(aClient *, snomask_t, int);
+extern struct Client* next_client(struct Client* next, const char* ch);
+extern char *umode_str(struct Client *cptr);
+extern void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask);
+extern int del_silence(struct Client *sptr, char *mask);
+extern void set_snomask(struct Client *, unsigned int, int);
 extern int is_snomask(char *);
-extern int check_target_limit(aClient *sptr, void *target, const char *name,
+extern int check_target_limit(struct Client *sptr, void *target, const char *name,
     int created);
-extern void add_target(aClient *sptr, void *target);
+extern void add_target(struct Client *sptr, void *target);
+extern unsigned int umode_make_snomask(unsigned int oldmask, char *arg,
+                                       int what);
 
-extern struct SLink *opsarray[];
 
-#endif /* S_USER_H */
+#endif /* INCLUDED_s_user_h */
index 73be18c58e788a5a8824cda26382b47d7a1222eb..3b719d0b2794806a92bd0822586914b0749067c2 100644 (file)
@@ -1,62 +1,73 @@
-#ifndef SEND_H
-#define SEND_H
+/*
+ * send.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_send_h
+#define INCLUDED_send_h
+#ifndef INCLUDED_stdarg_h
+#include <stdarg.h>         /* va_list */
+#define INCLUDED_stdarg_h 
+#endif
+
+struct Channel;
+struct Client;
+struct DBuf;
 
-/*=============================================================================
+/*
  * Macros
  */
 
 #define LastDeadComment(cptr) ((cptr)->info)
 
-/*=============================================================================
- * Proto types
+/*
+ * Prototypes
  */
 
-extern void sendto_one(aClient *to, char *pattern, ...)
-    __attribute__ ((format(printf, 2, 3)));
-extern void sendbufto_one(aClient *to);
-extern void sendto_ops(const char *pattern, ...)
-    __attribute__ ((format(printf, 1, 2)));
-extern void sendto_channel_butserv(aChannel *chptr, aClient *from,
-    char *pattern, ...) __attribute__ ((format(printf, 3, 4)));
-extern void sendto_serv_butone(aClient *one, char *pattern, ...)
-    __attribute__ ((format(printf, 2, 3)));
-extern void sendto_match_servs(aChannel *chptr, aClient *from,
-    char *format, ...) __attribute__ ((format(printf, 3, 4)));
-extern void sendto_lowprot_butone(aClient *cptr, int p, char *pattern, ...)
-    __attribute__ ((format(printf, 3, 4)));
-extern void sendto_highprot_butone(aClient *cptr, int p, char *pattern, ...)
-    __attribute__ ((format(printf, 3, 4)));
-extern void sendto_prefix_one(Reg1 aClient *to, Reg2 aClient *from,
-    char *pattern, ...) __attribute__ ((format(printf, 3, 4)));
-extern void flush_connections(int fd);
-extern void send_queued(aClient *to);
-extern void vsendto_one(aClient *to, char *pattern, va_list vl);
-extern void sendto_channel_butone(aClient *one, aClient *from,
-    aChannel *chptr, char *pattern, ...) __attribute__ ((format(printf, 4, 5)));
-extern void sendto_lchanops_butone(aClient *one, aClient *from,
-    aChannel *chptr, char *pattern, ...) __attribute__ ((format(printf, 4, 5)));
-extern void sendto_chanopsserv_butone(aClient *one, aClient *from,
-    aChannel *chptr, char *pattern, ...) __attribute__ ((format(printf, 4, 5)));
-extern void sendto_common_channels(aClient *user, char *pattern, ...)
-    __attribute__ ((format(printf, 2, 3)));
-extern void sendto_match_butone(aClient *one, aClient *from, char *mask,
-    int what, char *pattern, ...) __attribute__ ((format(printf, 5, 6)));
-extern void sendto_lops_butone(aClient *one, char *pattern, ...)
-    __attribute__ ((format(printf, 2, 3)));
+extern void send_buffer(struct Client* to, char* buf);
+extern void flush_sendq_except(const struct DBuf* one);
+
+extern void sendto_one(struct Client *to, const char* fmt, ...);
+extern void sendbufto_one(struct Client *to);
+extern void sendto_ops(const char* fmt, ...);
+extern void sendto_channel_butserv(struct Channel *chptr, struct Client *from,
+                                   const char* fmt, ...);
+extern void sendto_serv_butone(struct Client *one, const char* fmt, ...);
+extern void sendto_match_servs(struct Channel* chptr, struct Client* from,
+                               const char* fmt, ...);
+extern void sendto_lowprot_butone(struct Client *cptr, int p,
+                                  const char* fmt, ...);
+extern void sendto_highprot_butone(struct Client *cptr, int p,
+                                   const char* fmt, ...);
+extern void sendto_prefix_one(struct Client *to, struct Client *from,
+                              const char* fmt, ...);
+extern void flush_connections(struct Client* cptr);
+extern void send_queued(struct Client *to);
+extern void vsendto_one(struct Client *to, const char* fmt, va_list vl);
+extern void sendto_channel_butone(struct Client *one, struct Client *from,
+                                  struct Channel *chptr, const char* fmt, ...);
+extern void sendmsgto_channel_butone(struct Client *one, struct Client *from,
+                                  struct Channel *chptr, const char *sender,
+                                  const char *cmd, const char *chname, const char *msg);
+extern void sendto_lchanops_butone(struct Client *one, struct Client *from,
+                                   struct Channel *chptr, const char* fmt, ...);
+extern void sendto_chanopsserv_butone(struct Client *one, struct Client *from,
+                                   struct Channel *chptr, const char* fmt, ...);
+extern void sendto_common_channels(struct Client *user, const char* fmt, ...);
+extern void sendto_match_butone(struct Client *one, struct Client *from,
+                                const char *mask, int what, const char* fmt, ...);
+extern void sendto_lops_butone(struct Client *one, const char* fmt, ...);
 extern void vsendto_ops(const char *pattern, va_list vl);
-extern void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...)
-    __attribute__ ((format(printf, 3, 4)));
-extern void sendto_g_serv_butone(aClient *one, char *pattern, ...)
-    __attribute__ ((format(printf, 2, 3)));
-extern void sendto_realops(const char *pattern, ...)
-    __attribute__ ((format(printf, 1, 2)));
-extern void vsendto_op_mask(register snomask_t mask,
-    const char *pattern, va_list vl);
-extern void sendto_op_mask(snomask_t mask, const char *pattern, ...)
-    __attribute__ ((format(printf, 2, 3)));
-extern void sendbufto_op_mask(snomask_t mask);
-extern void sendbufto_serv_butone(aClient *one);
+extern void sendto_ops_butone(struct Client *one, struct Client *from,
+                              const char* fmt, ...);
+extern void sendto_g_serv_butone(struct Client *one, const char* fmt, ...);
+extern void sendto_realops(const char* fmt, ...);
+extern void vsendto_op_mask(unsigned int mask,
+                            const char* fmt, va_list vl);
+extern void sendto_op_mask(unsigned int mask, const char* fmt, ...);
+extern void sendbufto_op_mask(unsigned int mask);
+extern void sendbufto_serv_butone(struct Client *one);
 
 extern char sendbuf[2048];
 
-#endif /* SEND_H */
+#endif /* INCLUDED_send_h */
index 1a8d19ba99ffeeb9f147ed8d81aca89b5dba5504..0a8042d2694b52b5f00a5bac4152446587d27cda 100644 (file)
@@ -1,17 +1,21 @@
-#ifndef SPRINTF_IRC
-#define SPRINTF_IRC
-
+/*
+ * sprintf_irc.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_sprintf_irc_h
+#define INCLUDED_sprintf_irc_h
+#ifndef INCLUDED_stdarg_h
 #include <stdarg.h>
+#define INCLUDED_stdarg_h
+#endif
 
-/*=============================================================================
+/*
  * Proto types
  */
 
-extern char *vsprintf_irc(register char *str, register const char *format,
-    register va_list);
-extern char *sprintf_irc(register char *str, register const char *format, ...)
-    __attribute__ ((format(printf, 2, 3)));
-
+extern char *vsprintf_irc(char *str, const char *format, va_list);
+extern char *sprintf_irc(char *str, const char *format, ...); 
 extern const char atoi_tab[4000];
 
-#endif /* SPRINTF_IRC */
+#endif /* INCLUDED_sprintf_irc_h */
index 1a18590dcec3bc2edf0936de1a7258a6c8bc5a17..34fbe40e9c2f4d7b7bcd4e9d39e633add333d20f 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef STRUCT_H
-#define STRUCT_H
-
-#include <netinet/in.h>                /* Needed for struct in_addr */
-#include "whowas.h"            /* Needed for whowas struct */
-
-#ifndef INCLUDED_dbuf_h
-#include "dbuf.h"
-#endif
-
-
-/*=============================================================================
- * General defines
- */
-
-#define NICKLEN                9
-#define USERLEN                10
-#define HOSTLEN                63
-#define REALLEN                50
-#define PASSWDLEN      20
-#define BUFSIZE                512     /* WARNING: *DONT* CHANGE THIS!!!! */
-#define MAXTARGETS     20
-#define STARTTARGETS   10
-#define RESERVEDTARGETS 12
-
-/*-----------------------------------------------------------------------------
- * Macro's
- */
-
-#define CLIENT_LOCAL_SIZE sizeof(aClient)
-#define CLIENT_REMOTE_SIZE offsetof(aClient, count)
-
-#define MyConnect(x)   ((x)->from == (x))
-#define MyUser(x)      (MyConnect(x) && IsUser(x))
-#define MyOper(x)      (MyConnect(x) && IsOper(x))
-#define Protocol(x)    ((x)->serv->prot)
-
-/*=============================================================================
- * Structures
  *
- * Only put structures here that are being used in a very large number of
- * source files. Other structures go in the header file of there corresponding
- * source file, or in the source file itself (when only used in that file).
+ * $Id$
  */
-
-struct Client {
-  struct Client *next, *prev, *hnext;
-  struct User *user;           /* ...defined, if this is a User */
-  struct Server *serv;         /* ...defined, if this is a server */
-  struct Whowas *whowas;       /* Pointer to ww struct to be freed on quit */
-  char yxx[4];                 /* Numeric Nick: YMM if this is a server,
-                                  XX0 if this is a user */
-  time_t lasttime;             /* ...should be only LOCAL clients? --msa */
-  time_t firsttime;            /* time client was created */
-  time_t since;                        /* last time we parsed something */
-  time_t lastnick;             /* TimeStamp on nick */
-  int marker;                  /* /who processing marker */
-  unsigned int flags;          /* client flags */
-  struct Client *from;         /* == self, if Local Client, *NEVER* NULL! */
-  int fd;                      /* >= 0, for local clients */
-  unsigned int hopcount;       /* number of servers to this 0 = local */
-  short status;                        /* Client type */
-  struct in_addr ip;           /* Real ip# - NOT defined for remote servers! */
-  char name[HOSTLEN + 1];      /* Unique name of the client, nick or host */
-  char username[USERLEN + 1];  /* username here now for auth stuff */
-  char info[REALLEN + 1];      /* Free form additional client information */
-  /*
-   *  The following fields are allocated only for local clients
-   *  (directly connected to *this* server with a socket.
-   *  The first of them *MUST* be the "count"--it is the field
-   *  to which the allocation is tied to! *Never* refer to
-   *  these fields, if (from != self).
-   */
-  unsigned int count;          /* Amount of data in buffer, DON'T PUT
-                                  variables ABOVE this one! */
-  snomask_t snomask;           /* mask for server messages */
-  char buffer[BUFSIZE];                /* Incoming message buffer; or the error that
-                                  caused this clients socket to be `dead' */
-  unsigned short int lastsq;   /* # of 2k blocks when sendqueued called last */
-  time_t nextnick;             /* Next time that a nick change is allowed */
-  time_t nexttarget;           /* Next time that a target change is allowed */
-  unsigned char targets[MAXTARGETS];   /* Hash values of current targets */
-  unsigned int cookie;         /* Random number the user must PONG */
-  struct DBuf sendQ;           /* Outgoing message queue--if socket full */
-  struct DBuf recvQ;           /* Hold for data incoming yet to be parsed */
-  unsigned int sendM;          /* Statistics: protocol messages send */
-  unsigned int sendK;          /* Statistics: total k-bytes send */
-  unsigned int receiveM;       /* Statistics: protocol messages received */
-  unsigned int receiveK;       /* Statistics: total k-bytes received */
-  unsigned short int sendB;    /* counters to count upto 1-k lots of bytes */
-  unsigned short int receiveB; /* sent and received. */
-  struct Client *acpt;         /* listening client which we accepted from */
-  struct SLink *confs;         /* Configuration record associated */
-  int authfd;                  /* fd for rfc931 authentication */
-  unsigned short int port;     /* and the remote port# too :-) */
-  struct hostent *hostp;
-  struct ListingArgs *listing;
-#ifdef pyr
-  struct timeval lw;
+#ifndef INCLUDED_struct_h
+#define INCLUDED_struct_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>      /* time_t */
+#define INCLUDED_sys_types_h
 #endif
-  char sockhost[HOSTLEN + 1];  /* This is the host name from the socket and
-                                  after which the connection was accepted. */
-  char passwd[PASSWDLEN + 1];
-};
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"       /* sizes */
+#endif
+
+struct DLink;
+struct Client;
+struct User;
+struct Membership;
+struct SLink;
 
 struct Server {
-  struct Server *nexts;
-  struct Client *up;           /* Server one closer to me */
-  struct DSlink *down;         /* List with downlink servers */
-  struct DSlink *updown;       /* own Dlink in up->serv->down struct */
-  aClient **client_list;       /* List with client pointers on this server */
-  struct User *user;           /* who activated this connection */
-  struct ConfItem *nline;      /* N-line pointer for this server */
-  time_t timestamp;            /* Remotely determined connect try time */
-  time_t ghost;                        /* Local time at which a new server
-                                  caused a Ghost */
-  unsigned short prot;         /* Major protocol */
-  unsigned short nn_last;      /* Last numeric nick for p9 servers only */
-  unsigned int nn_mask;                /* [Remote] FD_SETSIZE - 1 */
-  char nn_capacity[4];         /* numeric representation of server capacity */
-#ifdef LIST_DEBUG
-  struct Client *bcptr;
-#endif
-  char *last_error_msg;                /* Allocated memory with last message receive with an ERROR */
+  struct Server*  nexts;
+  struct Client*  up;           /* Server one closer to me */
+  struct DLink*   down;         /* List with downlink servers */
+  struct DLink*   updown;       /* own Dlink in up->serv->down struct */
+  struct Client** client_list;  /* List with client pointers on this server */
+  struct User*    user;         /* who activated this connection */
+  time_t          timestamp;    /* Remotely determined connect try time */
+  time_t          ghost;        /* Local time at which a new server
+                                   caused a Ghost */
+  int             lag;          /* Approximation of the amount of lag to this server */                          
+  unsigned int    clients;      /* Number of clients on the network */
+  unsigned short  prot;         /* Major protocol */
+  unsigned short  nn_last;      /* Last numeric nick for p9 servers only */
+  unsigned int    nn_mask;      /* [Remote] FD_SETSIZE - 1 */
+  char          nn_capacity[4]; /* numeric representation of server capacity */
+
+  char *last_error_msg;         /* Allocated memory with last message receive with an ERROR */
   char by[NICKLEN + 1];
 };
 
 struct User {
-  struct User *nextu;
-  struct Client *server;       /* client structure of server */
-  struct SLink *channel;       /* chain of channel pointer blocks */
-  struct SLink *invited;       /* chain of invite pointer blocks */
-  struct SLink *silence;       /* chain of silence pointer blocks */
-  char *away;                  /* pointer to away message */
-  time_t last;
-  unsigned int refcnt;         /* Number of times this block is referenced */
-  unsigned int joined;         /* number of channels joined */
-  char username[USERLEN + 1];
-  char host[HOSTLEN + 1];
-#ifdef LIST_DEBUG
-  struct Client *bcptr;
-#endif
+  struct User*       nextu;
+  struct Client*     server;         /* client structure of server */
+  struct Membership* channel;        /* chain of channel pointer blocks */
+  struct SLink*      invited;        /* chain of invite pointer blocks */
+  struct SLink*      silence;        /* chain of silence pointer blocks */
+  char*              away;           /* pointer to away message */
+  time_t             last;
+  unsigned int       refcnt;          /* Number of times this block is referenced */
+  unsigned int       joined;          /* number of channels joined */
+  unsigned int       invites;         /* Number of channels we've been invited to */
+  char               username[USERLEN + 1];
+  char               host[HOSTLEN + 1];
 };
 
-#endif /* STRUCT_H */
+#endif /* INCLUDED_struct_h */
index 5629669589f8b482d4933156f25be328d06b7a5a..b3e546f0151a9b6a6087efced07675a40f058f3b 100644 (file)
@@ -1,22 +1,27 @@
-#ifndef SUPPORT_H
-#define SUPPORT_H
-
-#include <netinet/in.h>
-
-/*=============================================================================
- * Proto types
+/*
+ * support.h
+ *
+ * $Id$
  */
-
-#ifndef HAVE_STRTOKEN
-extern char *strtoken(char **save, char *str, char *fs);
+#ifndef INCLUDED_support_h
+#define INCLUDED_support_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#define INCLUDED_config_h
 #endif
-#ifndef HAVE_STRERROR
-extern char *strerror(int err_no);
+#if 0
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>         /* broken BSD system headers */
+#define INCLUDED_sys_types_h
 #endif
-extern void dumpcore(const char *pattern, ...)
-    __attribute__ ((format(printf, 1, 2)));
-extern char *inetntoa(struct in_addr in);
+#endif /* 0 */
+
+/*
+ * Prototypes
+ */
+
+extern void dumpcore(const char *pattern, ...);
 extern int check_if_ipmask(const char *mask);
 extern void write_log(const char *filename, const char *pattern, ...);
 
-#endif /* SUPPORT_H */
+#endif /* INCLUDED_support_h */
diff --git a/include/supported.h b/include/supported.h
new file mode 100644 (file)
index 0000000..64b5069
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * IRC - Internet Relay Chat, include/supported.h
+ * Copyright (C) 1999 Perry Lorier.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ * Description: This file has the featureset that ircu announces on connecting
+ *              a client.  It's in this .h because it's likely to be appended
+ *              to frequently and s_user.h is included by basically everyone.
+ */
+#ifndef INCLUDED_supported_h
+#define INCLUDED_supported_h
+
+#include "config.h"
+#include "channel.h"
+#include "ircd_defs.h"
+
+/* 
+ * 'Features' supported by this ircd
+ */
+#define FEATURES "SILENCE=15"\
+                " WHOX"\
+                " WALLCHOPS"\
+                " USERIP"\
+                " CPRIVMSG"\
+                " CNOTICE"\
+                " MODES=%i" \
+                " MAXCHANNELS=%i" \
+                " MAXBANS=%i" \
+                " NICKLEN=%i" \
+                " TOPICLEN=%i" \
+                " KICKLEN=%i" \
+                " MAP"
+                 
+#define FEATURESVALUES MAXMODEPARAMS,MAXCHANNELSPERUSER,MAXBANS, \
+        NICKLEN,TOPICLEN,TOPICLEN
+
+#endif /* INCLUDED_supported_h */
+
index 47814b56d3645c12511e11e68884a43217c23ea3..a8c86ee073b9bd907ebae6e1308e27aa83574b1b 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#ifndef __sys_include__
-#define __sys_include__
-
-#include "../config/config.h"
-#include "../config/setup.h"
-
-#ifdef __osf__
-#define _OSF_SOURCE
-#endif
-
-#ifdef __sun__
-#ifdef __svr4__
-#define SOL2
-#else
-#define SUNOS4
-#endif
+#ifndef INCLUDED_sys_h
+#define INCLUDED_sys_h
+#ifndef INCLUDED_config_h
+#include "config.h"
 #endif
 
 #if WORDS_BIGENDIAN
 # define BIT_ZERO_ON_RIGHT
 #endif
 
-#ifdef _SEQUENT_               /* Dynix 1.4 or 2.0 Generic Define.. */
-#undef BSD
-#define SYSV                   /* Also #define SYSV */
-#endif
-
-#ifdef __hpux
-#define HPUX
-#endif
-
-#ifdef sgi
-#define SGI
-#endif
-
-#if defined(mips)
-#undef SYSV
-#undef BSD
-#define BSD 1                  /* mips only works in bsd43 environment */
-#endif
-
-#ifdef BSD_RELIABLE_SIGNALS
-#if defined(SYSV_UNRELIABLE_SIGNALS) || defined(POSIX_SIGNALS)
-#error You stuffed up config.h signals #defines use only one.
-#endif
-#define HAVE_RELIABLE_SIGNALS
-#endif
-
-#ifdef SYSV_UNRELIABLE_SIGNALS
-#ifdef POSIX_SIGNALS
-#error You stuffed up config.h signals #defines use only one.
-#endif
-#undef HAVE_RELIABLE_SIGNALS
-#endif
-
-#ifdef POSIX_SIGNALS
 #define HAVE_RELIABLE_SIGNALS
-#endif
 
 /*
  * safety margin so we can always have one spare fd, for motd/authd or
  * whatever else.  -24 allows "safety" margin of 10 listen ports, 8 servers
  * and space reserved for logfiles, DNS sockets and identd sockets etc.
  */
-#define MAXCLIENTS     (MAXCONNECTIONS-24)
+#define MAXCLIENTS      (MAXCONNECTIONS-24)
 
 #ifdef HAVECURSES
 #define DOCURSES
 #undef DOTERMCAP
 #endif
 
-#ifndef UNIXPORT
-#undef UNIXPORTPATH
-#endif
-
 #if defined(CLIENT_FLOOD)
 #if (CLIENT_FLOOD > 8000) || (CLIENT_FLOOD < 512)
 #error CLIENT_FLOOD needs redefining.
 #undef IRC_GID
 #endif
 
-#define Reg1 register
-#define Reg2 register
-#define Reg3 register
-#define Reg4 register
-#define Reg5 register
-#define Reg6 register
-#define Reg7 register
-#define Reg8 register
-#define Reg9 register
-#define Reg10 register
-
 /* Define FD_SETSIZE to what we want before including sys/types.h on BSD */
 #if  defined(__FreeBSD__) || defined(__NetBSD__) || defined(__bsdi__)
 #if ((!defined(USE_POLL)) && (!defined(FD_SETSIZE)))
 #endif
 #endif
 
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/param.h>
-
-#ifdef __osf__
-#undef _OSF_SOURCE
-/* Buggy header */
-#include <netdb.h>
-#define _OSF_SOURCE
-#endif
-
-#if HAVE_ERRNO_H
-# include <errno.h>
-#else
-# if HAVE_NET_ERRNO_H
-#  include <net/errno.h>
-# endif
-#endif
-
-#if !defined(__FreeBSD__) && !defined(__NetBSD__) && \
-    !defined(__bsdi__) && !defined(__alpha) && !defined(__GLIBC__)
-extern char *sys_errlist[];
-#endif
-
-/* See AC_HEADER_STDC in 'info autoconf' */
-#if STDC_HEADERS
-# include <string.h>
-#else
-# if HAVE_STRING_H
-#  include <string.h>
-# endif
-# ifndef HAVE_STRCHR
-#  define strchr index
-#  define strrchr rindex
-# endif
-char *strchr(), *strrchr(), *strtok();
-# if HAVE_MEMORY_H             /* See AC_MEMORY_H in 'info autoconf' */
-#  include <memory.h>
-# endif
-# ifndef HAVE_MEMCPY
-#  define memcpy(d, s, n) bcopy ((s), (d), (n))
-#  define memset(a, b, c) bzero(a, c)  /* We ONLY use memset(x, 0, y) */
-# else
-#  if NEED_BZERO               /* This is not used yet - needs to be added to `configure' */
-#   define bzero(a, c) memset((a), 0, (c))     /* Some use it in FD_ZERO */
-#  endif
-# endif
-# ifndef HAVE_MEMMOVE
-#  define memmove(d, s, n) bcopy ((s), (d), (n))
-# endif
-#endif
-
-#if defined(_AIX) || (defined(__STRICT_ANSI__) && __GLIBC__ >= 2)
-#include <sys/select.h>
-#endif
-
-/* See AC_HEADER_TIME in 'info autoconf' */
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
-#endif
-
-#ifdef SOL2
-#define OPT_TYPE char          /* opt type for get/setsockopt */
-#else
-#define OPT_TYPE void
-#endif
-
-#ifdef SUNOS4
 #define LIMIT_FMT "%d"
-#else
-#if (defined(__bsdi__) || defined(__NetBSD__))
-#define LIMIT_FMT "%qd"
-#else
-#define LIMIT_FMT "%ld"
-#endif
-#endif
 
-/* Different name on NetBSD and FreeBSD --Skip */
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__bsdi__)
-#define dn_skipname  __dn_skipname
-#endif
-
-#if defined(DEBUGMODE) && !defined(DEBUGMALLOC)
-#define DEBUGMALLOC
-#endif
-
-#ifdef STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
-#else /* !STDC_HEADERS */
-#ifdef HAVE_MALLOC_H
-#include <malloc.h>
-#else
-#ifdef HAVE_SYS_MALLOC_H
-#include <sys/malloc.h>
-#endif /* HAVE_SYS_MALLOC_H */
-#endif /* HAVE_MALLOC_H */
-#endif /* !STDC_HEADERS */
-
-#ifndef MAX
-#define MAX(a, b)      ((a) > (b) ? (a) : (b))
-#endif
-#ifndef MIN
-#define MIN(a, b)      ((a) < (b) ? (a) : (b))
-#endif
+#define IRCD_MAX(a, b)  ((a) > (b) ? (a) : (b))
+#define IRCD_MIN(a, b)  ((a) < (b) ? (a) : (b))
 
 #ifndef FALSE
-#define FALSE (0)
+#define FALSE 0
 #endif
 #ifndef TRUE
-#define TRUE  (!FALSE)
-#endif
-
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
-#endif
-
-#include "runmalloc.h"
-
-#define MyCoreDump *((int *)NULL)=0
-
-/* This isn't really POSIX :(, but we really need it -- can this be replaced ? */
-#if defined(__STRICT_ANSI__) && !defined(_AIX)
-extern int gettimeofday(struct timeval *tv, struct timezone *tz);
-#endif
-
-/*
- * The following part is donated by Carlo Wood from his package 'libr':
- * (C) Copyright 1996 by Carlo Wood. All rights reserved.
- */
-
-/* GNU CC improvements: We can only use this if we have a gcc/g++ compiler */
-#ifdef __GNUC__
-
-#if (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
-#define NO_ATTRIBUTE
-#endif
-
-#else /* !__GNUC__ */
-
-/* No attributes if we don't have gcc-2.7 or higher */
-#define NO_ATTRIBUTE
-
-#endif /* !__GNUC__ */
-
-#ifdef __cplusplus
-#define HANDLER_ARG(x) x
-#define UNUSED(x)
-#else
-#define HANDLER_ARG(x)
-#ifdef NO_ATTRIBUTE
-#define __attribute__(x)
-#define UNUSED(x) unused_##x
-#else
-#define UNUSED(x) x __attribute__ ((unused))
-#endif
-#endif
-
-#ifdef NO_ATTRIBUTE
-#define RCSTAG_CC(string) static char unused_rcs_ident[] = string
-#else
-#define RCSTAG_CC(string) static char rcs_ident[] __attribute__ ((unused)) = string
-#endif
-
-#ifdef HAVE_SYS_CDEFS_H
-#include <sys/cdefs.h>
-#else /* !HAVE_SYS_MALLOC_H */
-#undef __BEGIN_DECLS
-#undef __END_DECLS
-#ifdef  __cplusplus
-#define __BEGIN_DECLS   extern "C" {
-#define __END_DECLS     }
-#else
-#define __BEGIN_DECLS
-#define __END_DECLS
+#define TRUE  1
 #endif
-#endif /* !HAVE_SYS_CDEFS_H */
 
-#endif /* __sys_include__ */
+#endif /* INCLUDED_sys_h */
diff --git a/include/uping.h b/include/uping.h
new file mode 100644 (file)
index 0000000..a9b3eea
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * IRC - Internet Relay Chat, include/uping.h
+ * Copyright (C) 1995 Carlo Wood
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_uping_h
+#define INCLUDED_uping_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>
+#define INCLUDED_sys_types_h
+#endif
+#ifndef INCLUDED_netinet_in_h
+#include <netinet/in.h>
+#define INCLUDED_netinet_in_h
+#endif
+#ifndef INCLUDED_ircd_defs_h
+#include "ircd_defs.h"
+#endif
+
+struct Client;
+
+struct UPing
+{
+  struct UPing*      next;     /* next ping in list, usually null */
+  int                fd;       /* socket file descriptor */
+  struct sockaddr_in sin;      /* socket name (ip addr, port, family ) */
+  char               count;    /* number of pings requested */
+  char               sent;     /* pings sent */
+  char               received; /* pings received */
+  char               active;   /* ping active flag */
+  struct Client*     client;   /* who requested the pings */
+  time_t             lastsent; /* when last ping was sent */
+  time_t             timeout;  /* current ping timeout time */
+  int                ms_min;   /* minimum time in milliseconds */
+  int                ms_ave;   /* average time in milliseconds */
+  int                ms_max;   /* maximum time in milliseconds */
+  int                index;    /* index into poll array */
+  char               name[HOSTLEN + 1]; /* server name to poing */
+  char               buf[BUFSIZE];      /* buffer to hold ping times */
+};
+
+
+/*=============================================================================
+ * Proto types
+ */
+
+extern int  setup_ping(void);
+extern void polludp(int fd);
+extern void send_ping(struct UPing* pptr);
+extern void read_ping(struct UPing* pptr);
+extern int  m_uping(struct Client *cptr, struct Client *sptr, int parc, char* parv[]);
+extern void end_ping(struct UPing* pptr);
+extern void cancel_ping(struct Client *sptr, struct Client *acptr);
+extern struct UPing* pings_begin(void);
+
+#ifdef DEBUG
+extern void uping_mark_blocks(void);
+#endif
+
+#endif /* INCLUDED_uping_h */
index 50adf2cfb66e5a3a805ea157dd06993dc2a1a70c..c6dfd18cf9a942ca3b1b59e732550fc6e29c10de 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_userload_h
+#define INCLUDED_userload_h
 
-#ifndef USERLOAD_H
-#define USERLOAD_H
+struct Client;
 
-/*=============================================================================
+/*
  * Structures
  */
 
@@ -34,14 +37,14 @@ struct current_load_st {
   unsigned int conn_count;
 };
 
-/*=============================================================================
+/*
  * Proto types
  */
 
 extern void update_load(void);
-extern void calc_load(aClient *sptr);
+extern void calc_load(struct Client *sptr);
 extern void initload(void);
 
 extern struct current_load_st current_load;
 
-#endif /* USERLOAD_H */
+#endif /* INCLUDED_userload_h */
index e9e3c74e199fe1e02fae325f5ec5e18cb87a6e34..faea17600f2e39ee8234c85202d6d53ce13a2a10 100644 (file)
@@ -1,9 +1,14 @@
-#ifndef VERSION_H
-#define VERSION_H
+/*
+ * version.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_version_h
+#define INCLUDED_version_h
 
 extern const char *version;
 extern const char *creation;
 extern const char *infotext[];
 extern const char *generation;
 
-#endif /* VERSION_H */
+#endif /* INCLUDED_version_h */
index f4715382ab23e7748829add018d3bcc5e9422e59..0e4190d73e826ddf3dd9dc07685198adf592dbf6 100644 (file)
@@ -1,15 +1,83 @@
-#ifndef WHOCMDS_H
-#define WHOCMDS_H
+/*
+ * whocmds.h
+ *
+ * $Id$
+ */
+#ifndef INCLUDED_whocmds_h
+#define INCLUDED_whocmds_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+
+struct Client;
+struct Channel;
 
-/*=============================================================================
- * Macro's
+
+/*
+ * m_who() 
+ * m_who with support routines rewritten by Nemesi, August 1997
+ * - Alghoritm have been flattened (no more recursive)
+ * - Several bug fixes
+ * - Strong performance improvement
+ * - Added possibility to have specific fields in the output
+ * See readme.who for further details.
  */
 
-/*=============================================================================
- * Proto types
+/* Macros used only in here by m_who and its support functions */
+
+#define WHOSELECT_OPER 1
+#define WHOSELECT_EXTRA 2
+
+#define WHO_FIELD_QTY 1
+#define WHO_FIELD_CHA 2
+#define WHO_FIELD_UID 4
+#define WHO_FIELD_NIP 8
+#define WHO_FIELD_HOS 16
+#define WHO_FIELD_SER 32
+#define WHO_FIELD_NIC 64
+#define WHO_FIELD_FLA 128
+#define WHO_FIELD_DIS 256
+#define WHO_FIELD_REN 512
+
+#define WHO_FIELD_DEF ( WHO_FIELD_NIC | WHO_FIELD_UID | WHO_FIELD_HOS | WHO_FIELD_SER )
+
+#define IS_VISIBLE_USER(s,ac) ((s==ac) || (!IsInvisible(ac)))
+
+#if defined(SHOW_INVISIBLE_LUSERS) || defined(SHOW_ALL_INVISIBLE_USERS)
+#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || ((b & WHOSELECT_EXTRA) && MyConnect(ac) && IsAnOper(s)))
+#else
+#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac))
+#endif
+
+#ifdef SHOW_ALL_INVISIBLE_USERS
+#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || ((b & WHOSELECT_EXTRA) && IsOper(s)))
+#else
+#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b))
+#endif
+
+#ifdef UNLIMIT_OPER_QUERY
+#define SHOW_MORE(sptr, counter) (IsAnOper(sptr) || (!(counter-- < 0)) )
+#else
+#define SHOW_MORE(sptr, counter) (!(counter-- < 0))
+#endif
+
+#ifdef OPERS_SEE_IN_SECRET_CHANNELS
+#ifdef LOCOP_SEE_IN_SECRET_CHANNELS
+#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && IsAnOper(s)))
+#else
+#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && IsOper(s)))
+#endif
+#else
+#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr))
+#endif
+
+#define MAX_WHOIS_LINES 50
+
+/*
+ * Prototypes
  */
+extern void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
+                   int fields, char* qrt);
 
-extern int m_who(aClient *cptr, aClient *sptr, int parc, char *parv[]);
-extern int m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[]);
 
-#endif /* WHOCMDS_H */
+#endif /* INCLUDED_whocmds_h */
index e7def4e3568bf5ab7a8c271eae5d98da48a2dd0c..9084e00d3a6e3b4f5a1e509dc1fa1aa0bfa3c54f 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#ifndef INCLUDED_whowas_h
+#define INCLUDED_whowas_h
+#ifndef INCLUDED_sys_types_h
+#include <sys/types.h>        /* size_t */
+#define INCLUDED_sys_types_h
+#endif
 
-#ifndef WHOWAS_H
-#define WHOWAS_H
+struct Client;
 
-/*=============================================================================
+/*
  * General defines
  */
 
-#define BITS_PER_COL           3
-#define BITS_PER_COL_MASK      0x7
-#define WW_MAX_INITIAL         16
+#define BITS_PER_COL            3
+#define BITS_PER_COL_MASK       0x7
+#define WW_MAX_INITIAL          16
 
 #define MAX_SUB (1 << BITS_PER_COL)
 #define WW_MAX_INITIAL_MASK (WW_MAX_INITIAL - 1)
 #define WW_MAX (WW_MAX_INITIAL * MAX_SUB)
 
-/*=============================================================================
+/*
  * Structures
  */
 
@@ -45,22 +52,24 @@ struct Whowas {
   char *realname;
   char *away;
   time_t logoff;
-  struct Client *online;       /* Needed for get_history() (nick chasing) */
-  struct Whowas *hnext;                /* Next entry with the same hash value */
-  struct Whowas **hprevnextp;  /* Pointer to previous next pointer */
-  struct Whowas *cnext;                /* Next entry with the same 'online' pointer */
-  struct Whowas **cprevnextp;  /* Pointer to previous next pointer */
+  struct Client *online;        /* Needed for get_history() (nick chasing) */
+  struct Whowas *hnext;         /* Next entry with the same hash value */
+  struct Whowas **hprevnextp;   /* Pointer to previous next pointer */
+  struct Whowas *cnext;         /* Next entry with the same 'online' pointer */
+  struct Whowas **cprevnextp;   /* Pointer to previous next pointer */
 };
 
-/*=============================================================================
+/*
  * Proto types
  */
+extern struct Whowas* whowashash[];
+
+extern unsigned int hash_whowas_name(const char *name);
 
-extern aClient *get_history(const char *nick, time_t timelimit);
-extern void add_history(aClient *cptr, int still_on);
-extern void off_history(const aClient *cptr);
+extern struct Client *get_history(const char *nick, time_t timelimit);
+extern void add_history(struct Client *cptr, int still_on);
+extern void off_history(const struct Client *cptr);
 extern void initwhowas(void);
-extern int m_whowas(aClient *cptr, aClient *sptr, int parc, char *parv[]);
 extern void count_whowas_memory(int *wwu, size_t *wwm, int *wwa, size_t *wwam);
 
-#endif /* WHOWAS_H */
+#endif /* INCLUDED_whowas_h */
index 54bccd8b2e583bbe3fb55a7c929228cf2cbe190e..0a3b345af174a79b1a9605a65ccaee433f302411 100644 (file)
@@ -3,3 +3,5 @@ stamp-m
 version.c
 ircd
 chkconf
+table_gen
+chattr.tab.c
index df668b6b754171e596690d4a4065a6388a98a8e1..f97a49efbe016e949b45ebd90d753b77b65928f2 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ * 
+ * This file should be edited in a window with a width of 141 characters
+ * ick
  */
-
-/* This file should be edited in a window with a width of 141 characters */
-
-#include "sys.h"
-#include <netinet/in.h>
-#include "h.h"
 #include "IPcheck.h"
-#include "querycmds.h"
-#include "struct.h"
-#include "s_user.h"
-#include "s_bsd.h"
-#include "struct.h"
-#ifdef GODMODE
-#include "numnicks.h"
-#endif
+#include "client.h"
+#include "ircd.h"
+#include "numnicks.h"       /* NumNick, NumServ (GODMODE) */
+#include "querycmds.h"      /* UserStats */
+#include "ircd_alloc.h"
+#include "s_bsd.h"          /* SetIPChecked */
+#include "s_user.h"         /* TARGET_DELAY */
 #include "send.h"
+#include "struct.h"
 
-RCSTAG_CC("$Id$");
-
-extern aClient me;
-extern time_t now;
+#include <assert.h>
+#include <stdio.h>          /* NULL ... bleah */
 
 /*
  * IP number and last targets of a user that just disconnected.
@@ -52,17 +50,19 @@ struct ip_targets_st {
 /* We keep one IPregistry for each IP number (for both, remote and local clients) */
 struct IPregistry {
   union {
-    struct in_addr ip;         /* The IP number of the registry entry. */
-    struct ip_targets_st *ptr; /* The IP number of the registry entry, and a list of targets */
+    struct in_addr ip;          /* The IP number of the registry entry. */
+    struct ip_targets_st *ptr;  /* a list of targets */
   } ip_targets;
-  unsigned int last_connect:16;        /* Time of last connect (attempt), see BITMASK below,
-                                  or time of last disconnect when `connected' is zero. */
-  unsigned int connected:8;    /* Used for IP# throttling: Number of currently on-line clients with this IP number */
-  unsigned int connect_attempts:4;     /* Used for connect speed throttling: Number of clients that connected with this IP number
-                                          or `15' when then real value is >= 15.  This value is only valid when the last connect
-                                          was less then IPCHECK_CLONE_PERIOD seconds ago, it should considered to be 0 otherwise. */
-  unsigned int free_targets:4; /* Number of free targets that the next local client will inherit on connect,
-                                  or HAS_TARGETS_MAGIC when ip_targets.ptr is a pointer to a ip_targets_st. */
+  unsigned int last_connect:16; /* Time of last connect (attempt), see BITMASK
+                                 * below, or time of last disconnect when 
+                                 * `connected' is zero. */
+  unsigned int connected:8;     /* Used for IP# throttling: Number of
+                                 * currently on-line clients with this IP */
+  unsigned int connect_attempts:4;      /* Used for connect speed throttling: Number of clients that connected with this IP number
+                                           or `15' when then real value is >= 15.  This value is only valid when the last connect
+                                           was less then IPCHECK_CLONE_PERIOD seconds ago, it should considered to be 0 otherwise. */
+  unsigned int free_targets:4;  /* Number of free targets that the next local client will inherit on connect,
+                                   or HAS_TARGETS_MAGIC when ip_targets.ptr is a pointer to a ip_targets_st. */
 };
 
 struct IPregistry_vector {
@@ -71,7 +71,7 @@ struct IPregistry_vector {
   struct IPregistry *vector;
 };
 
-#define HASHTABSIZE 0x2000     /* Must be power of 2 */
+#define HASHTABSIZE 0x2000      /* Must be power of 2 */
 static struct IPregistry_vector IPregistry_hashtable[HASHTABSIZE];
 
 /*
@@ -80,18 +80,19 @@ static struct IPregistry_vector IPregistry_hashtable[HASHTABSIZE];
  */
 #define CALCULATE_HASH(in_addr) \
   struct IPregistry_vector *hash; \
-  do { register unsigned int ip = (in_addr).s_addr; \
+  do { unsigned int ip = (in_addr).s_addr; \
        hash = &IPregistry_hashtable[((ip >> 14) + (ip >> 7) + ip) & (HASHTABSIZE - 1)]; } while(0)
 
 /*
- * Fit `now' in an unsigned short, the advantage is that we use less memory `struct IPregistry::last_connect' can be smaller
- * while the only disadvantage is that if someone reconnects after exactly 18 hours and 12 minutes, and NOBODY with the
- * same _hash_ value for this IP-number did disconnect in the meantime, then the server will think he reconnected immedeately.
- * In other words: No disadvantage at all.
+ * Fit `now' in an unsigned short, the advantage is that we use less memory
+ * `struct IPregistry::last_connect' can be smaller while the only disadvantage 
+ * is that if someone reconnects after exactly 18 hours and 12 minutes, and NOBODY with the
+ * same _hash_ value for this IP-number did disconnect in the meantime, then the server
+ * will think he reconnected immedeately. In other words: No disadvantage at all.
  */
-#define BITMASK 0xffff         /* Same number of bits as `struct IPregistry::last_connect' */
-#define NOW ((unsigned short)(now & BITMASK))
-#define CONNECTED_SINCE(x) ((unsigned short)((now & BITMASK) - (x)->last_connect))
+#define BITMASK 0xffff          /* Same number of bits as `struct IPregistry::last_connect' */
+#define NOW ((unsigned short)(CurrentTime & BITMASK))
+#define CONNECTED_SINCE(x) ((unsigned short)((CurrentTime & BITMASK) - (x)->last_connect))
 
 #define IPCHECK_CLONE_LIMIT 2
 #define IPCHECK_CLONE_PERIOD 20
@@ -112,12 +113,20 @@ static unsigned short count = 10000, average_length = 4;
 
 static struct IPregistry *IPregistry_add(struct IPregistry_vector *iprv)
 {
+  assert(0 != iprv);
   if (iprv->length == iprv->allocated_length)
   {
     iprv->allocated_length += 4;
-    iprv->vector =
-       (struct IPregistry *)RunRealloc(iprv->vector,
-       iprv->allocated_length * sizeof(struct IPregistry));
+    if (iprv->vector) {
+      iprv->vector = 
+              (struct IPregistry*) MyRealloc(iprv->vector,
+                       iprv->allocated_length * sizeof(struct IPregistry));
+    }
+    else {
+      iprv->vector = 
+              (struct IPregistry*) MyMalloc(
+                       iprv->allocated_length * sizeof(struct IPregistry));
+    }
   }
   return &iprv->vector[iprv->length++];
 }
@@ -130,7 +139,7 @@ static struct IPregistry *IPregistry_find(struct IPregistry_vector *iprv,
     struct IPregistry *i, *end = &iprv->vector[iprv->length];
     for (i = &iprv->vector[0]; i < end; ++i)
       if (IP(i).s_addr == ip.s_addr)
-       return i;
+        return i;
   }
   return NULL;
 }
@@ -138,9 +147,18 @@ static struct IPregistry *IPregistry_find(struct IPregistry_vector *iprv,
 static struct IPregistry *IPregistry_find_with_expire(struct IPregistry_vector
     *iprv, struct in_addr ip)
 {
-  struct IPregistry *last = &iprv->vector[iprv->length - 1];   /* length always > 0 because searched element always exists */
+  struct IPregistry *last;
   struct IPregistry *curr;
-  struct IPregistry *retval = NULL;    /* Core dump if we find nothing :/ - can be removed when code is stable */
+  struct IPregistry *retval = NULL;
+
+  /*
+   * if the vector is empty, IPcheck_disconnect will cause the server
+   * to core when NDEBUG is defined
+   */
+  if (iprv->length < 1)
+    return retval;
+
+  last = &iprv->vector[iprv->length - 1];
 
   for (curr = &iprv->vector[0]; curr < last;)
   {
@@ -149,30 +167,30 @@ static struct IPregistry *IPregistry_find_with_expire(struct IPregistry_vector
       retval = curr;
     else if (curr->connected == 0)
     {
-      if (CONNECTED_SINCE(curr) > 600U)        /* Don't touch this number, it has statistical significance */
+      if (CONNECTED_SINCE(curr) > 600U) /* Don't touch this number, it has statistical significance */
       {
-       /* `curr' expired */
-       if (HAS_TARGETS(curr))
-         RunFree(curr->ip_targets.ptr);
-       *curr = *last--;
-       iprv->length--;
-       if (--count == 0)
-       {
-         /* Make ever 10000 disconnects an estimation of the average vector length */
-         count = 10000;
-         average_length =
-             (nrof.clients + nrof.unknowns + nrof.local_servers) / HASHTABSIZE;
-       }
-       /* Now check the new element (last) that was moved to this position */
-       continue;
+        /* `curr' expired */
+        if (HAS_TARGETS(curr))
+          MyFree(curr->ip_targets.ptr);
+        *curr = *last--;
+        iprv->length--;
+        if (--count == 0)
+        {
+          /* Make ever 10000 disconnects an estimation of the average vector length */
+          count = 10000;
+          average_length =
+              (UserStats.clients + UserStats.unknowns + UserStats.local_servers) / HASHTABSIZE;
+        }
+        /* Now check the new element (last) that was moved to this position */
+        continue;
       }
       else if (CONNECTED_SINCE(curr) > 120U && HAS_TARGETS(curr))
       {
-       /* Expire storage of targets */
-       struct in_addr ip1 = curr->ip_targets.ptr->ip;
-       curr->free_targets = curr->ip_targets.ptr->free_targets;
-       RunFree(curr->ip_targets.ptr);
-       curr->ip_targets.ip = ip1;
+        /* Expire storage of targets */
+        struct in_addr ip1 = curr->ip_targets.ptr->ip;
+        curr->free_targets = curr->ip_targets.ptr->free_targets;
+        MyFree(curr->ip_targets.ptr);
+        curr->ip_targets.ip = ip1;
       }
     }
     /* Did not expire, check next element */
@@ -184,18 +202,18 @@ static struct IPregistry *IPregistry_find_with_expire(struct IPregistry_vector
     retval = curr;
   else if (curr->connected == 0)
   {
-    if (CONNECTED_SINCE(curr) > 600U)  /* Don't touch this number, it has statistical significance */
+    if (CONNECTED_SINCE(curr) > 600U)   /* Don't touch this number, it has statistical significance */
     {
       /* `curr' expired */
       if (HAS_TARGETS(curr))
-       RunFree(curr->ip_targets.ptr);
+        MyFree(curr->ip_targets.ptr);
       iprv->length--;
       if (--count == 0)
       {
-       /* Make ever 10000 disconnects an estimation of the average vector length */
-       count = 10000;
-       average_length =
-           (nrof.clients + nrof.unknowns + nrof.local_servers) / HASHTABSIZE;
+        /* Make ever 10000 disconnects an estimation of the average vector length */
+        count = 10000;
+        average_length =
+            (UserStats.clients + UserStats.unknowns + UserStats.local_servers) / HASHTABSIZE;
       }
     }
     else if (CONNECTED_SINCE(curr) > 120U && HAS_TARGETS(curr))
@@ -203,7 +221,7 @@ static struct IPregistry *IPregistry_find_with_expire(struct IPregistry_vector
       /* Expire storage of targets */
       struct in_addr ip1 = curr->ip_targets.ptr->ip;
       curr->free_targets = curr->ip_targets.ptr->free_targets;
-      RunFree(curr->ip_targets.ptr);
+      MyFree(curr->ip_targets.ptr);
       curr->ip_targets.ip = ip1;
     }
   }
@@ -214,13 +232,13 @@ static struct IPregistry *IPregistry_find_with_expire(struct IPregistry_vector
     struct IPregistry *newpos;
     iprv->allocated_length = iprv->length;
     newpos =
-       (struct IPregistry *)RunRealloc(iprv->vector,
-       iprv->allocated_length * sizeof(struct IPregistry));
-    if (newpos != iprv->vector)        /* Is this ever true? */
+        (struct IPregistry *)MyRealloc(iprv->vector,
+        iprv->allocated_length * sizeof(struct IPregistry));
+    if (newpos != iprv->vector) /* Is this ever true? */
     {
       retval =
-         (struct IPregistry *)((char *)retval + ((char *)newpos -
-         (char *)iprv->vector));
+          (struct IPregistry *)((char *)retval + ((char *)newpos -
+          (char *)iprv->vector));
       iprv->vector = newpos;
     }
   }
@@ -252,9 +270,9 @@ static void reset_connect_time(struct IPregistry *entry)
  *
  * Action:
  *   Update the IPcheck registry.
- *   Return < 0 if the connection should be rejected, otherwise 0.
- *     -1 : Throttled
- *     -2 : Too many connections from your host
+ *   Return:
+ *     1 : You're allowed to connect.
+ *     0 : You're not allowed to connect.
  *
  * Throttling:
  *
@@ -270,43 +288,49 @@ static void reset_connect_time(struct IPregistry *entry)
  * cptr->nexttarget to be `now - (TARGET_DELAY * (FREE_TARGETS - 1))',
  * where FREE_TARGETS may range from 0 till STARTTARGETS.
  */
-int IPcheck_local_connect(aClient *cptr)
+int IPcheck_local_connect(struct in_addr a, time_t* next_target_out)
 {
   struct IPregistry *entry;
-  CALCULATE_HASH(cptr->ip);
-  SetIPChecked(cptr);          /* Mark that we did add/update an IPregistry entry */
-  if (!(entry = IPregistry_find(hash, cptr->ip)))
+  CALCULATE_HASH(a);
+  assert(0 != next_target_out);
+
+  if (!(entry = IPregistry_find(hash, a)))
   {
     entry = IPregistry_add(hash);
-    entry->ip_targets.ip = cptr->ip;   /* The IP number of registry entry */
-    entry->last_connect = NOW; /* Seconds since last connect (attempt) */
-    entry->connected = 1;      /* Number of currently connected clients with this IP number */
-    entry->connect_attempts = 1;       /* Number of clients that connected with this IP number */
-    entry->free_targets = STARTTARGETS;        /* Number of free targets that a client gets on connect */
-    return 0;
+    entry->ip_targets.ip = a;          /* The IP number of registry entry */
+    entry->last_connect = NOW;          /* Seconds since last connect attempt */
+    entry->connected = 1;               /* connected clients for this IP */
+    entry->connect_attempts = 1;        /* Number attempts for this IP */
+    entry->free_targets = STARTTARGETS; /* free targets a client gets */
+    return 1;
   }
-#ifdef GODMODE
-  sendto_one(cptr,
-      "ERROR :I saw your face before my friend (connected: %u; connect_attempts %u; free_targets %u)",
-      entry->connected, entry->connect_attempts, FREE_TARGETS(entry));
-#endif
-  /* Note that this also connects server connects.  It is hard and not interesting, to change that. */
-  if (++(entry->connected) == 0)       /* Don't allow more then 255 connects from one IP number, ever */
-    return -2;
+  /* Note that this also connects server connects.
+   * It is hard and not interesting, to change that.
+   *
+   * Don't allow more then 255 connects from one IP number, ever
+   */
+  if (0 == ++entry->connected)
+    return 0;
+
   if (CONNECTED_SINCE(entry) > IPCHECK_CLONE_PERIOD)
     entry->connect_attempts = 0;
+
   reset_connect_time(entry);
-  if (++(entry->connect_attempts) == 0)        /* Check for overflow */
-    --(entry->connect_attempts);
+
+  if (0 == ++entry->connect_attempts)   /* Check for overflow */
+    --entry->connect_attempts;
+
   if (entry->connect_attempts <= IPCHECK_CLONE_LIMIT)
-    cptr->nexttarget = now - (TARGET_DELAY * (FREE_TARGETS(entry) - 1));
-#ifdef DEBUGMODE
-  else
+    *next_target_out = CurrentTime - (TARGET_DELAY * (FREE_TARGETS(entry) - 1));
+
+  /* Don't refuse connection when we just rebooted the server */
+  else if (CurrentTime - me.since > IPCHECK_CLONE_DELAY)
+#ifndef NOTHROTTLE 
+    return 0;
 #else
-  else if (now - me.since > IPCHECK_CLONE_DELAY)       /* Don't refuse connection when we just rebooted the server */
-#endif
-    return -1;
-  return 0;
+    return 1;
+#endif        
+  return 1;
 }
 
 /*
@@ -320,37 +344,37 @@ int IPcheck_local_connect(aClient *cptr)
  *   Update the IPcheck registry.
  *   Return -1 on failure, 0 on success.
  */
-int IPcheck_remote_connect(aClient *cptr, const char *UNUSED(hostname),
+int IPcheck_remote_connect(struct Client *cptr, const char *hostname,
     int is_burst)
 {
   struct IPregistry *entry;
   CALCULATE_HASH(cptr->ip);
-  SetIPChecked(cptr);          /* Mark that we did add/update an IPregistry entry */
+  SetIPChecked(cptr);           /* Mark that we did add/update an IPregistry entry */
   if (!(entry = IPregistry_find(hash, cptr->ip)))
   {
     entry = IPregistry_add(hash);
-    entry->ip_targets.ip = cptr->ip;   /* The IP number of registry entry */
-    entry->last_connect = NOW; /* Seconds since last connect (attempt) */
-    entry->connected = 1;      /* Number of currently connected clients with this IP number */
-    entry->connect_attempts = is_burst ? 1 : 0;        /* Number of clients that connected with this IP number */
-    entry->free_targets = STARTTARGETS;        /* Number of free targets that a client gets on connect */
+    entry->ip_targets.ip = cptr->ip;    /* The IP number of registry entry */
+    entry->last_connect = NOW;  /* Seconds since last connect (attempt) */
+    entry->connected = 1;       /* Number of currently connected clients with this IP number */
+    entry->connect_attempts = is_burst ? 1 : 0; /* Number of clients that connected with this IP number */
+    entry->free_targets = STARTTARGETS; /* Number of free targets that a client gets on connect */
   }
   else
   {
 #ifdef GODMODE
     sendto_one(cptr,
-       "%s NOTICE %s%s :I saw your face before my friend (connected: %u; connect_attempts %u; free_targets %u)",
-       NumServ(&me), NumNick(cptr), entry->connected, entry->connect_attempts,
-       FREE_TARGETS(entry));
+        "%s NOTICE %s%s :I saw your face before my friend (connected: %u; connect_attempts %u; free_targets %u)",
+        NumServ(&me), NumNick(cptr), entry->connected, entry->connect_attempts,
+        FREE_TARGETS(entry));
 #endif
-    if (++(entry->connected) == 0)     /* Don't allow more then 255 connects from one IP number, ever */
+    if (++(entry->connected) == 0)      /* Don't allow more then 255 connects from one IP number, ever */
       return -1;
     if (CONNECTED_SINCE(entry) > IPCHECK_CLONE_PERIOD)
       entry->connect_attempts = 0;
     if (!is_burst)
     {
-      if (++(entry->connect_attempts) == 0)    /* Check for overflow */
-       --(entry->connect_attempts);
+      if (++(entry->connect_attempts) == 0)     /* Check for overflow */
+        --(entry->connect_attempts);
       reset_connect_time(entry);
     }
   }
@@ -368,12 +392,12 @@ int IPcheck_remote_connect(aClient *cptr, const char *UNUSED(hostname),
  *   a way that the client won't be penalized when trying to reconnect
  *   again.
  */
-void IPcheck_connect_fail(aClient *cptr)
+void IPcheck_connect_fail(struct in_addr a)
 {
   struct IPregistry *entry;
-  CALCULATE_HASH(cptr->ip);
-  entry = IPregistry_find(hash, cptr->ip);
-  entry->connect_attempts--;
+  CALCULATE_HASH(a);
+  if ((entry = IPregistry_find(hash, a)))
+    --entry->connect_attempts;
 }
 
 /*
@@ -384,7 +408,7 @@ void IPcheck_connect_fail(aClient *cptr)
  *
  * Finish IPcheck registration of a successfully, locally connected client.
  */
-void IPcheck_connect_succeeded(aClient *cptr)
+void IPcheck_connect_succeeded(struct Client *cptr)
 {
   struct IPregistry *entry;
   const char *tr = "";
@@ -411,28 +435,43 @@ void IPcheck_connect_succeeded(aClient *cptr)
  *   Remove all expired IPregistry structures from the hash bucket
  *     that belongs to this clients IP number.
  */
-void IPcheck_disconnect(aClient *cptr)
+void IPcheck_disconnect(struct Client *cptr)
 {
   struct IPregistry *entry;
   CALCULATE_HASH(cptr->ip);
   entry = IPregistry_find_with_expire(hash, cptr->ip);
-  if (--(entry->connected) == 0)       /* If this was the last one, set `last_connect' to disconnect time (used for expiration) */
-  {
+  if (0 == entry) {
+    /*
+     * trying to find an entry for a server causes this to happen,
+     * servers should never have FLAGS_IPCHECK set
+     */
+    assert(0 != entry);
+    return;
+  }
+  /*
+   * If this was the last one, set `last_connect' to disconnect time (used for expiration)
+   */
+  if (--(entry->connected) == 0) {
     if (CONNECTED_SINCE(entry) > IPCHECK_CLONE_LIMIT * IPCHECK_CLONE_PERIOD)
-      entry->connect_attempts = 0;     /* Otherwise we'd penetalize for this old value if the client reconnects within 20 seconds */
+      /*
+       * Otherwise we'd penetalize for this old value if the client reconnects within 20 seconds
+       */
+      entry->connect_attempts = 0;
     reset_connect_time(entry);
   }
-  if (MyConnect(cptr))
-  {
+  if (MyConnect(cptr)) {
     unsigned int inheritance;
-    /* Copy the clients targets */
-    if (HAS_TARGETS(entry))
-    {
+    /*
+     * Copy the clients targets
+     */
+    if (HAS_TARGETS(entry)) {
       entry->free_targets = entry->ip_targets.ptr->free_targets;
-      RunFree(entry->ip_targets.ptr);
+      MyFree(entry->ip_targets.ptr);
     }
     entry->ip_targets.ptr =
-       (struct ip_targets_st *)RunMalloc(sizeof(struct ip_targets_st));
+        (struct ip_targets_st*) MyMalloc(sizeof(struct ip_targets_st));
+
+    assert(0 != entry->ip_targets.ptr);
     entry->ip_targets.ptr->ip = cptr->ip;
     entry->ip_targets.ptr->free_targets = entry->free_targets;
     entry->free_targets = HAS_TARGETS_MAGIC;
@@ -450,14 +489,24 @@ void IPcheck_disconnect(aClient *cptr)
      * ALL should get no free targets when reconnecting.  We'd need to store an entry
      * per client (instead of per IP number) to avoid this.
      */
-    if (cptr->nexttarget <= now)
-      inheritance = (now - cptr->nexttarget) / TARGET_DELAY + 1;       /* Number of free targets */
+    if (cptr->nexttarget <= CurrentTime)
+        /*
+         * Number of free targets
+         */
+      inheritance = (CurrentTime - cptr->nexttarget) / TARGET_DELAY + 1;
     else
       inheritance = 0;
-    /* Add bonus, this is pretty fuzzy, but it will help in some cases. */
-    if (now - cptr->firsttime > 600)   /* Was longer then 10 minutes online? */
-      inheritance += (now - cptr->firsttime - 600) / TARGET_DELAY;
-    /* Finally, store smallest value for Judgement Day */
+    /*
+     * Add bonus, this is pretty fuzzy, but it will help in some cases.
+     */
+    if (CurrentTime - cptr->firsttime > 600)
+      /*
+       * Was longer then 10 minutes online?
+       */
+      inheritance += (CurrentTime - cptr->firsttime - 600) / TARGET_DELAY;
+    /*
+     * Finally, store smallest value for Judgement Day
+     */
     if (inheritance < entry->ip_targets.ptr->free_targets)
       entry->ip_targets.ptr->free_targets = inheritance;
   }
@@ -468,10 +517,11 @@ void IPcheck_disconnect(aClient *cptr)
  *
  * Returns number of clients with the same IP number
  */
-unsigned short IPcheck_nr(aClient *cptr)
+unsigned short IPcheck_nr(struct Client *cptr)
 {
   struct IPregistry *entry;
   CALCULATE_HASH(cptr->ip);
   entry = IPregistry_find(hash, cptr->ip);
   return (entry ? entry->connected : 0);
 }
+
index 4bf1c443d3489adb9d61409df246fae5da456956..838a0a6726f3a4c4c223a317584895088f3b4226 100644 (file)
@@ -37,6 +37,7 @@ CHGRP=chgrp
 MKDIR=mkdir
 TOUCH=touch
 GREP=grep
+OSDEP_C=@OSDEP_C@
 @SET_MAKE@
 # The following variables are replaced by what you give during configuration :
 
@@ -56,14 +57,115 @@ LDFLAGS=
 IRCDLIBS=
 
 #### End of system configuration section. ####
-
-OBJS=IPcheck.o bsd.o channel.o class.o common.o crule.o dbuf.o fileio.o ircd.o \
-     list.o map.o match.o numnicks.o opercmds.o packet.o parse.o querycmds.o \
-     random.o res.o runmalloc.o s_auth.o s_bsd.o s_conf.o s_debug.o s_err.o \
-     s_misc.o s_numeric.o s_ping.o s_serv.o s_user.o send.o sprintf_irc.o \
-     support.o userload.o whocmds.o whowas.o hash.o
-
-SRC=${OBJS:%.o=%.c}
+PURIFY =
+
+SRC = \
+       IPcheck.c \
+       channel.c \
+       class.c \
+       crule.c \
+       dbuf.c \
+       fda.c \
+       fileio.c \
+       gline.c \
+       hash.c \
+       ircd.c \
+       ircd_alloc.c \
+       ircd_log.c \
+       ircd_osdep.c \
+       ircd_relay.c \
+       ircd_reply.c \
+       ircd_signal.c \
+       ircd_string.c \
+       ircd_xopen.c \
+       list.c \
+       listener.c \
+       m_admin.c \
+       m_away.c \
+       m_burst.c \
+       m_close.c \
+       m_connect.c \
+       m_cprivmsg.c \
+       m_create.c \
+       m_defaults.c \
+       m_destruct.c \
+       m_desynch.c \
+       m_die.c \
+       m_endburst.c \
+       m_error.c \
+       m_gline.c \
+       m_help.c \
+       m_info.c \
+       m_invite.c \
+       m_ison.c \
+       m_join.c \
+       m_kick.c \
+       m_kill.c \
+       m_links.c \
+       m_list.c \
+       m_lusers.c \
+       m_map.c \
+       m_mode.c \
+       m_motd.c \
+       m_names.c \
+       m_nick.c \
+       m_notice.c \
+       m_oper.c \
+       m_part.c \
+       m_pass.c \
+       m_ping.c \
+       m_pong.c \
+       m_privmsg.c \
+       m_proto.c \
+       m_quit.c \
+       m_rehash.c \
+       m_restart.c \
+       m_rping.c \
+       m_rpong.c \
+       m_server.c \
+       m_settime.c \
+       m_silence.c \
+       m_squit.c \
+       m_stats.c \
+       m_time.c \
+       m_topic.c \
+       m_trace.c \
+       m_user.c \
+       m_userhost.c \
+       m_userip.c \
+       m_version.c \
+       m_wallchops.c \
+       m_wallops.c \
+       m_who.c \
+       m_whois.c \
+       m_whowas.c \
+       map.c \
+       match.c \
+       numnicks.c \
+       opercmds.c \
+       packet.c \
+       parse.c \
+       querycmds.c \
+       random.c \
+       res.c \
+       s_auth.c \
+       s_bsd.c \
+       s_conf.c \
+       s_debug.c \
+       s_err.c \
+       s_misc.c \
+       s_numeric.c \
+       s_serv.c \
+       s_user.c \
+       send.c \
+       sprintf_irc.c \
+       support.c \
+       uping.c \
+       userload.c \
+       whocmds.c \
+       whowas.c
+
+OBJS = ${SRC:%.c=%.o}
 
 all:
        ( cd ..; make -f Makefile )
@@ -75,24 +177,35 @@ all:
 
 build: ircd chkconf
 
-ircd: ${OBJS} ../include/patchlevel.h
-       ${SHELL} version.c.SH
-       ${CC} ${CFLAGS} ${CPPFLAGS} -c version.c
-       ${CC} ${CFLAGS} ${OBJS} version.o ${LDFLAGS} ${IRCDLIBS} -o ircd
+ircd: ${OBJS} ../include/patchlevel.h version.o
+       ${PURIFY} ${CC} ${OBJS} version.o ${LDFLAGS} ${IRCDLIBS} -o ircd
        ${CHMOD} ${IRCDMODE} ircd
 
-chkcrule.o: crule.c ../include/sys.h ../include/../config/config.h \
-       ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
-       ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
-       ../include/whowas.h ../include/s_serv.h ../include/ircd.h \
-       ../include/match.h ../include/s_bsd.h ../include/s_conf.h \
-       ../include/list.h ../include/common.h ../include/crule.h
+#
+# Make sure the anti hack checksums get included when things change
+# bleah
+#
+version.c: version.c.SH s_serv.c s_user.c channel.c s_bsd.c s_misc.c ircd.c
+       ${SHELL} version.c.SH
+
+ircd_osdep.c: ${OSDEP_C}
+       rm -f ircd_osdep.c
+       ln -s ${OSDEP_C} ircd_osdep.c
+
+ircd_string.o: ircd_string.c chattr.tab.c
+
+table_gen: table_gen.o
+       ${CC} -o $@ table_gen.o
+
+chattr.tab.c: table_gen
+       ./table_gen > chattr.tab.c
+
+chkcrule.o: crule.c
        ${CC} ${CFLAGS} ${CPPFLAGS} -DCR_CHKCONF -o chkcrule.o -c crule.c
 
-chkconf: chkconf.o match.o common.o chkcrule.o runmalloc.o fileio.o
-       ${CC} ${CFLAGS} ${CPPFLAGS} \
-           chkconf.o match.o common.o chkcrule.o runmalloc.o fileio.o \
-           ${LDFLAGS} ${IRCDLIBS} -o chkconf
+chkconf: chkconf.o fda.o match.o chkcrule.o ircd_alloc.o fileio.o ircd_string.o
+       ${CC} chkconf.o fda.o match.o chkcrule.o ircd_alloc.o fileio.o \
+       ircd_string.o ${LDFLAGS} ${IRCDLIBS} -o chkconf
 
 install: build
        @if [ ! -d ${DPATH} -a ! -f ${DPATH} ]; then \
@@ -102,13 +215,7 @@ install: build
          ${CHOWN} ${IRCDOWN} ${DPATH}; \
          ${CHGRP} ${IRCDGRP} ${DPATH}; \
        fi
-       @echo `date +%y%m%d%H%M`.`cat ../.patches | \
-           ${AWK} -F . '{ if ($$(NF)~/\+$$/) { \
-               for(i=1;i<NF;i++) \
-                 printf("%s_",$$i); \
-                 gsub("\\\\+","",$$(NF)); \
-               }; \
-               print $$(NF) }'` > /tmp/ircd.tag;
+       @echo `date +%Y%m%d%H%M` > /tmp/ircd.tag;
        @echo "Installing new ircd as ${BINDIR}/ircd.`cat /tmp/ircd.tag` :"
        ${INSTALL} -m ${IRCDMODE} -o ${IRCDOWN} -g ${IRCDGRP} ircd ${BINDIR}/ircd.`cat /tmp/ircd.tag`
        @( cd ${BINDIR}; \
@@ -131,43 +238,22 @@ uninstall:
        @echo "Please remove the contents of ${DPATH} manually"
 
 clean:
-       ${RM} -f *.o ircd version.c chkconf
+       ${RM} -f *.o *.bak ircd version.c chkconf ircd_osdep.c chattr.tab.c table_gen
 
 distclean: clean
        ${RM} -f Makefile stamp-m
 
 maintainer-clean: distclean
 
-ctables: common.c
-       ${CC} -I../include -DMAKETABLES common.c || exit 1
-       { ${GREP} -A1 -B1000 ^...NTL_TOK_START common.c ; ./a.out ; \
-         ${GREP} -A1000 -B1 ^...NTL_TOK_END common.c ; } > common.temp || exit 1;
-       ${MV} common.temp common.c
-       ${RM} a.out
-
 depend:
        @if [ -f Makefile.in.bak ]; then \
          echo "make depend: First remove ircd/Makefile.in.bak"; \
        else \
          ( ${MV} Makefile.in Makefile.in.bak; \
-           ${GREP} -A1 -B1000 '^# DO NOT DELETE THIS LINE' Makefile.in.bak > Makefile.in;\
-           ${CC} ${CFLAGS} -MM ${CPPFLAGS} ${SRC:hash.c=} >> Makefile.in; ) \
+           ${GREP} -A1 -B10000 '^# DO NOT DELETE THIS LINE' Makefile.in.bak > Makefile.in;\
+           ${CC} ${CFLAGS} -MM ${CPPFLAGS} ${SRC} >> Makefile.in; ) \
        fi
 
-hash.o: hash.c ../include/sys.h ../config/config.h \
- ../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/common.h ../include/match.h ../include/hash.h \
- ../include/channel.h ../include/list.h ../include/send.h \
- ../include/s_serv.h ../include/ircd.h \
- ircd.c version.c.SH
-       @CC="${CC}" CFLAGS="${CFLAGS}" CPPFLAGS="${CPPFLAGS}" \
-       crypt/sums
-       ${CC} ${CFLAGS} ${CPPFLAGS} -c hash.c -o hash.o
-       @${RM} -f hash.c
-       @${MV} -f hash.c.old hash.c
-       @${TOUCH} hash.o
-
 # Coders: You need GNU make for this to work
 Makefile: ../config/config.status Makefile.in ../config/gen.ircd.Makefile \
          ../config/config.h ../config/.config stamp-m
@@ -188,273 +274,681 @@ stamp-m:
 
 # DO NOT DELETE THIS LINE -- make depend depends on it.
 
-IPcheck.o: IPcheck.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/IPcheck.h ../include/querycmds.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/s_user.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/list.h ../include/numnicks.h ../include/send.h
-bsd.o: bsd.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/list.h ../include/ircd.h ../include/bsd.h
-channel.o: channel.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/channel.h ../include/list.h \
- ../include/parse.h ../include/send.h ../include/s_err.h \
- ../include/numeric.h ../include/ircd.h ../include/common.h \
- ../include/match.h ../include/hash.h ../include/s_serv.h \
- ../include/s_misc.h ../include/s_user.h ../include/s_conf.h \
- ../include/s_bsd.h ../include/msg.h ../include/support.h \
- ../include/numnicks.h ../include/sprintf_irc.h ../include/querycmds.h
-class.o: class.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/class.h ../include/s_conf.h \
- ../include/list.h ../include/s_serv.h ../include/send.h \
- ../include/s_err.h ../include/numeric.h ../include/ircd.h
-common.o: common.c ../include/common.h ../include/sys.h \
- ../include/../config/config.h ../include/../config/setup.h \
- ../include/runmalloc.h
-crule.o: crule.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_serv.h ../include/ircd.h \
- ../include/match.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/list.h ../include/common.h ../include/crule.h
-dbuf.o: dbuf.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/dbuf.h
-ircd.o: ircd.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/res.h ../include/list.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/s_serv.h ../include/send.h ../include/ircd.h \
- ../include/s_conf.h ../include/class.h ../include/s_misc.h \
- ../include/parse.h ../include/match.h ../include/s_bsd.h \
- ../include/crule.h ../include/userload.h ../include/numeric.h \
- ../include/hash.h ../include/bsd.h ../include/version.h \
- ../include/numnicks.h
-list.o: list.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/numeric.h ../include/send.h \
- ../include/s_conf.h ../include/list.h ../include/class.h \
- ../include/match.h ../include/ircd.h ../include/s_serv.h \
- ../include/support.h ../include/s_misc.h ../include/s_bsd.h \
- ../include/res.h ../include/common.h ../include/s_user.h \
- ../include/opercmds.h
-map.o: map.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/numeric.h ../include/send.h \
- ../include/match.h ../include/list.h ../include/s_err.h \
- ../include/ircd.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/s_misc.h ../include/map.h
-match.o: match.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/common.h ../include/match.h \
- ../include/ircd.h
-numnicks.o: numnicks.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/s_serv.h ../include/struct.h \
- ../include/dbuf.h ../include/whowas.h ../include/common.h \
- ../include/numnicks.h ../include/ircd.h ../include/parse.h \
- ../include/s_misc.h ../include/match.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/list.h
-opercmds.o: opercmds.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/opercmds.h ../include/struct.h \
- ../include/dbuf.h ../include/whowas.h ../include/ircd.h \
- ../include/s_bsd.h ../include/s_conf.h ../include/list.h \
- ../include/send.h ../include/s_err.h ../include/numeric.h \
- ../include/match.h ../include/s_misc.h ../include/class.h \
- ../include/s_user.h ../include/common.h ../include/msg.h \
- ../include/sprintf_irc.h ../include/userload.h ../include/parse.h \
- ../include/numnicks.h ../include/crule.h ../include/version.h \
- ../include/support.h ../include/s_serv.h ../include/hash.h
-packet.o: packet.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_misc.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/list.h ../include/ircd.h \
- ../include/msg.h ../include/parse.h ../include/send.h \
- ../include/packet.h ../include/s_serv.h
-parse.o: parse.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_serv.h ../include/send.h \
- ../include/parse.h ../include/common.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/list.h ../include/msg.h \
- ../include/s_user.h ../include/channel.h ../include/s_ping.h \
- ../include/res.h ../include/map.h ../include/hash.h \
- ../include/numeric.h ../include/ircd.h ../include/s_misc.h \
- ../include/s_numeric.h ../include/numnicks.h ../include/opercmds.h \
- ../include/querycmds.h ../include/whocmds.h
-querycmds.o: querycmds.c ../include/sys.h \
- ../include/../config/config.h ../include/../config/setup.h \
- ../include/runmalloc.h ../include/h.h ../include/s_debug.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/parse.h ../include/send.h ../include/s_err.h \
- ../include/numeric.h ../include/ircd.h ../include/s_user.h \
- ../include/version.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/list.h ../include/s_misc.h ../include/match.h \
- ../include/s_serv.h ../include/msg.h ../include/channel.h \
- ../include/numnicks.h ../include/userload.h ../include/support.h \
- ../include/querycmds.h
-random.o: random.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h \
- ../include/random.h
-res.o: res.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/res.h ../include/list.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/numeric.h ../include/send.h ../include/s_misc.h \
- ../include/s_bsd.h ../include/s_conf.h ../include/ircd.h \
- ../include/s_ping.h ../include/support.h ../include/common.h \
- ../include/sprintf_irc.h
-runmalloc.o: runmalloc.c ../include/sys.h \
- ../include/../config/config.h ../include/../config/setup.h \
- ../include/runmalloc.h ../include/h.h ../include/s_debug.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/send.h ../include/numeric.h ../include/s_err.h \
- ../include/ircd.h ../include/s_serv.h ../include/numnicks.h
-s_auth.o: s_auth.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/res.h ../include/list.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/common.h ../include/send.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/s_misc.h ../include/support.h \
- ../include/ircd.h ../include/s_auth.h ../include/sprintf_irc.h
-s_bsd.o: s_bsd.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/res.h ../include/list.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/s_bsd.h ../include/s_conf.h ../include/s_serv.h \
- ../include/numeric.h ../include/send.h ../include/s_misc.h \
- ../include/hash.h ../include/s_err.h ../include/ircd.h \
- ../include/support.h ../include/s_auth.h ../include/class.h \
- ../include/packet.h ../include/s_ping.h ../include/channel.h \
- ../include/version.h ../include/parse.h ../include/common.h \
- ../include/bsd.h ../include/numnicks.h ../include/s_user.h \
- ../include/sprintf_irc.h ../include/querycmds.h ../include/IPcheck.h
-s_conf.o: s_conf.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_serv.h ../include/opercmds.h \
- ../include/numeric.h ../include/send.h ../include/s_conf.h \
- ../include/list.h ../include/class.h ../include/s_misc.h \
- ../include/match.h ../include/common.h ../include/s_err.h \
- ../include/s_bsd.h ../include/ircd.h ../include/crule.h \
- ../include/res.h ../include/support.h ../include/parse.h \
- ../include/numnicks.h ../include/sprintf_irc.h ../include/IPcheck.h \
- ../include/hash.h
-s_debug.o: s_debug.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/numeric.h ../include/hash.h \
- ../include/s_serv.h ../include/send.h ../include/s_conf.h \
- ../include/list.h ../include/class.h ../include/ircd.h \
- ../include/s_bsd.h ../include/bsd.h ../include/res.h \
- ../include/channel.h ../include/numnicks.h
-s_err.o: s_err.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/numeric.h ../include/s_err.h \
- ../include/sprintf_irc.h
-s_misc.o: s_misc.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_serv.h ../include/numeric.h \
- ../include/send.h ../include/s_conf.h ../include/list.h \
- ../include/s_misc.h ../include/common.h ../include/match.h \
- ../include/hash.h ../include/s_bsd.h ../include/res.h \
- ../include/ircd.h ../include/s_ping.h ../include/channel.h \
- ../include/s_err.h ../include/support.h ../include/userload.h \
- ../include/parse.h ../include/s_user.h ../include/numnicks.h \
- ../include/sprintf_irc.h ../include/querycmds.h ../include/IPcheck.h
-s_numeric.o: s_numeric.c ../include/sys.h \
- ../include/../config/config.h ../include/../config/setup.h \
- ../include/runmalloc.h ../include/h.h ../include/s_debug.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/s_serv.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/list.h ../include/send.h ../include/support.h \
- ../include/parse.h ../include/numeric.h ../include/channel.h \
- ../include/ircd.h ../include/hash.h ../include/numnicks.h \
- ../include/s_numeric.h
-s_ping.o: s_ping.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/send.h ../include/s_conf.h \
- ../include/list.h ../include/match.h ../include/res.h \
- ../include/s_bsd.h ../include/s_serv.h ../include/ircd.h \
- ../include/s_ping.h ../include/support.h ../include/numeric.h \
- ../include/s_user.h ../include/s_err.h ../include/common.h \
- ../include/numnicks.h
-s_serv.o: s_serv.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/ircd.h ../include/s_serv.h \
- ../include/s_misc.h ../include/sprintf_irc.h ../include/send.h \
- ../include/s_err.h ../include/numeric.h ../include/s_bsd.h \
- ../include/s_conf.h ../include/list.h ../include/hash.h \
- ../include/common.h ../include/match.h ../include/crule.h \
- ../include/parse.h ../include/numnicks.h ../include/userload.h \
- ../include/s_user.h ../include/channel.h ../include/querycmds.h \
- ../include/IPcheck.h
-s_user.o: s_user.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/common.h ../include/s_serv.h \
- ../include/numeric.h ../include/send.h ../include/s_conf.h \
- ../include/list.h ../include/s_misc.h ../include/match.h \
- ../include/hash.h ../include/s_bsd.h ../include/s_err.h \
- ../include/parse.h ../include/ircd.h ../include/s_user.h \
- ../include/support.h ../include/channel.h ../include/random.h \
- ../include/version.h ../include/msg.h ../include/userload.h \
- ../include/numnicks.h ../include/sprintf_irc.h ../include/querycmds.h \
- ../include/IPcheck.h
-send.o: send.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/s_bsd.h ../include/s_conf.h \
- ../include/list.h ../include/s_serv.h ../include/send.h \
- ../include/s_misc.h ../include/common.h ../include/match.h \
- ../include/ircd.h ../include/channel.h ../include/bsd.h \
- ../include/class.h ../include/s_user.h ../include/sprintf_irc.h
-sprintf_irc.o: sprintf_irc.c ../include/sys.h \
- ../include/../config/config.h ../include/../config/setup.h \
- ../include/runmalloc.h ../include/h.h ../include/s_debug.h \
+IPcheck.o: IPcheck.c ../include/IPcheck.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/numnicks.h ../include/querycmds.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/s_bsd.h \
+ ../include/s_user.h ../include/send.h
+channel.o: channel.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/gline.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/list.h \
+ ../include/match.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h ../include/sprintf_irc.h \
+ ../include/support.h ../include/whowas.h
+class.o: class.c ../include/class.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/list.h ../include/numeric.h \
+ ../include/s_conf.h ../include/s_debug.h ../include/send.h
+crule.o: crule.c ../include/crule.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_string.h ../include/match.h \
+ ../include/s_bsd.h ../include/s_debug.h
+dbuf.o: dbuf.c ../include/dbuf.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_chattr.h ../include/send.h \
+ ../include/sys.h ../config/config.h ../config/setup.h
+fda.o: fda.c
+fileio.o: fileio.c ../include/fileio.h ../include/ircd_alloc.h \
+ ../include/fda.h
+gline.o: gline.c ../include/gline.h ../config/config.h \
+ ../config/setup.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/numeric.h ../include/s_bsd.h ../include/s_misc.h \
+ ../include/send.h ../include/sys.h
+hash.o: hash.c ../include/hash.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/channel.h \
+ ../config/config.h ../config/setup.h ../include/ircd_chattr.h \
+ ../include/ircd_string.h ../include/ircd.h ../include/struct.h \
+ ../include/send.h ../include/support.h ../include/sys.h
+ircd.o: ircd.c ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_defs.h ../include/class.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_handler.h \
+ ../include/crule.h ../include/hash.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_log.h ../include/ircd_signal.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/listener.h ../include/match.h ../include/numeric.h \
+ ../include/numnicks.h ../include/parse.h ../include/res.h \
+ ../include/s_auth.h ../include/s_bsd.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/send.h \
+ ../include/sys.h ../include/userload.h ../include/version.h \
+ ../include/whowas.h ../include/msg.h
+ircd_alloc.o: ircd_alloc.c ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_string.h ../config/config.h ../config/setup.h \
+ ../include/ircd_chattr.h ../include/s_debug.h ../include/ircd_defs.h
+ircd_log.o: ircd_log.c ../include/ircd_log.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../config/config.h ../config/setup.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/s_debug.h ../include/struct.h
+ircd_osdep.o: ircd_osdep.c ../include/ircd_osdep.h
+ircd_relay.o: ircd_relay.c ../include/ircd_relay.h \
+ ../include/channel.h ../config/config.h ../config/setup.h \
+ ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h
+ircd_reply.o: ircd_reply.c ../include/ircd_reply.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/numeric.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/send.h
+ircd_signal.o: ircd_signal.c ../include/ircd_signal.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_defs.h
+ircd_string.o: ircd_string.c ../include/ircd_string.h \
+ ../config/config.h ../config/setup.h ../include/ircd_chattr.h \
+ ../include/ircd_defs.h chattr.tab.c
+ircd_xopen.o: ircd_xopen.c ../include/ircd_xopen.h
+list.o: list.c ../include/list.h ../include/class.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_defs.h \
+ ../include/ircd_handler.h ../include/ircd.h ../config/config.h \
+ ../config/setup.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/match.h ../include/numeric.h ../include/res.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h \
+ ../include/support.h ../include/whowas.h
+listener.o: listener.c ../include/listener.h ../include/ircd_defs.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_osdep.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_misc.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/sys.h
+m_admin.o: m_admin.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_conf.h ../include/s_user.h
+m_away.o: m_away.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_user.h ../include/send.h
+m_burst.o: m_burst.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+ ../include/s_misc.h ../include/send.h
+m_close.o: m_close.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/numeric.h ../include/s_bsd.h \
+ ../include/send.h
+m_connect.o: m_connect.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/crule.h \
+ ../include/hash.h ../include/ircd.h ../config/config.h \
+ ../config/setup.h ../include/struct.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_user.h ../include/send.h
+m_cprivmsg.o: m_cprivmsg.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/ircd_chattr.h ../include/s_user.h
+m_create.o: m_create.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_defaults.o: m_defaults.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/numeric.h ../include/numnicks.h \
+ ../include/send.h ../include/supported.h ../include/channel.h \
+ ../include/version.h
+m_destruct.o: m_destruct.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h
+m_desynch.o: m_desynch.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_bsd.h ../include/send.h
+m_die.o: m_die.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_bsd.h ../include/send.h
+m_endburst.o: m_endburst.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/send.h
+m_error.o: m_error.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/send.h
+m_gline.o: m_gline.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/gline.h \
+ ../config/config.h ../config/setup.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_conf.h ../include/s_misc.h ../include/send.h \
+ ../include/support.h
+m_help.o: m_help.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h
+m_info.o: m_info.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h ../include/version.h
+m_invite.o: m_invite.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_user.h ../include/send.h
+m_ison.o: m_ison.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/send.h
+m_join.o: m_join.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/gline.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_user.h ../include/send.h \
+ ../include/handlers.h
+m_kick.o: m_kick.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_kill.o: m_kill.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_misc.h \
+ ../include/send.h ../include/whowas.h
+m_links.o: m_links.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/send.h
+m_list.o: m_list.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h
+m_lusers.o: m_lusers.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/s_user.h \
+ ../include/s_serv.h ../include/send.h
+m_map.o: m_map.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/map.h ../include/numeric.h \
+ ../include/send.h
+m_mode.o: m_mode.c ../include/handlers.h ../include/channel.h \
+ ../config/config.h ../config/setup.h ../include/ircd_defs.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_user.h \
+ ../include/send.h
+m_motd.o: m_motd.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_conf.h \
+ ../include/s_user.h ../include/send.h
+m_names.o: m_names.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/send.h
+m_nick.o: m_nick.c ../include/IPcheck.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../config/config.h \
+ ../config/setup.h ../include/struct.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h
+m_notice.o: m_notice.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_chattr.h ../include/ircd_relay.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/match.h ../include/msg.h \
+ ../include/numeric.h ../include/send.h ../include/handlers.h
+m_oper.o: m_oper.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/ircd_xopen.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_user.h ../include/send.h
+m_part.o: m_part.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_pass.o: m_pass.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/ircd_chattr.h ../include/send.h
+m_ping.o: m_ping.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/ircd_chattr.h ../include/ircd.h \
+ ../include/struct.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/send.h
+m_pong.o: m_pong.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_user.h ../include/send.h
+m_privmsg.o: m_privmsg.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_relay.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/send.h
+m_proto.o: m_proto.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_chattr.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/send.h ../include/supported.h ../include/channel.h \
+ ../include/version.h
+m_quit.o: m_quit.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/struct.h ../include/s_misc.h
+m_rehash.o: m_rehash.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/numeric.h ../include/s_conf.h ../include/send.h
+m_restart.o: m_restart.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_rping.o: m_rping.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/opercmds.h ../include/s_user.h \
+ ../include/send.h
+m_rpong.o: m_rpong.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/numnicks.h \
+ ../include/opercmds.h ../include/send.h
+m_server.o: m_server.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/crule.h \
+ ../include/hash.h ../include/ircd.h ../config/config.h \
+ ../config/setup.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/match.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_serv.h ../include/send.h ../include/userload.h
+m_settime.o: m_settime.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/list.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/send.h
+m_silence.o: m_silence.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_user.h ../include/send.h
+m_squit.o: m_squit.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/numeric.h ../include/numnicks.h \
+ ../include/match.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h
+m_stats.o: m_stats.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/class.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_handler.h \
+ ../include/gline.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/list.h ../include/listener.h \
+ ../include/match.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/opercmds.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_serv.h ../include/s_user.h ../include/send.h \
+ ../include/userload.h
+m_time.o: m_time.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h
+m_topic.o: m_topic.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/send.h
+m_trace.o: m_trace.c ../include/class.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../config/config.h \
+ ../config/setup.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_user.h \
+ ../include/send.h ../include/version.h
+m_user.o: m_user.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h
+m_userhost.o: m_userhost.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/ircd_chattr.h ../include/numeric.h \
+ ../include/s_user.h ../include/struct.h
+m_userip.o: m_userip.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/ircd_chattr.h ../include/numeric.h \
+ ../include/s_user.h ../include/struct.h
+m_version.o: m_version.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_debug.h ../include/s_user.h \
+ ../include/send.h ../include/version.h
+m_wallchops.o: m_wallchops.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/msg.h \
+ ../include/numeric.h ../include/numnicks.h ../include/s_user.h \
+ ../include/send.h
+m_wallops.o: m_wallops.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../config/config.h \
+ ../config/setup.h ../include/ircd_chattr.h ../include/numeric.h \
+ ../include/send.h
+m_who.o: m_who.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_chattr.h \
+ ../include/ircd_log.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/match.h ../include/numeric.h \
+ ../include/numnicks.h ../include/send.h ../include/support.h \
+ ../include/whocmds.h
+m_whois.o: m_whois.c ../include/channel.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_user.h ../include/send.h ../include/whocmds.h
+m_whowas.o: m_whowas.c ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/s_user.h ../include/s_misc.h \
+ ../include/send.h ../include/whowas.h
+map.o: map.c ../include/map.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/list.h ../include/match.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/send.h
+match.o: match.c ../include/match.h ../include/ircd_chattr.h
+numnicks.o: numnicks.c ../include/numnicks.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h
+opercmds.o: opercmds.c ../include/opercmds.h ../include/class.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_defs.h \
+ ../include/ircd_handler.h ../include/crule.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_chattr.h ../include/ircd_reply.h \
+ ../include/ircd_string.h ../include/listener.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/s_conf.h ../include/send.h
+packet.o: packet.c ../include/packet.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/parse.h \
+ ../include/s_bsd.h ../include/s_misc.h ../include/send.h
+parse.o: parse.c ../include/parse.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/channel.h ../config/config.h ../config/setup.h \
+ ../include/handlers.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_string.h ../include/map.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/opercmds.h ../include/querycmds.h ../include/res.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_numeric.h ../include/s_user.h \
+ ../include/send.h ../include/sys.h ../include/whocmds.h \
+ ../include/whowas.h
+querycmds.o: querycmds.c ../include/querycmds.h
+random.o: random.c ../include/random.h ../config/config.h \
+ ../config/setup.h
+res.o: res.c ../include/res.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/ircd.h \
+ ../config/config.h ../config/setup.h ../include/struct.h \
+ ../include/ircd_alloc.h ../include/fda.h ../include/ircd_log.h \
+ ../include/ircd_osdep.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/numeric.h ../include/s_bsd.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/support.h ../include/sys.h
+s_auth.o: s_auth.c ../include/s_auth.h ../config/config.h \
+ ../config/setup.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/IPcheck.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_chattr.h ../include/ircd_log.h \
+ ../include/ircd_osdep.h ../include/ircd_string.h ../include/list.h \
+ ../include/numeric.h ../include/res.h ../include/s_bsd.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/sys.h
+s_bsd.o: s_bsd.c ../include/s_bsd.h ../config/config.h \
+ ../config/setup.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/IPcheck.h \
+ ../include/channel.h ../include/class.h ../include/hash.h \
+ ../include/ircd_log.h ../include/ircd_osdep.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/ircd.h \
+ ../include/struct.h ../include/list.h ../include/listener.h \
+ ../include/numeric.h ../include/numnicks.h ../include/packet.h \
+ ../include/parse.h ../include/querycmds.h ../include/res.h \
+ ../include/s_auth.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/support.h ../include/sys.h \
+ ../include/version.h
+s_conf.o: s_conf.c ../include/s_conf.h ../include/IPcheck.h \
+ ../include/class.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_defs.h ../include/ircd_handler.h ../include/crule.h \
+ ../include/fileio.h ../include/gline.h ../config/config.h \
+ ../config/setup.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_log.h \
+ ../include/ircd_string.h ../include/list.h ../include/listener.h \
+ ../include/match.h ../include/numeric.h ../include/numnicks.h \
+ ../include/opercmds.h ../include/parse.h ../include/res.h \
+ ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/send.h ../include/sprintf_irc.h ../include/support.h \
+ ../include/sys.h
+s_debug.o: s_debug.c ../include/s_debug.h ../config/config.h \
+ ../config/setup.h ../include/ircd_defs.h ../include/channel.h \
+ ../include/class.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_osdep.h ../include/ircd.h \
+ ../include/struct.h ../include/list.h ../include/numeric.h \
+ ../include/numnicks.h ../include/res.h ../include/s_bsd.h \
+ ../include/s_conf.h ../include/send.h ../include/sys.h \
+ ../include/whowas.h
+s_err.o: s_err.c ../include/numeric.h ../include/s_debug.h \
+ ../config/config.h ../config/setup.h ../include/ircd_defs.h \
  ../include/sprintf_irc.h
-support.o: support.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/send.h ../include/ircd.h \
- ../include/s_bsd.h ../include/s_conf.h ../include/list.h \
- ../include/support.h ../include/sprintf_irc.h ../include/common.h
-userload.o: userload.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/send.h ../include/s_misc.h \
- ../include/userload.h ../include/ircd.h ../include/numnicks.h \
- ../include/s_serv.h ../include/querycmds.h
-whocmds.o: whocmds.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h ../include/h.h \
- ../include/s_debug.h ../include/struct.h ../include/dbuf.h \
- ../include/whowas.h ../include/common.h ../include/s_serv.h \
- ../include/numeric.h ../include/send.h ../include/s_conf.h \
- ../include/list.h ../include/s_misc.h ../include/match.h \
- ../include/hash.h ../include/s_bsd.h ../include/s_err.h \
- ../include/parse.h ../include/ircd.h ../include/s_user.h \
- ../include/support.h ../include/channel.h ../include/random.h \
- ../include/version.h ../include/msg.h ../include/userload.h \
- ../include/numnicks.h ../include/sprintf_irc.h ../include/querycmds.h \
- ../include/IPcheck.h
-whowas.o: whowas.c ../include/sys.h ../include/../config/config.h \
- ../include/../config/setup.h ../include/runmalloc.h \
- ../include/common.h ../include/h.h ../include/s_debug.h \
- ../include/struct.h ../include/dbuf.h ../include/whowas.h \
- ../include/numeric.h ../include/send.h ../include/s_misc.h \
- ../include/s_err.h ../include/ircd.h ../include/list.h \
- ../include/s_user.h ../include/support.h
+s_misc.o: s_misc.c ../include/s_misc.h ../include/IPcheck.h \
+ ../include/channel.h ../config/config.h ../config/setup.h \
+ ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/list.h ../include/match.h \
+ ../include/msg.h ../include/numeric.h ../include/numnicks.h \
+ ../include/parse.h ../include/querycmds.h ../include/res.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_user.h ../include/send.h ../include/sprintf_irc.h \
+ ../include/support.h ../include/sys.h ../include/userload.h
+s_numeric.o: s_numeric.c ../include/s_numeric.h ../include/channel.h \
+ ../config/config.h ../config/setup.h ../include/ircd_defs.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_handler.h \
+ ../include/hash.h ../include/ircd.h ../include/struct.h \
+ ../include/numnicks.h ../include/send.h
+s_serv.o: s_serv.c ../include/s_serv.h ../include/IPcheck.h \
+ ../include/channel.h ../config/config.h ../config/setup.h \
+ ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_handler.h ../include/crule.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_reply.h ../include/ircd_string.h \
+ ../include/ircd_chattr.h ../include/ircd_xopen.h ../include/list.h \
+ ../include/msg.h ../include/match.h ../include/numeric.h \
+ ../include/numnicks.h ../include/parse.h ../include/querycmds.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/sys.h ../include/userload.h
+s_user.o: s_user.c ../include/s_user.h ../include/IPcheck.h \
+ ../include/channel.h ../config/config.h ../config/setup.h \
+ ../include/ircd_defs.h ../include/class.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_handler.h ../include/hash.h \
+ ../include/ircd.h ../include/struct.h ../include/ircd_alloc.h \
+ ../include/fda.h ../include/ircd_chattr.h ../include/ircd_log.h \
+ ../include/ircd_reply.h ../include/ircd_string.h ../include/list.h \
+ ../include/match.h ../include/msg.h ../include/numeric.h \
+ ../include/numnicks.h ../include/parse.h ../include/querycmds.h \
+ ../include/random.h ../include/s_bsd.h ../include/s_conf.h \
+ ../include/s_debug.h ../include/s_misc.h ../include/s_serv.h \
+ ../include/send.h ../include/sprintf_irc.h ../include/support.h \
+ ../include/supported.h ../include/sys.h ../include/userload.h \
+ ../include/version.h ../include/whowas.h
+send.o: send.c ../include/send.h ../include/channel.h \
+ ../config/config.h ../config/setup.h ../include/ircd_defs.h \
+ ../include/class.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_handler.h ../include/ircd.h ../include/struct.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/list.h \
+ ../include/match.h ../include/msg.h ../include/numnicks.h \
+ ../include/s_bsd.h ../include/s_debug.h ../include/s_misc.h \
+ ../include/s_user.h ../include/sprintf_irc.h ../include/sys.h
+sprintf_irc.o: sprintf_irc.c ../include/sprintf_irc.h ../include/sys.h \
+ ../config/config.h ../config/setup.h
+support.o: support.c ../include/support.h ../config/config.h \
+ ../config/setup.h ../include/fileio.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_defs.h ../include/ircd_chattr.h \
+ ../include/s_bsd.h ../include/s_debug.h ../include/send.h \
+ ../include/sprintf_irc.h ../include/sys.h
+uping.o: uping.c ../include/uping.h ../include/ircd_defs.h \
+ ../include/client.h ../include/dbuf.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_log.h ../include/ircd_osdep.h \
+ ../include/ircd_string.h ../include/ircd_chattr.h ../include/match.h \
+ ../include/numeric.h ../include/numnicks.h ../include/res.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_debug.h \
+ ../include/s_misc.h ../include/s_user.h ../include/send.h \
+ ../include/sys.h
+userload.o: userload.c ../include/userload.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/numnicks.h ../include/querycmds.h \
+ ../include/s_misc.h ../include/send.h ../include/sys.h
+whocmds.o: whocmds.c ../include/whocmds.h ../config/config.h \
+ ../config/setup.h ../include/IPcheck.h ../include/channel.h \
+ ../include/ircd_defs.h ../include/client.h ../include/dbuf.h \
+ ../include/ircd_handler.h ../include/hash.h ../include/ircd.h \
+ ../include/struct.h ../include/ircd_chattr.h ../include/ircd_string.h \
+ ../include/list.h ../include/match.h ../include/numeric.h \
+ ../include/numnicks.h ../include/querycmds.h ../include/random.h \
+ ../include/s_bsd.h ../include/s_conf.h ../include/s_misc.h \
+ ../include/s_user.h ../include/send.h ../include/sprintf_irc.h \
+ ../include/support.h ../include/sys.h ../include/userload.h \
+ ../include/version.h ../include/whowas.h ../include/msg.h
+whowas.o: whowas.c ../include/whowas.h ../include/client.h \
+ ../include/dbuf.h ../include/ircd_defs.h ../include/ircd_handler.h \
+ ../include/ircd.h ../config/config.h ../config/setup.h \
+ ../include/struct.h ../include/ircd_alloc.h ../include/fda.h \
+ ../include/ircd_chattr.h ../include/ircd_string.h ../include/list.h \
+ ../include/numeric.h ../include/s_misc.h ../include/s_user.h \
+ ../include/send.h ../include/support.h ../include/sys.h \
+ ../include/msg.h
diff --git a/ircd/bsd.c b/ircd/bsd.c
deleted file mode 100644 (file)
index 89467d0..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * IRC - Internet Relay Chat, common/bsd.c
- * Copyright (C) 1990 Jarkko Oikarinen and
- *                    University of Oulu, Computing Center
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "sys.h"
-#include <signal.h>
-#include <sys/socket.h>                /* Needed for send() */
-#include "h.h"
-#include "struct.h"
-#include "s_bsd.h"
-#include "ircd.h"
-#include "bsd.h"
-
-RCSTAG_CC("$Id$");
-
-#ifdef DEBUGMODE
-int writecalls = 0;
-int writeb[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-#endif
-
-RETSIGTYPE dummy(HANDLER_ARG(int UNUSED(sig)))
-{
-#ifndef HAVE_RELIABLE_SIGNALS
-  signal(SIGALRM, dummy);
-  signal(SIGPIPE, dummy);
-#ifndef HPUX                   /* Only 9k/800 series require this,
-                                  but don't know how to.. */
-#ifdef SIGWINCH
-  signal(SIGWINCH, dummy);
-#endif
-#endif
-#else
-#ifdef POSIX_SIGNALS
-  struct sigaction act;
-
-  act.sa_handler = dummy;
-  act.sa_flags = 0;
-  sigemptyset(&act.sa_mask);
-  sigaddset(&act.sa_mask, SIGALRM);
-  sigaddset(&act.sa_mask, SIGPIPE);
-#ifdef SIGWINCH
-  sigaddset(&act.sa_mask, SIGWINCH);
-#endif
-  sigaction(SIGALRM, &act, (struct sigaction *)NULL);
-  sigaction(SIGPIPE, &act, (struct sigaction *)NULL);
-#ifdef SIGWINCH
-  sigaction(SIGWINCH, &act, (struct sigaction *)NULL);
-#endif
-#endif
-#endif
-}
-
-/*
- * deliver_it
- *   Attempt to send a sequence of bytes to the connection.
- *   Returns
- *
- *   < 0     Some fatal error occurred, (but not EWOULDBLOCK).
- *           This return is a request to close the socket and
- *           clean up the link.
- *
- *   >= 0    No real error occurred, returns the number of
- *           bytes actually transferred. EWOULDBLOCK and other
- *           possibly similar conditions should be mapped to
- *           zero return. Upper level routine will have to
- *           decide what to do with those unwritten bytes...
- *
- *   *NOTE*  alarm calls have been preserved, so this should
- *           work equally well whether blocking or non-blocking
- *           mode is used...
- *
- *   We don't use blocking anymore, that is impossible with the
- *      net.loads today anyway. Commented out the alarms to save cpu.
- *      --Run
- */
-int deliver_it(aClient *cptr, const char *str, int len)
-{
-  int retval;
-  aClient *acpt = cptr->acpt;
-
-#ifdef DEBUGMODE
-  writecalls++;
-#endif
-#ifdef VMS
-  retval = netwrite(cptr->fd, str, len);
-#else
-  retval = send(cptr->fd, str, len, 0);
-  /*
-   * Convert WOULDBLOCK to a return of "0 bytes moved". This
-   * should occur only if socket was non-blocking. Note, that
-   * all is Ok, if the 'write' just returns '0' instead of an
-   * error and errno=EWOULDBLOCK.
-   *
-   * ...now, would this work on VMS too? --msa
-   */
-  if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN ||
-#ifdef SOL2
-      errno == ENOMEM || errno == ENOSR ||
-#endif
-      errno == ENOBUFS))
-  {
-    retval = 0;
-    cptr->flags |= FLAGS_BLOCKED;
-  }
-  else if (retval > 0)
-  {
-#ifdef pyr
-    gettimeofday(&cptr->lw, NULL);
-#endif
-    cptr->flags &= ~FLAGS_BLOCKED;
-  }
-
-#endif
-#ifdef DEBUGMODE
-  if (retval < 0)
-  {
-    writeb[0]++;
-    Debug((DEBUG_ERROR, "write error (%s) to %s",
-       sys_errlist[errno], cptr->name));
-  }
-  else if (retval == 0)
-    writeb[1]++;
-  else if (retval < 16)
-    writeb[2]++;
-  else if (retval < 32)
-    writeb[3]++;
-  else if (retval < 64)
-    writeb[4]++;
-  else if (retval < 128)
-    writeb[5]++;
-  else if (retval < 256)
-    writeb[6]++;
-  else if (retval < 512)
-    writeb[7]++;
-  else if (retval < 1024)
-    writeb[8]++;
-  else
-    writeb[9]++;
-#endif
-  if (retval > 0)
-  {
-    cptr->sendB += retval;
-    me.sendB += retval;
-    if (cptr->sendB > 1023)
-    {
-      cptr->sendK += (cptr->sendB >> 10);
-      cptr->sendB &= 0x03ff;   /* 2^10 = 1024, 3ff = 1023 */
-    }
-    if (acpt != &me)
-    {
-      acpt->sendB += retval;
-      if (acpt->sendB > 1023)
-      {
-       acpt->sendK += (acpt->sendB >> 10);
-       acpt->sendB &= 0x03ff;
-      }
-    }
-    else if (me.sendB > 1023)
-    {
-      me.sendK += (me.sendB >> 10);
-      me.sendB &= 0x03ff;
-    }
-  }
-  return (retval);
-}
index 91044d00c43638fcabc49e512b9fc0934d75abfe..209158f2f92e46568eb65a086cbe6e97f5671429 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdlib.h>
-#include "h.h"
-#include "struct.h"
 #include "channel.h"
-#include "parse.h"
-#include "whowas.h"
-#include "send.h"
-#include "s_err.h"
-#include "numeric.h"
+#include "client.h"
+#include "gline.h"        /* bad_channel */
+#include "hash.h"
 #include "ircd.h"
-#include "common.h"
-#include "match.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
 #include "list.h"
-#include "hash.h"
-#include "s_misc.h"
-#include "s_user.h"
-#include "s_conf.h"
-#include "s_bsd.h"
+#include "match.h"
 #include "msg.h"
-#include "common.h"
-#include "s_serv.h"
-#include "channel.h"
-#include "support.h"
+#include "numeric.h"
 #include "numnicks.h"
-#include "sprintf_irc.h"
 #include "querycmds.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sprintf_irc.h"
+#include "struct.h"
+#include "support.h"
+#include "whowas.h"
 
-RCSTAG_CC("$Id$");
-
-aChannel *channel = NullChn;
-
-static void sendmodeto_one(aClient *cptr, char *from, char *name,
-    char *mode, char *param, time_t creationtime);
-static void add_invite(aClient *, aChannel *);
-static int add_banid(aClient *, aChannel *, char *, int, int);
-static Link *next_overlapped_ban(void);
-static Link *next_removed_overlapped_ban(void);
-static int can_join(aClient *, aChannel *, char *);
-static void channel_modes(aClient *, char *, char *, aChannel *);
-static int del_banid(aChannel *, char *, int);
-static int is_banned(aClient *, aChannel *, Link *);
-static int number_of_zombies(aChannel *);
-static int is_deopped(aClient *, aChannel *);
-static int set_mode(aClient *, aClient *, aChannel *, int,
-    char **, char *, char *, char *, int *);
-static void sub1_from_channel(aChannel *);
-static void send_hack_notice(aClient *, aClient *, int, char *[], int, int);
-static void clean_channelname(char *);
-
-void del_invite(aClient *, aChannel *);
-
-static char *PartFmt1 = ":%s PART %s";
-static char *PartFmt2 = ":%s PART %s :%s";
-/*
- * some buffers for rebuilding channel/nick lists with ,'s
- */
-static char nickbuf[BUFSIZE], buf[BUFSIZE];
-static char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN];
-static char nparabuf[MODEBUFLEN];
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-/*
- * Maximum acceptable lag time in seconds: A channel younger than
- * this is not protected against hacking admins.
- * Mainly here to check if the TS clocks really sync (otherwise this
- * will start causing HACK notices.
- * This value must be the same on all servers.
- *
- * This value has been increased to 1 day in order to distinguish this
- * "normal" type of HACK wallops / desyncs, from possiblity still
- * existing bugs.
- */
-#define TS_LAG_TIME ((time_t)86400)
+struct Channel* GlobalChannelList = 0;
 
-/*
- * A Magic TS that is used for channels that are created by JOIN,
- * a channel with this TS accepts all TS without complaining that
- * it might receive later via MODE or CREATE.
- */
-#define MAGIC_REMOTE_JOIN_TS 1270080000
+static struct SLink *next_overlapped_ban(void);
+static int del_banid(struct Channel *, char *, int);
+void del_invite(struct Client *, struct Channel *);
+
+const char* const PartFmt1     = ":%s " MSG_PART " %s";
+const char* const PartFmt2     = ":%s " MSG_PART " %s :%s";
+const char* const PartFmt1serv = "%s%s " TOK_PART " %s";
+const char* const PartFmt2serv = "%s%s " TOK_PART " %s :%s";
+
+
+static struct SLink* next_ban;
+static struct SLink* prev_ban;
+static struct SLink* removed_bans_list;
 
 /*
  * Use a global variable to remember if an oper set a mode on a local channel. Ugly,
@@ -105,38 +72,78 @@ static char nparabuf[MODEBUFLEN];
  */
 int LocalChanOperMode = 0;
 
+#if !defined(NDEBUG)
 /*
  * return the length (>=0) of a chain of links.
  */
-static int list_length(Link *lp)
+static int list_length(struct SLink *lp)
 {
-  Reg2 int count = 0;
+  int count = 0;
 
   for (; lp; lp = lp->next)
-    count++;
+    ++count;
   return count;
 }
+#endif
+
+struct Membership* find_member_link(struct Channel* chptr, const struct Client* cptr)
+{
+  struct Membership *m;
+  assert(0 != cptr);
+  assert(0 != chptr);
+  
+  /* Servers don't have member links */
+  if (IsServer(cptr))
+     return 0;
+  
+  /* +k users are typically on a LOT of channels.  So we iterate over who
+   * is in the channel.  X/W are +k and are in about 5800 channels each.
+   * however there are typically no more than 1000 people in a channel
+   * at a time.
+   */
+  if (IsChannelService(cptr)) {
+    m = chptr->members;
+    while (m) {
+      assert(m->channel == chptr);
+      if (m->user == cptr)
+        return m;
+      m=m->next_member;
+    }
+  }
+  /* Users on the other hand aren't allowed on more than 15 channels.  50%
+   * of users that are on channels are on 2 or less, 95% are on 7 or less,
+   * and 99% are on 10 or less.
+   */
+  else {
+   m = cptr->user->channel;
+   while (m) {
+     assert(m->user == cptr);
+     if (m->channel == chptr)
+       return m;
+     m=m->next_channel;
+   }
+  }
+  return 0;
+}
 
 /*
- * find_chasing
- *
- * Find the client structure for a nick name (user) using history
- * mechanism if necessary. If the client is not found, an error
+ * find_chasing - Find the client structure for a nick name (user)
+ * using history mechanism if necessary. If the client is not found, an error
  * message (NO SUCH NICK) is generated. If the client was found
  * through the history, chasing will be 1 and otherwise 0.
  */
-static aClient *find_chasing(aClient *sptr, char *user, int *chasing)
+struct Client* find_chasing(struct Client* sptr, const char* user, int* chasing)
 {
-  Reg2 aClient *who = FindClient(user);
+  struct Client* who = FindClient(user);
 
   if (chasing)
     *chasing = 0;
   if (who)
     return who;
-  if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
-  {
+
+  if (!(who = get_history(user, KILLCHASETIMELIMIT))) {
     sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, user);
-    return NULL;
+    return 0;
   }
   if (chasing)
     *chasing = 1;
@@ -147,7 +154,8 @@ static aClient *find_chasing(aClient *sptr, char *user, int *chasing)
  * Create a string of form "foo!bar@fubar" given foo, bar and fubar
  * as the parameters.  If NULL, they become "*".
  */
-static char *make_nick_user_host(char *nick, char *name, char *host)
+static char *make_nick_user_host(const char *nick, const char *name,
+                                 const char *host)
 {
   static char namebuf[NICKLEN + USERLEN + HOSTLEN + 3];
   sprintf_irc(namebuf, "%s!%s@%s", nick, name, host);
@@ -161,10 +169,103 @@ static char *make_nick_user_host(char *nick, char *name, char *host)
 static char *make_nick_user_ip(char *nick, char *name, struct in_addr ip)
 {
   static char ipbuf[NICKLEN + USERLEN + 16 + 3];
-  sprintf_irc(ipbuf, "%s!%s@%s", nick, name, inetntoa(ip));
+  sprintf_irc(ipbuf, "%s!%s@%s", nick, name, ircd_ntoa((const char*) &ip));
   return ipbuf;
 }
 
+#if 0
+static int DoesOp(const char* modebuf)
+{
+  assert(0 != modebuf);
+  while (*modebuf) {
+    if (*modebuf == 'o' || *modebuf == 'v')
+      return 1;
+    ++modebuf;
+  }
+  return 0;
+}
+
+/*
+ * This function should be removed when all servers are 2.10
+ */
+static void sendmodeto_one(struct Client* cptr, const char* from,
+                           const char* name, const char* mode,
+                           const char* param, time_t creationtime)
+{
+  if (IsServer(cptr) && DoesOp(mode) && creationtime)
+    sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
+               from, name, mode, param, creationtime);
+  else
+    sendto_one(cptr, ":%s MODE %s %s %s", from, name, mode, param);
+}
+#endif /* 0 */
+
+/*
+ * Subtract one user from channel i (and free channel
+ * block, if channel became empty).
+ * Returns: true  (1) if channel still exists
+ *          false (0) if the channel was destroyed
+ */
+int sub1_from_channel(struct Channel* chptr)
+{
+  struct SLink *tmp;
+  struct SLink *obtmp;
+
+  if (chptr->users > 1)         /* Can be 0, called for an empty channel too */
+  {
+    assert(0 != chptr->members);
+    --chptr->users;
+    return 1;
+  }
+
+  assert(0 == chptr->members);
+
+  /* Channel became (or was) empty: Remove channel */
+  if (is_listed(chptr))
+  {
+    int i;
+    for (i = 0; i <= HighestFd; i++)
+    {
+      struct Client *acptr;
+      if ((acptr = LocalClientArray[i]) && acptr->listing &&
+          acptr->listing->chptr == chptr)
+      {
+        list_next_channels(acptr, 1);
+        break;                  /* Only one client can list a channel */
+      }
+    }
+  }
+  /*
+   * Now, find all invite links from channel structure
+   */
+  while ((tmp = chptr->invites))
+    del_invite(tmp->value.cptr, chptr);
+
+  tmp = chptr->banlist;
+  while (tmp)
+  {
+    obtmp = tmp;
+    tmp = tmp->next;
+    MyFree(obtmp->value.ban.banstr);
+    MyFree(obtmp->value.ban.who);
+    free_link(obtmp);
+  }
+  if (chptr->prev)
+    chptr->prev->next = chptr->next;
+  else
+    GlobalChannelList = chptr->next;
+  if (chptr->next)
+    chptr->next->prev = chptr->prev;
+  hRemChannel(chptr);
+  --UserStats.channels;
+  /*
+   * make sure that channel actually got removed from hash table
+   */
+  assert(chptr->hnext == chptr);
+  MyFree(chptr);
+  return 0;
+}
+
 /*
  * add_banid
  *
@@ -186,19 +287,20 @@ static char *make_nick_user_ip(char *nick, char *name, struct in_addr ip)
  *
  * --Run
  */
-static Link *next_ban, *prev_ban, *removed_bans_list;
-
-static int add_banid(aClient *cptr, aChannel *chptr, char *banid,
-    int change, int firsttime)
+int add_banid(struct Client *cptr, struct Channel *chptr, char *banid,
+                     int change, int firsttime)
 {
-  Reg1 Link *ban, **banp;
-  Reg2 int cnt = 0, removed_bans = 0, len = strlen(banid);
+  struct SLink*  ban;
+  struct SLink** banp;
+  int            cnt = 0;
+  int            removed_bans = 0;
+  int            len = strlen(banid);
 
   if (firsttime)
   {
     next_ban = NULL;
-    if (prev_ban || removed_bans_list)
-      MyCoreDump;              /* Memory leak */
+    assert(0 == prev_ban);
+    assert(0 == removed_bans_list);
   }
   if (MyUser(cptr))
     collapse(banid);
@@ -210,102 +312,113 @@ static int add_banid(aClient *cptr, aChannel *chptr, char *banid,
     {
       if (!strcmp((*banp)->value.ban.banstr, banid))
       {
-       (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
-       return -2;
+        (*banp)->flags &= ~CHFL_BURST_BAN_WIPEOUT;
+        return -2;
       }
     }
     else if (!mmatch((*banp)->value.ban.banstr, banid))
       return -1;
     if (!mmatch(banid, (*banp)->value.ban.banstr))
     {
-      Link *tmp = *banp;
+      struct SLink *tmp = *banp;
       if (change)
       {
-       if (MyUser(cptr))
-       {
-         cnt--;
-         len -= strlen(tmp->value.ban.banstr);
-       }
-       *banp = tmp->next;
+        if (MyUser(cptr))
+        {
+          cnt--;
+          len -= strlen(tmp->value.ban.banstr);
+        }
+        *banp = tmp->next;
 #if 0
-       /* Silently remove overlapping bans */
-       RunFree(tmp->value.ban.banstr);
-       RunFree(tmp->value.ban.who);
-       free_link(tmp);
+        /* Silently remove overlapping bans */
+        MyFree(tmp->value.ban.banstr);
+        MyFree(tmp->value.ban.who);
+        free_link(tmp);
+        tmp = 0;
 #else
-       /* These will be sent to the user later as -b */
-       tmp->next = removed_bans_list;
-       removed_bans_list = tmp;
-       removed_bans = 1;
+        /* These will be sent to the user later as -b */
+        tmp->next = removed_bans_list;
+        removed_bans_list = tmp;
+        removed_bans = 1;
 #endif
       }
       else if (!(tmp->flags & CHFL_BURST_BAN_WIPEOUT))
       {
-       tmp->flags |= CHFL_BAN_OVERLAPPED;
-       if (!next_ban)
-         next_ban = tmp;
-       banp = &tmp->next;
+        tmp->flags |= CHFL_BAN_OVERLAPPED;
+        if (!next_ban)
+          next_ban = tmp;
+        banp = &tmp->next;
       }
       else
-       banp = &tmp->next;
+        banp = &tmp->next;
     }
     else
     {
       if (firsttime)
-       (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
+        (*banp)->flags &= ~CHFL_BAN_OVERLAPPED;
       banp = &(*banp)->next;
     }
   }
   if (MyUser(cptr) && !removed_bans && (len > MAXBANLENGTH || (cnt >= MAXBANS)))
   {
     sendto_one(cptr, err_str(ERR_BANLISTFULL), me.name, cptr->name,
-       chptr->chname, banid);
+        chptr->chname, banid);
     return -1;
   }
   if (change)
   {
-    char *ip_start;
+    char*              ip_start;
+    struct Membership* member;
     ban = make_link();
     ban->next = chptr->banlist;
-    ban->value.ban.banstr = (char *)RunMalloc(strlen(banid) + 1);
+
+    ban->value.ban.banstr = (char*) MyMalloc(strlen(banid) + 1);
+    assert(0 != ban->value.ban.banstr);
     strcpy(ban->value.ban.banstr, banid);
-    ban->value.ban.who = (char *)RunMalloc(strlen(cptr->name) + 1);
+
+    ban->value.ban.who = (char*) MyMalloc(strlen(cptr->name) + 1);
+    assert(0 != ban->value.ban.who);
     strcpy(ban->value.ban.who, cptr->name);
-    ban->value.ban.when = now;
-    ban->flags = CHFL_BAN;     /* This bit is never used I think... */
+
+    ban->value.ban.when = CurrentTime;
+    ban->flags = CHFL_BAN;      /* This bit is never used I think... */
     if ((ip_start = strrchr(banid, '@')) && check_if_ipmask(ip_start + 1))
       ban->flags |= CHFL_BAN_IPMASK;
     chptr->banlist = ban;
-    /* Erase ban-valid-bit */
-    for (ban = chptr->members; ban; ban = ban->next)
-      ban->flags &= ~CHFL_BANVALID;    /* `ban' == channel member ! */
+
+    /*
+     * Erase ban-valid-bit
+     */
+    for (member = chptr->members; member; member = member->next_member)
+      ClearBanValid(member);     /* `ban' == channel member ! */
   }
   return 0;
 }
 
-static Link *next_overlapped_ban(void)
+static struct SLink *next_overlapped_ban(void)
 {
-  Reg1 Link *tmp = next_ban;
+  struct SLink *tmp = next_ban;
   if (tmp)
   {
-    Reg2 Link *ban;
+    struct SLink *ban;
     for (ban = tmp->next; ban; ban = ban->next)
       if ((ban->flags & CHFL_BAN_OVERLAPPED))
-       break;
+        break;
     next_ban = ban;
   }
   return tmp;
 }
 
-static Link *next_removed_overlapped_ban(void)
+struct SLink *next_removed_overlapped_ban(void)
 {
-  Reg1 Link *tmp = removed_bans_list;
+  struct SLink *tmp = removed_bans_list;
   if (prev_ban)
   {
-    if (prev_ban->value.ban.banstr)    /* Can be set to NULL in set_mode() */
-      RunFree(prev_ban->value.ban.banstr);
-    RunFree(prev_ban->value.ban.who);
+    if (prev_ban->value.ban.banstr)     /* Can be set to NULL in set_mode() */
+      MyFree(prev_ban->value.ban.banstr);
+    MyFree(prev_ban->value.ban.who);
     free_link(prev_ban);
+    prev_ban = 0;
   }
   if (tmp)
     removed_bans_list = removed_bans_list->next;
@@ -319,87 +432,86 @@ static Link *next_removed_overlapped_ban(void)
  * If `change' is true, delete `banid' from channel `chptr'.
  * Returns `false' if removal was (or would have been) successful.
  */
-static int del_banid(aChannel *chptr, char *banid, int change)
+static int del_banid(struct Channel *chptr, char *banid, int change)
 {
-  Reg1 Link **ban;
-  Reg2 Link *tmp;
+  struct SLink **ban;
+  struct SLink *tmp;
 
   if (!banid)
     return -1;
-  for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
-    if (strCasediff(banid, (*ban)->value.ban.banstr) == 0)
+  for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next)) {
+    if (0 == ircd_strcmp(banid, (*ban)->value.ban.banstr))
     {
       tmp = *ban;
       if (change)
       {
-       *ban = tmp->next;
-       RunFree(tmp->value.ban.banstr);
-       RunFree(tmp->value.ban.who);
-       free_link(tmp);
-       /* Erase ban-valid-bit, for channel members that are banned */
-       for (tmp = chptr->members; tmp; tmp = tmp->next)
-         if ((tmp->flags & (CHFL_BANNED | CHFL_BANVALID)) ==
-             (CHFL_BANNED | CHFL_BANVALID))
-           tmp->flags &= ~CHFL_BANVALID;       /* `tmp' == channel member */
+        struct Membership* member;
+        *ban = tmp->next;
+        MyFree(tmp->value.ban.banstr);
+        MyFree(tmp->value.ban.who);
+        free_link(tmp);
+        /*
+         * Erase ban-valid-bit, for channel members that are banned
+         */
+        for (member = chptr->members; member; member = member->next_member)
+          if (CHFL_BANVALIDMASK == (member->status & CHFL_BANVALIDMASK))
+            ClearBanValid(member);       /* `tmp' == channel member */
       }
       return 0;
     }
+  }
   return -1;
 }
 
 /*
- * IsMember - returns Link * if a person is joined and not a zombie
+ * find_channel_member - returns Membership * if a person is joined and not a zombie
  */
-Link *IsMember(aClient *cptr, aChannel *chptr)
+struct Membership* find_channel_member(struct Client* cptr, struct Channel* chptr)
 {
-  Link *lp;
-  return (((lp = find_user_link(chptr->members, cptr)) &&
-      !(lp->flags & CHFL_ZOMBIE)) ? lp : NULL);
+  struct Membership* member;
+  assert(0 != chptr);
+
+  member = find_member_link(chptr, cptr);
+  return (member && !IsZombie(member)) ? member : 0;
 }
 
 /*
  * is_banned - a non-zero value if banned else 0.
  */
-static int is_banned(aClient *cptr, aChannel *chptr, Link *member)
+static int is_banned(struct Client *cptr, struct Channel *chptr,
+                     struct Membership* member)
 {
-  Reg1 Link *tmp;
-  char *s, *ip_s = NULL;
+  struct SLink* tmp;
+  char*         s;
+  char*         ip_s = NULL;
 
   if (!IsUser(cptr))
     return 0;
 
-  if (member)
-  {
-    if ((member->flags & CHFL_BANVALID))
-      return (member->flags & CHFL_BANNED);
-  }
+  if (member && IsBanValid(member))
+    return IsBanned(member);
 
   s = make_nick_user_host(cptr->name, cptr->user->username, cptr->user->host);
 
-  for (tmp = chptr->banlist; tmp; tmp = tmp->next)
-  {
-    if ((tmp->flags & CHFL_BAN_IPMASK))
-    {
+  for (tmp = chptr->banlist; tmp; tmp = tmp->next) {
+    if ((tmp->flags & CHFL_BAN_IPMASK)) {
       if (!ip_s)
-       ip_s = make_nick_user_ip(cptr->name, cptr->user->username, cptr->ip);
+        ip_s = make_nick_user_ip(cptr->name, cptr->user->username, cptr->ip);
       if (match(tmp->value.ban.banstr, ip_s) == 0)
-       break;
+        break;
     }
     else if (match(tmp->value.ban.banstr, s) == 0)
       break;
   }
 
-  if (member)
-  {
-    member->flags |= CHFL_BANVALID;
-    if (tmp)
-    {
-      member->flags |= CHFL_BANNED;
+  if (member) {
+    SetBanValid(member);
+    if (tmp) {
+      SetBanned(member);
       return 1;
     }
-    else
-    {
-      member->flags &= ~CHFL_BANNED;
+    else {
+      ClearBanned(member);
       return 0;
     }
   }
@@ -411,138 +523,229 @@ static int is_banned(aClient *cptr, aChannel *chptr, Link *member)
  * adds a user to a channel by adding another link to the channels member
  * chain.
  */
-static void add_user_to_channel(aChannel *chptr, aClient *who, int flags)
+void add_user_to_channel(struct Channel* chptr, struct Client* who,
+                                unsigned int flags)
 {
-  Reg1 Link *ptr;
+  assert(0 != chptr);
+  assert(0 != who);
+
+  if (who->user) {
+    struct Membership* member = 
+            (struct Membership*) MyMalloc(sizeof(struct Membership));
+    assert(0 != member);
+    member->user         = who;
+    member->channel      = chptr;
+    member->status       = flags;
+
+    member->next_member  = chptr->members;
+    if (member->next_member)
+      member->next_member->prev_member = member;
+    member->prev_member  = 0; 
+    chptr->members       = member;
+
+    member->next_channel = who->user->channel;
+    if (member->next_channel)
+      member->next_channel->prev_channel = member;
+    member->prev_channel = 0;
+    who->user->channel = member;
+
+    ++chptr->users;
+    ++who->user->joined;
+  }
+}
 
-  if (who->user)
-  {
-    ptr = make_link();
-    ptr->value.cptr = who;
-    ptr->flags = flags;
-    ptr->next = chptr->members;
-    chptr->members = ptr;
-    chptr->users++;
-
-    ptr = make_link();
-    ptr->value.chptr = chptr;
-    ptr->next = who->user->channel;
-    who->user->channel = ptr;
-    who->user->joined++;
+static int remove_member_from_channel(struct Membership* member)
+{
+  struct Channel* chptr;
+  assert(0 != member);
+  chptr = member->channel;
+  /*
+   * unlink channel member list
+   */
+  if (member->next_member)
+    member->next_member->prev_member = member->prev_member;
+  if (member->prev_member)
+    member->prev_member->next_member = member->next_member;
+  else
+    member->channel->members = member->next_member; 
+      
+  /*
+   * unlink client channel list
+   */
+  if (member->next_channel)
+    member->next_channel->prev_channel = member->prev_channel;
+  if (member->prev_channel)
+    member->prev_channel->next_channel = member->next_channel;
+  else
+    member->user->user->channel = member->next_channel;
+
+  --member->user->user->joined;
+  MyFree(member);
+
+  return sub1_from_channel(chptr);
+}
+
+static int channel_all_zombies(struct Channel* chptr)
+{
+  struct Membership* member;
+
+  for (member = chptr->members; member; member = member->next_member) {
+    if (!IsZombie(member))
+      return 0;
   }
+  return 1;
 }
+      
 
-void remove_user_from_channel(aClient *sptr, aChannel *chptr)
+void remove_user_from_channel(struct Client* cptr, struct Channel* chptr)
 {
-  Reg1 Link **curr;
-  Reg2 Link *tmp;
-  Reg3 Link *lp = chptr->members;
+  
+  struct Membership* member;
+  assert(0 != chptr);
 
-  for (; lp && (lp->flags & CHFL_ZOMBIE || lp->value.cptr == sptr);
-      lp = lp->next);
-  for (;;)
-  {
-    for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
-      if (tmp->value.cptr == sptr)
-      {
-       *curr = tmp->next;
-       free_link(tmp);
-       break;
-      }
-    for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next)
-      if (tmp->value.chptr == chptr)
-      {
-       *curr = tmp->next;
-       free_link(tmp);
-       break;
+  if ((member = find_member_link(chptr, cptr))) {
+    if (remove_member_from_channel(member)) {
+      if (channel_all_zombies(chptr)) {
+        /*
+         * XXX - this looks dangerous but isn't if we got the referential
+         * integrity right for channels
+         */
+        while (remove_member_from_channel(chptr->members))
+          ;
       }
-    sptr->user->joined--;
-    if (lp)
-      break;
-    if (chptr->members)
-      sptr = chptr->members->value.cptr;
-    else
-      break;
-    sub1_from_channel(chptr);
+    }
   }
-  sub1_from_channel(chptr);
 }
 
-int is_chan_op(aClient *cptr, aChannel *chptr)
+void remove_user_from_all_channels(struct Client* cptr)
 {
-  Reg1 Link *lp;
+  struct Membership* chan;
+  assert(0 != cptr);
+  assert(0 != cptr->user);
 
-  if (chptr)
-    if ((lp = find_user_link(chptr->members, cptr)) &&
-       !(lp->flags & CHFL_ZOMBIE))
-      return (lp->flags & CHFL_CHANOP);
+  while ((chan = cptr->user->channel))
+    remove_user_from_channel(cptr, chan->channel);
+}
+
+int is_chan_op(struct Client *cptr, struct Channel *chptr)
+{
+  struct Membership* member;
+  assert(chptr);
+  if ((member = find_member_link(chptr, cptr)))
+    return (!IsZombie(member) && IsChanOp(member));
 
   return 0;
 }
 
-static int is_deopped(aClient *cptr, aChannel *chptr)
+static int is_deopped(struct Client *cptr, struct Channel *chptr)
 {
-  Reg1 Link *lp;
+  struct Membership* member;
 
-  if (chptr)
-    if ((lp = find_user_link(chptr->members, cptr)))
-      return (lp->flags & CHFL_DEOPPED);
+  assert(0 != chptr);
+  if ((member = find_member_link(chptr, cptr)))
+    return IsDeopped(member);
 
   return (IsUser(cptr) ? 1 : 0);
 }
 
-int is_zombie(aClient *cptr, aChannel *chptr)
+int is_zombie(struct Client *cptr, struct Channel *chptr)
 {
-  Reg1 Link *lp;
+  struct Membership* member;
 
-  if (chptr)
-    if ((lp = find_user_link(chptr->members, cptr)))
-      return (lp->flags & CHFL_ZOMBIE);
+  assert(0 != chptr);
 
+  if ((member = find_member_link(chptr, cptr)))
+      return IsZombie(member);
   return 0;
 }
 
-int has_voice(aClient *cptr, aChannel *chptr)
+int has_voice(struct Client* cptr, struct Channel* chptr)
 {
-  Reg1 Link *lp;
+  struct Membership* member;
 
-  if (chptr)
-    if ((lp = find_user_link(chptr->members, cptr)) &&
-       !(lp->flags & CHFL_ZOMBIE))
-      return (lp->flags & CHFL_VOICE);
+  assert(0 != chptr);
+  if ((member = find_member_link(chptr, cptr)))
+    return (!IsZombie(member) && HasVoice(member));
 
   return 0;
 }
 
-int can_send(aClient *cptr, aChannel *chptr)
+int member_can_send_to_channel(struct Membership* member)
 {
-  Reg1 Link *lp;
+  assert(0 != member);
 
-  lp = IsMember(cptr, chptr);
+  if (IsVoicedOrOpped(member))
+    return 1;
+  /*
+   * If it's moderated, and you aren't a priviledged user, you can't
+   * speak.  
+   */
+  if (member->channel->mode.mode & MODE_MODERATED)
+    return 0;
+  /*
+   * If you're banned then you can't speak either.
+   * but because of the amount of CPU time that is_banned chews
+   * we only check it for our clients.
+   */
+  if (MyUser(member->user) && is_banned(member->user, member->channel, member))
+    return 0;
+  return 1;
+}
 
-  if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
-      (lp->flags & CHFL_ZOMBIE)) && MyUser(cptr) && is_banned(cptr, chptr, lp))
-    return (MODE_BAN);
+int client_can_send_to_channel(struct Client *cptr, struct Channel *chptr)
+{
+  struct Membership *member;
+  assert(0 != cptr); 
+  /*
+   * Servers can always speak on channels.
+   */
+  if (IsServer(cptr))
+    return 1;
 
-  if (chptr->mode.mode & MODE_MODERATED &&
-      (!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
-      (lp->flags & CHFL_ZOMBIE)))
-    return (MODE_MODERATED);
+  member = find_channel_member(cptr, chptr);
 
-  if (!lp && ((chptr->mode.mode & MODE_NOPRIVMSGS) ||
-      IsModelessChannel(chptr->chname)))
-    return (MODE_NOPRIVMSGS);
+  /*
+   * You can't speak if your off channel, if the channel is modeless, or
+   * +n.(no external messages)
+   */
+  if (!member) {
+    if ((chptr->mode.mode & MODE_NOPRIVMSGS) || IsModelessChannel(chptr->chname)) 
+      return 0;
+    else
+      return 1;
+  }
+  return member_can_send_to_channel(member); 
+}
 
+/*
+ * find_no_nickchange_channel
+ * if a member and not opped or voiced and banned
+ * return the name of the first channel banned on
+ */
+const char* find_no_nickchange_channel(struct Client* cptr)
+{
+  if (MyUser(cptr)) {
+    struct Membership* member;
+    for (member = cptr->user->channel; member; member = member->next_channel) {
+      if (!IsVoicedOrOpped(member) && is_banned(cptr, member->channel, member))
+        return member->channel->chname;
+    }
+  }
   return 0;
 }
 
+
 /*
  * write the "simple" list of channel modes for channel chptr onto buffer mbuf
  * with the parameters in pbuf.
  */
-static void channel_modes(aClient *cptr, char *mbuf, char *pbuf,
-    aChannel *chptr)
+void channel_modes(struct Client *cptr, char *mbuf, char *pbuf,
+                          struct Channel *chptr)
 {
+  assert(0 != mbuf);
+  assert(0 != pbuf);
+  assert(0 != chptr);
+
   *mbuf++ = '+';
   if (chptr->mode.mode & MODE_SECRET)
     *mbuf++ = 's';
@@ -556,34 +759,36 @@ static void channel_modes(aClient *cptr, char *mbuf, char *pbuf,
     *mbuf++ = 'i';
   if (chptr->mode.mode & MODE_NOPRIVMSGS)
     *mbuf++ = 'n';
-  if (chptr->mode.limit)
-  {
+  if (chptr->mode.limit) {
     *mbuf++ = 'l';
     sprintf_irc(pbuf, "%d", chptr->mode.limit);
   }
-  if (*chptr->mode.key)
-  {
+
+  if (*chptr->mode.key) {
     *mbuf++ = 'k';
-    if (is_chan_op(cptr, chptr) || IsServer(cptr))
-    {
+    if (is_chan_op(cptr, chptr) || IsServer(cptr)) {
       if (chptr->mode.limit)
-       strcat(pbuf, " ");
+        strcat(pbuf, " ");
       strcat(pbuf, chptr->mode.key);
     }
   }
   *mbuf = '\0';
-  return;
 }
 
-static int send_mode_list(aClient *cptr, char *chname, time_t creationtime,
-    Link *top, int mask, char flag)
+#if 0
+static int send_mode_list(struct Client *cptr, char *chname,
+                          time_t creationtime, struct SLink *top,
+                          int mask, char flag)
 {
-  Reg1 Link *lp;
-  Reg2 char *cp, *name;
-  int count = 0, send = 0, sent = 0;
+  struct SLink* lp;
+  char*         cp;
+  char*         name;
+  int           count = 0;
+  int           send = 0;
+  int           sent = 0;
 
   cp = modebuf + strlen(modebuf);
-  if (*parabuf)                        /* mode +l or +k xx */
+  if (*parabuf)                 /* mode +l or +k xx */
     count = 1;
   for (lp = top; lp; lp = lp->next)
   {
@@ -616,8 +821,8 @@ static int send_mode_list(aClient *cptr, char *chname, time_t creationtime,
       *cp++ = '+';
       if (count != 6)
       {
-       strcpy(parabuf, name);
-       *cp++ = flag;
+        strcpy(parabuf, name);
+        *cp++ = flag;
       }
       count = 0;
       *cp = '\0';
@@ -626,312 +831,171 @@ static int send_mode_list(aClient *cptr, char *chname, time_t creationtime,
   return sent;
 }
 
+#endif /* 0 */
+
 /*
  * send "cptr" a full list of the modes for channel chptr.
  */
-void send_channel_modes(aClient *cptr, aChannel *chptr)
+void send_channel_modes(struct Client *cptr, struct Channel *chptr)
 {
-  int sent;
+  static unsigned int current_flags[4] =
+      { 0, CHFL_CHANOP | CHFL_VOICE, CHFL_VOICE, CHFL_CHANOP };
+  int                first = 1;
+  int                full  = 1;
+  int                flag_cnt = 0;
+  int                new_mode = 0;
+  size_t             len;
+  size_t             sblen;
+  struct Membership* member;
+  struct SLink*      lp2;
+  char modebuf[MODEBUFLEN];
+  char parabuf[MODEBUFLEN];
+
+  assert(0 != cptr);
+  assert(0 != chptr); 
+
   if (IsLocalChannel(chptr->chname))
     return;
 
+  member = chptr->members;
+  lp2 = chptr->banlist;
+
   *modebuf = *parabuf = '\0';
   channel_modes(cptr, modebuf, parabuf, chptr);
 
-  if (Protocol(cptr) < 10)
+  for (first = 1; full; first = 0)      /* Loop for multiple messages */
   {
-    sent = send_mode_list(cptr, chptr->chname, chptr->creationtime,
-       chptr->members, CHFL_CHANOP, 'o');
-    if (!sent && chptr->creationtime)
-      sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT, me.name,
-         chptr->chname, modebuf, parabuf, chptr->creationtime);
-    else if (modebuf[1] || *parabuf)
-      sendmodeto_one(cptr, me.name,
-         chptr->chname, modebuf, parabuf, chptr->creationtime);
-
-    *parabuf = '\0';
-    *modebuf = '+';
-    modebuf[1] = '\0';
-    send_mode_list(cptr, chptr->chname, chptr->creationtime,
-       chptr->banlist, CHFL_BAN, 'b');
-    if (modebuf[1] || *parabuf)
-      sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
-         parabuf, chptr->creationtime);
-
-    *parabuf = '\0';
-    *modebuf = '+';
-    modebuf[1] = '\0';
-    send_mode_list(cptr, chptr->chname, chptr->creationtime,
-       chptr->members, CHFL_VOICE, 'v');
-    if (modebuf[1] || *parabuf)
-      sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
-         parabuf, chptr->creationtime);
-  }
-  else
-  {
-    static unsigned int current_flags[4] =
-       { 0, CHFL_CHANOP | CHFL_VOICE, CHFL_VOICE, CHFL_CHANOP };
-    int first = 1, full = 1, flag_cnt = 0, new_mode = 0;
-    size_t len, sblen;
-    Link *lp1 = chptr->members;
-    Link *lp2 = chptr->banlist;
-    for (first = 1; full; first = 0)   /* Loop for multiple messages */
-    {
-      full = 0;                        /* Assume by default we get it
-                                  all in one message */
+    full = 0;                   /* Assume by default we get it
+                                 all in one message */
 
-      /* (Continued) prefix: "<Y> BURST <channel> <TS>" */
-      sprintf_irc(sendbuf, "%s BURST %s " TIME_T_FMT, NumServ(&me),
-         chptr->chname, chptr->creationtime);
-      sblen = strlen(sendbuf);
+    /* (Continued) prefix: "<Y> B <channel> <TS>" */
+    sprintf_irc(sendbuf, "%s B %s " TIME_T_FMT, NumServ(&me),
+                chptr->chname, chptr->creationtime);
+    sblen = strlen(sendbuf);
 
-      if (first && modebuf[1]) /* Add simple modes (iklmnpst)
-                                  if first message */
+    if (first && modebuf[1])    /* Add simple modes (iklmnpst)
+                                 if first message */
+    {
+      /* prefix: "<Y> B <channel> <TS>[ <modes>[ <params>]]" */
+      sendbuf[sblen++] = ' ';
+      strcpy(sendbuf + sblen, modebuf);
+      sblen += strlen(modebuf);
+      if (*parabuf)
       {
-       /* prefix: "<Y> BURST <channel> <TS>[ <modes>[ <params>]]" */
-       sendbuf[sblen++] = ' ';
-       strcpy(sendbuf + sblen, modebuf);
-       sblen += strlen(modebuf);
-       if (*parabuf)
-       {
-         sendbuf[sblen++] = ' ';
-         strcpy(sendbuf + sblen, parabuf);
-         sblen += strlen(parabuf);
-       }
+        sendbuf[sblen++] = ' ';
+        strcpy(sendbuf + sblen, parabuf);
+        sblen += strlen(parabuf);
       }
+    }
 
-      /* Attach nicks, comma seperated " nick[:modes],nick[:modes],..." */
-      /* Run 4 times over all members, to group the members with the
-       * same mode together */
-      for (first = 1; flag_cnt < 4;
-         lp1 = chptr->members, new_mode = 1, flag_cnt++)
+    /*
+     * Attach nicks, comma seperated " nick[:modes],nick[:modes],..."
+     *
+     * Run 4 times over all members, to group the members with the
+     * same mode together
+     */
+    for (first = 1; flag_cnt < 4;
+         member = chptr->members, new_mode = 1, flag_cnt++)
+    {
+      for (; member; member = member->next_member)
       {
-       for (; lp1; lp1 = lp1->next)
-       {
-         if ((lp1->flags & (CHFL_CHANOP | CHFL_VOICE)) !=
-             current_flags[flag_cnt])
-           continue;           /* Skip members with different flags */
-         if (sblen + NUMNICKLEN + 4 > BUFSIZE - 3)
-           /* The 4 is a possible ",:ov"
-              The -3 is for the "\r\n\0" that is added in send.c */
-         {
-           full = 1;           /* Make sure we continue after
-                                  sending it so far */
-           break;              /* Do not add this member to this message */
-         }
-         sendbuf[sblen++] = first ? ' ' : ',';
-         first = 0;            /* From now on, us comma's to add new nicks */
-
-         sprintf_irc(sendbuf + sblen, "%s%s", NumNick(lp1->value.cptr));
-         sblen += strlen(sendbuf + sblen);
-
-         if (new_mode)         /* Do we have a nick with a new mode ? */
-         {
-           new_mode = 0;
-            if (lp1->flags & (CHFL_CHANOP | CHFL_VOICE)) {
-             sendbuf[sblen++] = ':';
-             if (lp1->flags & CHFL_CHANOP)
-               sendbuf[sblen++] = 'o';
-             if (lp1->flags & CHFL_VOICE)
-               sendbuf[sblen++] = 'v';
-            }
-         }
-       }
-       if (full)
-         break;
+        if ((member->status & CHFL_VOICED_OR_OPPED) !=
+            current_flags[flag_cnt])
+          continue;             /* Skip members with different flags */
+        if (sblen + NUMNICKLEN + 4 > BUFSIZE - 3)
+          /* The 4 is a possible ",:ov"
+             The -3 is for the "\r\n\0" that is added in send.c */
+        {
+          full = 1;           /* Make sure we continue after
+                                 sending it so far */
+          new_mode = 1;       /* Ensure the new BURST line contains the current
+                                 mode. --Gte */
+          break;              /* Do not add this member to this message */
+        }
+        sendbuf[sblen++] = first ? ' ' : ',';
+        first = 0;              /* From now on, us comma's to add new nicks */
+
+        sprintf_irc(sendbuf + sblen, "%s%s", NumNick(member->user));
+        sblen += strlen(sendbuf + sblen);
+        /*
+         * Do we have a nick with a new mode ?
+         * Or are we starting a new BURST line?
+         */
+        if (new_mode)
+        {
+          new_mode = 0;
+          if (IsVoicedOrOpped(member)) {
+            sendbuf[sblen++] = ':';
+            if (IsChanOp(member))
+              sendbuf[sblen++] = 'o';
+            if (HasVoice(member))
+              sendbuf[sblen++] = 'v';
+          }
+        }
       }
+      if (full)
+        break;
+    }
 
-      if (!full)
+    if (!full)
+    {
+      /* Attach all bans, space seperated " :%ban ban ..." */
+      for (first = 2; lp2; lp2 = lp2->next)
       {
-       /* Attach all bans, space seperated " :%ban ban ..." */
-       for (first = 2; lp2; lp2 = lp2->next)
-       {
-         len = strlen(lp2->value.ban.banstr);
-         if (sblen + len + 1 + first > BUFSIZE - 3)
-           /* The +1 stands for the added ' '.
-            * The +first stands for the added ":%".
-            * The -3 is for the "\r\n\0" that is added in send.c
-            */
-         {
-           full = 1;
-           break;
-         }
-         if (first)
-         {
-           first = 0;
-           sendbuf[sblen++] = ' ';
-           sendbuf[sblen++] = ':';     /* Will be last parameter */
-           sendbuf[sblen++] = '%';     /* To tell bans apart */
-         }
-         else
-           sendbuf[sblen++] = ' ';
-         strcpy(sendbuf + sblen, lp2->value.ban.banstr);
-         sblen += len;
-       }
+        len = strlen(lp2->value.ban.banstr);
+        if (sblen + len + 1 + first > BUFSIZE - 3)
+          /* The +1 stands for the added ' '.
+           * The +first stands for the added ":%".
+           * The -3 is for the "\r\n\0" that is added in send.c
+           */
+        {
+          full = 1;
+          break;
+        }
+        if (first)
+        {
+          first = 0;
+          sendbuf[sblen++] = ' ';
+          sendbuf[sblen++] = ':';       /* Will be last parameter */
+          sendbuf[sblen++] = '%';       /* To tell bans apart */
+        }
+        else
+          sendbuf[sblen++] = ' ';
+        strcpy(sendbuf + sblen, lp2->value.ban.banstr);
+        sblen += len;
       }
+    }
 
-      sendbuf[sblen] = '\0';
-      sendbufto_one(cptr);     /* Send this message */
-    }                          /* Continue when there was something
-                                  that didn't fit (full==1) */
-  }
+    sendbuf[sblen] = '\0';
+    sendbufto_one(cptr);        /* Send this message */
+  }                             /* Continue when there was something
+                                 that didn't fit (full==1) */
 }
 
 /*
- * m_mode
- * parv[0] - sender
- * parv[1] - channel
+ * pretty_mask
+ *
+ * by Carlo Wood (Run), 05 Oct 1998.
+ *
+ * Canonify a mask.
+ *
+ * When the nick is longer then NICKLEN, it is cut off (its an error of course).
+ * When the user name or host name are too long (USERLEN and HOSTLEN
+ * respectively) then they are cut off at the start with a '*'.
+ *
+ * The following transformations are made:
+ *
+ * 1)   xxx             -> nick!*@*
+ * 2)   xxx.xxx         -> *!*@host
+ * 3)   xxx!yyy         -> nick!user@*
+ * 4)   xxx@yyy         -> *!user@host
+ * 5)   xxx!yyy@zzz     -> nick!user@host
  */
-
-int m_mode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+char *pretty_mask(char *mask)
 {
-  int badop, sendts;
-  aChannel *chptr;
-
-  /* Now, try to find the channel in question */
-  if (parc > 1)
-  {
-    chptr = FindChannel(parv[1]);
-    if (chptr == NullChn)
-      return m_umode(cptr, sptr, parc, parv);
-  }
-  else
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE");
-    return 0;
-  }
-
-  sptr->flags &= ~FLAGS_TS8;
-
-  if (MyUser(sptr))
-    clean_channelname(parv[1]);
-  else if (IsLocalChannel(parv[1]))
-    return 0;
-
-  /* sending an error wasnt good, lets just send an empty mode reply..  poptix */
-  if (IsModelessChannel(chptr->chname))
-  {
-    if (IsUser(sptr))
-      sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
-         chptr->chname, "+nt", "");
-    return 0;
-  }
-
-  if (parc < 3)
-  {
-    *modebuf = *parabuf = '\0';
-    modebuf[1] = '\0';
-    channel_modes(sptr, modebuf, parabuf, chptr);
-    sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
-       chptr->chname, modebuf, parabuf);
-    sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
-       chptr->chname, chptr->creationtime);
-    return 0;
-  }
-
-  LocalChanOperMode = 0;
-
-  if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
-      modebuf, parabuf, nparabuf, &badop)))
-  {
-    sendto_one(sptr, err_str(IsMember(sptr, chptr) ? ERR_CHANOPRIVSNEEDED :
-       ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
-    return 0;
-  }
-
-  if (badop >= 2)
-    send_hack_notice(cptr, sptr, parc, parv, badop, 1);
-
-  if (strlen(modebuf) > (size_t)1 || sendts > 0)
-  {
-    if (badop != 2 && strlen(modebuf) > (size_t)1)
-    {
-#ifdef OPER_MODE_LCHAN
-      if (LocalChanOperMode) {
-         sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s",
-                                me.name, chptr->chname, modebuf, parabuf);
-         sendto_op_mask(SNO_HACK4, 
-                        "OPER MODE: %s MODE %s %s %s",
-                        sptr->name,chptr->chname,modebuf,parabuf);
-       }
-       else
-#endif
-      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
-         parv[0], chptr->chname, modebuf, parabuf);
-    }
-    if (IsLocalChannel(chptr->chname))
-      return 0;
-    /* We send a creationtime of 0, to mark it as a hack --Run */
-    if (IsServer(sptr) && (badop == 2 || sendts > 0))
-    {
-      if (*modebuf == '\0')
-       strcpy(modebuf, "+");
-      if (badop != 2)
-      {
-       sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s %s " TIME_T_FMT,
-           parv[0], chptr->chname, modebuf, parabuf,
-           (badop == 4) ? (time_t) 0 : chptr->creationtime);
-       sendto_highprot_butone(cptr, 10, ":%s MODE %s %s %s " TIME_T_FMT,
-           parv[0], chptr->chname, modebuf, nparabuf,
-           (badop == 4) ? (time_t) 0 : chptr->creationtime);
-      }
-    }
-    else
-    {
-      sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s %s",
-         parv[0], chptr->chname, modebuf, parabuf);
-      sendto_highprot_butone(cptr, 10, ":%s MODE %s %s %s",
-         parv[0], chptr->chname, modebuf, nparabuf);
-    }
-  }
-  return 0;
-}
-
-static int DoesOp(char *modebuf)
-{
-  modebuf--;                   /* Is it possible that a mode
-                                  starts with o and not +o ? */
-  while (*++modebuf)
-    if (*modebuf == 'o' || *modebuf == 'v')
-      return (1);
-  return 0;
-}
-
-/* This function should be removed when all servers are 2.10 */
-static void sendmodeto_one(aClient *cptr, char *from, char *name,
-    char *mode, char *param, time_t creationtime)
-{
-  if (IsServer(cptr) && DoesOp(mode) && creationtime)
-    sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
-       from, name, mode, param, creationtime);
-  else
-    sendto_one(cptr, ":%s MODE %s %s %s", from, name, mode, param);
-}
-
-/*
- * pretty_mask
- *
- * by Carlo Wood (Run), 05 Oct 1998.
- *
- * Canonify a mask.
- *
- * When the nick is longer then NICKLEN, it is cut off (its an error of course).
- * When the user name or host name are too long (USERLEN and HOSTLEN
- * respectively) then they are cut off at the start with a '*'.
- *
- * The following transformations are made:
- *
- * 1)   xxx             -> nick!*@*
- * 2)   xxx.xxx         -> *!*@host
- * 3)   xxx!yyy         -> nick!user@*
- * 4)   xxx@yyy         -> *!user@host
- * 5)   xxx!yyy@zzz     -> nick!user@host
- */
-char *pretty_mask(char *mask)
-{
-  static char star[2] = { '*', 0 };
-  char *last_dot = NULL;
-  char *ptr;
+  static char star[2] = { '*', 0 };
+  char *last_dot = NULL;
+  char *ptr;
 
   /* Case 1: default */
   char *nick = mask;
@@ -966,8 +1030,8 @@ char *pretty_mask(char *mask)
     {
       if (*ptr == '@')
       {
-       /* Case 4 or 5: Found last '@' */
-       host = ptr + 1;
+        /* Case 4 or 5: Found last '@' */
+        host = ptr + 1;
       }
     }
     break;
@@ -1005,137 +1069,186 @@ char *pretty_mask(char *mask)
   return make_nick_user_host(nick, user, host);
 }
 
-static char bmodebuf[MODEBUFLEN], bparambuf[MODEBUFLEN];
-static char nbparambuf[MODEBUFLEN];    /* "Numeric" Bounce Parameter Buffer */
+static void send_ban_list(struct Client* cptr, struct Channel* chptr)
+{
+  struct SLink* lp;
+
+  assert(0 != cptr);
+  assert(0 != chptr);
+
+  for (lp = chptr->banlist; lp; lp = lp->next)
+    sendto_one(cptr, rpl_str(RPL_BANLIST), me.name, cptr->name,
+               chptr->chname, lp->value.ban.banstr, lp->value.ban.who,
+               lp->value.ban.when);
+  sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST), me.name, cptr->name,
+             chptr->chname);
+}
 
 /*
  * Check and try to apply the channel modes passed in the parv array for
  * the client ccptr to channel chptr.  The resultant changes are printed
  * into mbuf and pbuf (if any) and applied to the channel.
  */
-static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
-    char *parv[], char *mbuf, char *pbuf, char *npbuf, int *badop)
-{
-  static Link chops[MAXPARA - 2];      /* This size is only needed when a broken
-                                          server sends more then MAXMODEPARAMS
-                                          parameters */
+int set_mode(struct Client* cptr, struct Client* sptr,
+                    struct Channel* chptr, int parc, char* parv[],
+                    char* mbuf, char* pbuf, char* npbuf, int* badop)
+{ 
+  /* 
+   * This size is only needed when a broken
+   * server sends more then MAXMODEPARAMS
+   * parameters
+   */
+  static struct SLink chops[MAXPARA - 2];
   static int flags[] = {
-    MODE_PRIVATE, 'p', MODE_SECRET, 's',
-    MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
-    MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i',
-    MODE_VOICE, 'v', MODE_KEY, 'k',
+    MODE_PRIVATE,    'p',
+    MODE_SECRET,     's',
+    MODE_MODERATED,  'm',
+    MODE_NOPRIVMSGS, 'n',
+    MODE_TOPICLIMIT, 't',
+    MODE_INVITEONLY, 'i',
+    MODE_VOICE,      'v',
+    MODE_KEY,        'k',
     0x0, 0x0
   };
 
-  Reg1 Link *lp;
-  Reg2 char *curr = parv[0], *cp = NULL;
-  Reg3 int *ip;
-  Link *member, *tmp = NULL;
-  unsigned int whatt = MODE_ADD, bwhatt = 0;
-  int limitset = 0, bounce, add_banid_called = 0;
-  size_t len, nlen, blen, nblen;
-  int keychange = 0;
-  unsigned int nusers = 0, newmode;
-  int opcnt = 0, banlsent = 0;
-  int doesdeop = 0, doesop = 0, hacknotice = 0, change, gotts = 0;
-  aClient *who;
-  Mode *mode, oldm;
-  static char numeric[16];
-  char *bmbuf = bmodebuf, *bpbuf = bparambuf, *nbpbuf = nbparambuf;
-  time_t newtime = (time_t) 0;
-  aConfItem *aconf;
+  char bmodebuf[MODEBUFLEN];
+  char bparambuf[MODEBUFLEN];
+  char nbparambuf[MODEBUFLEN];     /* "Numeric" Bounce Parameter Buffer */
+  struct SLink*      lp;
+  char*              curr = parv[0];
+  char*              cp = NULL;
+  int*               ip;
+  struct Membership* member_x;
+  struct Membership* member_y;
+  unsigned int       whatt = MODE_ADD;
+  unsigned int       bwhatt = 0;
+  int                limitset = 0;
+  int                bounce;
+  int                add_banid_called = 0;
+  size_t             len;
+  size_t             nlen;
+  size_t             blen;
+  size_t             nblen;
+  int                keychange = 0;
+  unsigned int       nusers = 0;
+  unsigned int       newmode;
+  int                opcnt = 0;
+  int                banlsent = 0;
+  int                doesdeop = 0;
+  int                doesop = 0;
+  int                hacknotice = 0;
+  int                change;
+  int                gotts = 0;
+  struct Client*     who;
+  struct Mode*       mode;
+  struct Mode        oldm;
+  static char        numeric[16];
+  char*              bmbuf = bmodebuf;
+  char*              bpbuf = bparambuf;
+  char*              nbpbuf = nbparambuf;
+  time_t             newtime = 0;
+  struct ConfItem*   aconf;
 
   *mbuf = *pbuf = *npbuf = *bmbuf = *bpbuf = *nbpbuf = '\0';
   *badop = 0;
   if (parc < 1)
     return 0;
-
-  mode = &(chptr->mode);
-  memcpy(&oldm, mode, sizeof(Mode));
   /*
    * Mode is accepted when sptr is a channel operator
    * but also when the mode is received from a server.
    * At this point, let any member pass, so they are allowed
    * to see the bans.
    */
-  if (!(IsServer(cptr) || (tmp = IsMember(sptr, chptr))))
+  member_y = find_channel_member(sptr, chptr);
+  if (!(IsServer(cptr) || member_y))
     return 0;
 
 #ifdef OPER_MODE_LCHAN
-  if (IsOperOnLocalChannel(sptr, chptr->chname) && !(tmp->flags & CHFL_CHANOP))
+  if (IsOperOnLocalChannel(sptr, chptr->chname) && !IsChanOp(member_y))
     LocalChanOperMode = 1;
 #endif
 
+  mode = &(chptr->mode);
+  memcpy(&oldm, mode, sizeof(struct Mode));
+
   newmode = mode->mode;
 
-  while (curr && *curr)
-  {
-    switch (*curr)
-    {
+  while (curr && *curr) {
+    switch (*curr) {
       case '+':
-       whatt = MODE_ADD;
-       break;
+        whatt = MODE_ADD;
+        break;
       case '-':
-       whatt = MODE_DEL;
-       break;
+        whatt = MODE_DEL;
+        break;
       case 'o':
       case 'v':
-       if (--parc <= 0)
-         break;
-       parv++;
-       if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
-         break;
-       /*
-        * Check for nickname changes and try to follow these
-        * to make sure the right client is affected by the
-        * mode change.
-        * Even if we find a nick with find_chasing() there
-        * is still a reason to ignore in a special case.
-        * We need to ignore the mode when:
-        * - It is part of a net.burst (from a server and
-        *   a MODE_ADD). Ofcourse we don't ignore mode
-        *   changes from Uworld.
-        * - The found nick is not on the right side off
-        *   the net.junction.
-        * This fixes the bug that when someone (tries to)
-        * ride a net.break and does so with the nick of
-        * someone on the otherside, that he is nick collided
-        * (killed) but his +o still ops the other person.
-        */
-       if (MyUser(sptr) || Protocol(cptr) < 10)
-       {
-         if (!(who = find_chasing(sptr, parv[0], NULL)))
-           break;
-       }
-       else
-       {
-         if (!(who = findNUser(parv[0])))
-           break;
-       }
-       if (whatt == MODE_ADD && IsServer(sptr) && who->from != sptr->from &&
-           !find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
-         break;
-       if (!(member = find_user_link(chptr->members, who)) ||
-           (MyUser(sptr) && (member->flags & CHFL_ZOMBIE)))
-       {
-         sendto_one(cptr, err_str(ERR_USERNOTINCHANNEL),
-             me.name, cptr->name, who->name, chptr->chname);
-         break;
-       }
-       /* if the user is +k, prevent a deop from local user */
-       if (whatt == MODE_DEL && IsChannelService(who) &&
-           MyUser(cptr) && *curr == 'o')
-       {
-         sendto_one(cptr, err_str(ERR_ISCHANSERVICE), me.name,
-             cptr->name, parv[0], chptr->chname);
-         break;
-       }
+        if (--parc <= 0)
+          break;
+        parv++;
+        if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
+          break;
+        /*
+         * Check for nickname changes and try to follow these
+         * to make sure the right client is affected by the
+         * mode change.
+         * Even if we find a nick with find_chasing() there
+         * is still a reason to ignore in a special case.
+         * We need to ignore the mode when:
+         * - It is part of a net.burst (from a server and
+         *   a MODE_ADD). Ofcourse we don't ignore mode
+         *   changes from Uworld.
+         * - The found nick is not on the right side off
+         *   the net.junction.
+         * This fixes the bug that when someone (tries to)
+         * ride a net.break and does so with the nick of
+         * someone on the otherside, that he is nick collided
+         * (killed) but his +o still ops the other person.
+         */
+        if (MyUser(sptr))
+        {
+          if (!(who = find_chasing(sptr, parv[0], NULL)))
+            break;
+        }
+        else
+        {
+          if (!(who = findNUser(parv[0])))
+            break;
+        }
+        if (whatt == MODE_ADD && IsServer(sptr) && who->from != sptr->from &&
+            !find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
+          break;
+
+        if (!(member_x = find_member_link(chptr, who)) ||
+            (MyUser(sptr) && IsZombie(member_x)))
+        {
+          sendto_one(cptr, err_str(ERR_USERNOTINCHANNEL),
+              me.name, cptr->name, who->name, chptr->chname);
+          break;
+        }
+        /*
+         * if the user is +k, prevent a deop from local user
+         */
+        if (whatt == MODE_DEL && IsChannelService(who) && *curr == 'o') {
+          /*
+           * XXX - CHECKME
+           */
+          if (MyUser(cptr)) {
+            sendto_one(cptr, err_str(ERR_ISCHANSERVICE), me.name,
+                       cptr->name, parv[0], chptr->chname);
+            break;
+           }
+           else {
+             sprintf_irc(sendbuf,":%s NOTICE * :*** Notice -- Deop of +k user on %s by %s",
+                         me.name,chptr->chname,cptr->name);             
+           }
+        }
 #ifdef NO_OPER_DEOP_LCHAN
         /*
          * if the user is an oper on a local channel, prevent him
          * from being deoped. that oper can deop himself though.
          */
-        if (whatt == MODE_DEL && IsOperOnLocalChannel(who, chptr->chname) && 
+        if (whatt == MODE_DEL && IsOperOnLocalChannel(who, chptr->chname) &&
             (who != sptr) && MyUser(cptr) && *curr == 'o')
         {
           sendto_one(cptr, err_str(ERR_ISOPERLCHAN), me.name,
@@ -1143,168 +1256,166 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
           break;
         }
 #endif
-       if (whatt == MODE_ADD)
-       {
-         lp = &chops[opcnt++];
-         lp->value.cptr = who;
-         if (IsServer(sptr) && (!(who->flags & FLAGS_TS8) || ((*curr == 'o') &&
-             !(member->flags & (CHFL_SERVOPOK | CHFL_CHANOP)))))
-           *badop = ((member->flags & CHFL_DEOPPED) && (*curr == 'o')) ? 2 : 3;
-         lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
-         lp->flags |= MODE_ADD;
-       }
-       else if (whatt == MODE_DEL)
-       {
-         lp = &chops[opcnt++];
-         lp->value.cptr = who;
-         doesdeop = 1;         /* Also when -v */
-         lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
-         lp->flags |= MODE_DEL;
-       }
-       if (*curr == 'o')
-         doesop = 1;
-       break;
+        if (whatt == MODE_ADD)
+        {
+          lp = &chops[opcnt++];
+          lp->value.cptr = who;
+          if (IsServer(sptr) && (!(who->flags & FLAGS_TS8) || ((*curr == 'o') &&
+              !(member_x->status & (CHFL_SERVOPOK | CHFL_CHANOP)))))
+            *badop = ((member_x->status & CHFL_DEOPPED) && (*curr == 'o')) ? 2 : 3;
+          lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
+          lp->flags |= MODE_ADD;
+        }
+        else if (whatt == MODE_DEL)
+        {
+          lp = &chops[opcnt++];
+          lp->value.cptr = who;
+          doesdeop = 1;         /* Also when -v */
+          lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
+          lp->flags |= MODE_DEL;
+        }
+        if (*curr == 'o')
+          doesop = 1;
+        break;
       case 'k':
-       if (--parc <= 0)
-         break;
-       parv++;
-       /* check now so we eat the parameter if present */
-       if (keychange)
-         break;
-       else
-       {
-         char *s = &(*parv)[-1];
-         unsigned short count = KEYLEN + 1;
-
-         while (*++s > ' ' && *s != ':' && --count);
-         *s = '\0';
-         if (!**parv)          /* nothing left in key */
-           break;
-       }
-       if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
-         break;
-       if (whatt == MODE_ADD)
-       {
-         if (*mode->key && !IsServer(cptr))
-           sendto_one(cptr, err_str(ERR_KEYSET),
-               me.name, cptr->name, chptr->chname);
-         else if (!*mode->key || IsServer(cptr))
-         {
-           lp = &chops[opcnt++];
-           lp->value.cp = *parv;
-           if (strlen(lp->value.cp) > (size_t)KEYLEN)
-             lp->value.cp[KEYLEN] = '\0';
-           lp->flags = MODE_KEY | MODE_ADD;
-           keychange = 1;
-         }
-       }
-       else if (whatt == MODE_DEL)
-       {
-         if (strCasediff(mode->key, *parv) == 0 || IsServer(cptr))
-         {
-           lp = &chops[opcnt++];
-           lp->value.cp = mode->key;
-           lp->flags = MODE_KEY | MODE_DEL;
-           keychange = 1;
-         }
-       }
-       break;
+        if (--parc <= 0)
+          break;
+        parv++;
+        /* check now so we eat the parameter if present */
+        if (keychange)
+          break;
+        else
+        {
+          char *s = &(*parv)[-1];
+          unsigned short count = KEYLEN + 1;
+
+          while (*++s > ' ' && *s != ':' && --count);
+          *s = '\0';
+          if (!**parv)          /* nothing left in key */
+            break;
+        }
+        if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
+          break;
+        if (whatt == MODE_ADD)
+        {
+          if (*mode->key && !IsServer(cptr))
+            sendto_one(cptr, err_str(ERR_KEYSET),
+                me.name, cptr->name, chptr->chname);
+          else if (!*mode->key || IsServer(cptr))
+          {
+            lp = &chops[opcnt++];
+            lp->value.cp = *parv;
+            if (strlen(lp->value.cp) > (size_t)KEYLEN)
+              lp->value.cp[KEYLEN] = '\0';
+            lp->flags = MODE_KEY | MODE_ADD;
+            keychange = 1;
+          }
+        }
+        else if (whatt == MODE_DEL)
+        {
+          /* Debug((DEBUG_INFO, "removing key: mode->key: >%s< *parv: >%s<", mode->key, *parv)); */
+          if (0 == ircd_strcmp(mode->key, *parv) || IsServer(cptr))
+          {
+            /* Debug((DEBUG_INFO, "key matched")); */
+            lp = &chops[opcnt++];
+            lp->value.cp = mode->key;
+            lp->flags = MODE_KEY | MODE_DEL;
+            keychange = 1;
+          }
+        }
+        break;
       case 'b':
-       if (--parc <= 0)
-       {
-         if (banlsent)         /* Only send it once */
-           break;
-         for (lp = chptr->banlist; lp; lp = lp->next)
-           sendto_one(cptr, rpl_str(RPL_BANLIST), me.name, cptr->name,
-               chptr->chname, lp->value.ban.banstr, lp->value.ban.who,
-               lp->value.ban.when);
-         sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST), me.name, cptr->name,
-             chptr->chname);
-         banlsent = 1;
-         break;
-       }
-       parv++;
-       if (BadPtr(*parv))
-         break;
-       if (MyUser(sptr))
-       {
-         if ((cp = strchr(*parv, ' ')))
-           *cp = 0;
-         if (opcnt >= MAXMODEPARAMS || **parv == ':' || **parv == '\0')
-           break;
-       }
-       if (whatt == MODE_ADD)
-       {
-         lp = &chops[opcnt++];
-         lp->value.cp = *parv;
-         lp->flags = MODE_ADD | MODE_BAN;
-       }
-       else if (whatt == MODE_DEL)
-       {
-         lp = &chops[opcnt++];
-         lp->value.cp = *parv;
-         lp->flags = MODE_DEL | MODE_BAN;
-       }
-       break;
+        if (--parc <= 0) {
+          if (0 == banlsent) {
+            /*
+             * Only send it once
+             */
+            send_ban_list(cptr, chptr);
+            banlsent = 1;
+          }
+          break;
+        }
+        parv++;
+        if (EmptyString(*parv))
+          break;
+        if (MyUser(sptr))
+        {
+          if ((cp = strchr(*parv, ' ')))
+            *cp = 0;
+          if (opcnt >= MAXMODEPARAMS || **parv == ':' || **parv == '\0')
+            break;
+        }
+        if (whatt == MODE_ADD)
+        {
+          lp = &chops[opcnt++];
+          lp->value.cp = *parv;
+          lp->flags = MODE_ADD | MODE_BAN;
+        }
+        else if (whatt == MODE_DEL)
+        {
+          lp = &chops[opcnt++];
+          lp->value.cp = *parv;
+          lp->flags = MODE_DEL | MODE_BAN;
+        }
+        break;
       case 'l':
-       /*
-        * limit 'l' to only *1* change per mode command but
-        * eat up others.
-        */
-       if (limitset)
-       {
-         if (whatt == MODE_ADD && --parc > 0)
-           parv++;
-         break;
-       }
-       if (whatt == MODE_DEL)
-       {
-         limitset = 1;
-         nusers = 0;
-         break;
-       }
-       if (--parc > 0)
-       {
-         if (BadPtr(*parv))
-           break;
-         if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
-           break;
-         if (!(nusers = atoi(*++parv)))
-           continue;
-         lp = &chops[opcnt++];
-         lp->flags = MODE_ADD | MODE_LIMIT;
-         limitset = 1;
-         break;
-       }
-       sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS),
-           me.name, cptr->name, "MODE +l");
-       break;
-      case 'i':                /* falls through for default case */
-       if (whatt == MODE_DEL)
-         while ((lp = chptr->invites))
-           del_invite(lp->value.cptr, chptr);
+        /*
+         * limit 'l' to only *1* change per mode command but
+         * eat up others.
+         */
+        if (limitset)
+        {
+          if (whatt == MODE_ADD && --parc > 0)
+            parv++;
+          break;
+        }
+        if (whatt == MODE_DEL)
+        {
+          limitset = 1;
+          nusers = 0;
+          break;
+        }
+        if (--parc > 0)
+        {
+          if (EmptyString(*parv))
+            break;
+          if (MyUser(sptr) && opcnt >= MAXMODEPARAMS)
+            break;
+          if (!(nusers = atoi(*++parv)))
+            continue;
+          lp = &chops[opcnt++];
+          lp->flags = MODE_ADD | MODE_LIMIT;
+          limitset = 1;
+          break;
+        }
+        need_more_params(cptr, "MODE +l");
+        break;
+      case 'i':         /* falls through for default case */
+        if (whatt == MODE_DEL)
+          while ((lp = chptr->invites))
+            del_invite(lp->value.cptr, chptr);
       default:
-       for (ip = flags; *ip; ip += 2)
-         if (*(ip + 1) == *curr)
-           break;
-
-       if (*ip)
-       {
-         if (whatt == MODE_ADD)
-         {
-           if (*ip == MODE_PRIVATE)
-             newmode &= ~MODE_SECRET;
-           else if (*ip == MODE_SECRET)
-             newmode &= ~MODE_PRIVATE;
-           newmode |= *ip;
-         }
-         else
-           newmode &= ~*ip;
-       }
-       else if (!IsServer(cptr))
-         sendto_one(cptr, err_str(ERR_UNKNOWNMODE),
-             me.name, cptr->name, *curr);
-       break;
+        for (ip = flags; *ip; ip += 2)
+          if (*(ip + 1) == *curr)
+            break;
+
+        if (*ip)
+        {
+          if (whatt == MODE_ADD)
+          {
+            if (*ip == MODE_PRIVATE)
+              newmode &= ~MODE_SECRET;
+            else if (*ip == MODE_SECRET)
+              newmode &= ~MODE_PRIVATE;
+            newmode |= *ip;
+          }
+          else
+            newmode &= ~*ip;
+        }
+        else if (!IsServer(cptr))
+          sendto_one(cptr, err_str(ERR_UNKNOWNMODE),
+              me.name, cptr->name, *curr);
+        break;
     }
     curr++;
     /*
@@ -1321,66 +1432,66 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
        */
       if (IsServer(sptr))
       {
-       if (parc == 1 && isDigit(*curr))
-       {
-         newtime = atoi(curr);
-         if (newtime && chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
-         {
-           chptr->creationtime = newtime;
-           *badop = 0;
-         }
-         gotts = 1;
-         if (newtime == 0)
-         {
-           *badop = 2;
-           hacknotice = 1;
-         }
-         else if (newtime > chptr->creationtime)
-         {                     /* It is a net-break ride if we have ops.
-                                  bounce modes if we have ops.  --Run */
-           if (doesdeop)
-             *badop = 2;
-           else if (chptr->creationtime == 0)
-           {
-             if (chptr->creationtime == 0 || doesop)
-               chptr->creationtime = newtime;
-             *badop = 0;
-           }
-           /* Bounce: */
-           else
-             *badop = 1;
-         }
-         /*
-          * A legal *badop can occur when two
-          * people join simultaneously a channel,
-          * Allow for 10 min of lag (and thus hacking
-          * on channels younger then 10 min) --Run
-          */
-         else if (*badop == 0 ||
-             chptr->creationtime > (TStime() - TS_LAG_TIME))
-         {
-           if (newtime < chptr->creationtime)
-             chptr->creationtime = newtime;
-           *badop = 0;
-         }
-         break;
-       }
+        if (parc == 1 && IsDigit(*curr))
+        {
+          newtime = atoi(curr);
+          if (newtime && chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
+          {
+            chptr->creationtime = newtime;
+            *badop = 0;
+          }
+          gotts = 1;
+          if (newtime == 0)
+          {
+            *badop = 2;
+            hacknotice = 1;
+          }
+          else if (newtime > chptr->creationtime)
+          {                     /* It is a net-break ride if we have ops.
+                                   bounce modes if we have ops.  --Run */
+            if (doesdeop)
+              *badop = 2;
+            else if (chptr->creationtime == 0)
+            {
+              if (chptr->creationtime == 0 || doesop)
+                chptr->creationtime = newtime;
+              *badop = 0;
+            }
+            /* Bounce: */
+            else
+              *badop = 1;
+          }
+          /*
+           * A legal *badop can occur when two
+           * people join simultaneously a channel,
+           * Allow for 10 min of lag (and thus hacking
+           * on channels younger then 10 min) --Run
+           */
+          else if (*badop == 0 ||
+              chptr->creationtime > (TStime() - TS_LAG_TIME))
+          {
+            if (newtime < chptr->creationtime)
+              chptr->creationtime = newtime;
+            *badop = 0;
+          }
+          break;
+        }
       }
       else
-       *badop = 0;
+        *badop = 0;
     }
-  }                            /* end of while loop for MODE processing */
+  }                             /* end of while loop for MODE processing */
 
+#ifdef OPER_MODE_LCHAN
   /*
    * Now reject non chan ops. Accept modes from opers on local channels
    * even if they are deopped
    */
-#ifdef OPER_MODE_LCHAN
-  if (!IsServer(cptr) && 
-      (!tmp || !((tmp->flags & CHFL_CHANOP) || 
+  if (!IsServer(cptr) &&
+      (!member_y || !(IsChanOp(member_y) ||
                  IsOperOnLocalChannel(sptr, chptr->chname))))
 #else
-  if (!IsServer(cptr) && (!tmp || !(tmp->flags & CHFL_CHANOP)))
+  if (!IsServer(cptr) && (!member_y || !IsChanOp(member_y)))
 #endif
   {
     *badop = 0;
@@ -1391,66 +1502,66 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
     *badop = 2;
 
   if (*badop >= 2 &&
-      (aconf = find_conf_host(cptr->confs, sptr->name, CONF_UWORLD)))
+      (aconf = find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)))
     *badop = 4;
 
 #ifdef OPER_MODE_LCHAN
-  bounce = (*badop == 1 || *badop == 2 || 
-            (is_deopped(sptr, chptr) && 
+  bounce = (*badop == 1 || *badop == 2 ||
+            (is_deopped(sptr, chptr) &&
              !IsOperOnLocalChannel(sptr, chptr->chname))) ? 1 : 0;
 #else
   bounce = (*badop == 1 || *badop == 2 || is_deopped(sptr, chptr)) ? 1 : 0;
 #endif
 
   whatt = 0;
-  for (ip = flags; *ip; ip += 2)
+  for (ip = flags; *ip; ip += 2) {
     if ((*ip & newmode) && !(*ip & oldm.mode))
     {
       if (bounce)
       {
-       if (bwhatt != MODE_DEL)
-       {
-         *bmbuf++ = '-';
-         bwhatt = MODE_DEL;
-       }
-       *bmbuf++ = *(ip + 1);
+        if (bwhatt != MODE_DEL)
+        {
+          *bmbuf++ = '-';
+          bwhatt = MODE_DEL;
+        }
+        *bmbuf++ = *(ip + 1);
       }
       else
       {
-       if (whatt != MODE_ADD)
-       {
-         *mbuf++ = '+';
-         whatt = MODE_ADD;
-       }
-       mode->mode |= *ip;
-       *mbuf++ = *(ip + 1);
+        if (whatt != MODE_ADD)
+        {
+          *mbuf++ = '+';
+          whatt = MODE_ADD;
+        }
+        mode->mode |= *ip;
+        *mbuf++ = *(ip + 1);
       }
     }
-
-  for (ip = flags; *ip; ip += 2)
+  }
+  for (ip = flags; *ip; ip += 2) {
     if ((*ip & oldm.mode) && !(*ip & newmode))
     {
       if (bounce)
       {
-       if (bwhatt != MODE_ADD)
-       {
-         *bmbuf++ = '+';
-         bwhatt = MODE_ADD;
-       }
-       *bmbuf++ = *(ip + 1);
+        if (bwhatt != MODE_ADD)
+        {
+          *bmbuf++ = '+';
+          bwhatt = MODE_ADD;
+        }
+        *bmbuf++ = *(ip + 1);
       }
       else
       {
-       if (whatt != MODE_DEL)
-       {
-         *mbuf++ = '-';
-         whatt = MODE_DEL;
-       }
-       mode->mode &= ~*ip;
-       *mbuf++ = *(ip + 1);
+        if (whatt != MODE_DEL)
+        {
+          *mbuf++ = '-';
+          whatt = MODE_DEL;
+        }
+        mode->mode &= ~*ip;
+        *mbuf++ = *(ip + 1);
       }
     }
-
+  }
   blen = nblen = 0;
   if (limitset && !nusers && mode->limit)
   {
@@ -1458,13 +1569,13 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
     {
       if (bwhatt != MODE_ADD)
       {
-       *bmbuf++ = '+';
-       bwhatt = MODE_ADD;
+        *bmbuf++ = '+';
+        bwhatt = MODE_ADD;
       }
       *bmbuf++ = 'l';
       sprintf(numeric, "%-15d", mode->limit);
       if ((cp = strchr(numeric, ' ')))
-       *cp = '\0';
+        *cp = '\0';
       strcat(bpbuf, numeric);
       blen += strlen(numeric);
       strcat(bpbuf, " ");
@@ -1476,8 +1587,8 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
     {
       if (whatt != MODE_DEL)
       {
-       *mbuf++ = '-';
-       whatt = MODE_DEL;
+        *mbuf++ = '-';
+        whatt = MODE_DEL;
       }
       mode->mode &= ~MODE_LIMIT;
       mode->limit = 0;
@@ -1489,8 +1600,8 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
    */
   if (opcnt)
   {
-    Reg1 int i = 0;
-    Reg2 char c = 0;
+    int i = 0;
+    char c = 0;
     unsigned int prev_whatt = 0;
 
     for (; i < opcnt; i++)
@@ -1501,18 +1612,18 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
        */
       if (whatt != (lp->flags & (MODE_ADD | MODE_DEL)))
       {
-       if (lp->flags & MODE_ADD)
-       {
-         *mbuf++ = '+';
-         prev_whatt = whatt;
-         whatt = MODE_ADD;
-       }
-       else
-       {
-         *mbuf++ = '-';
-         prev_whatt = whatt;
-         whatt = MODE_DEL;
-       }
+        if (lp->flags & MODE_ADD)
+        {
+          *mbuf++ = '+';
+          prev_whatt = whatt;
+          whatt = MODE_ADD;
+        }
+        else
+        {
+          *mbuf++ = '-';
+          prev_whatt = whatt;
+          whatt = MODE_DEL;
+        }
       }
       len = strlen(pbuf);
       nlen = strlen(npbuf);
@@ -1522,250 +1633,251 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
        */
       switch (lp->flags & MODE_WPARAS)
       {
-       case MODE_CHANOP:
-         c = 'o';
-         cp = lp->value.cptr->name;
-         break;
-       case MODE_VOICE:
-         c = 'v';
-         cp = lp->value.cptr->name;
-         break;
-       case MODE_BAN:
-         /*
-          * I made this a bit more user-friendly (tm):
-          * nick = nick!*@*
-          * nick!user = nick!user@*
-          * user@host = *!user@host
-          * host.name = *!*@host.name    --Run
-          */
-         c = 'b';
-         cp = pretty_mask(lp->value.cp);
-         break;
-       case MODE_KEY:
-         c = 'k';
-         cp = lp->value.cp;
-         break;
-       case MODE_LIMIT:
-         c = 'l';
-         sprintf(numeric, "%-15d", nusers);
-         if ((cp = strchr(numeric, ' ')))
-           *cp = '\0';
-         cp = numeric;
-         break;
+        case MODE_CHANOP:
+          c = 'o';
+          cp = lp->value.cptr->name;
+          break;
+        case MODE_VOICE:
+          c = 'v';
+          cp = lp->value.cptr->name;
+          break;
+        case MODE_BAN:
+          /*
+           * I made this a bit more user-friendly (tm):
+           * nick = nick!*@*
+           * nick!user = nick!user@*
+           * user@host = *!user@host
+           * host.name = *!*@host.name    --Run
+           */
+          c = 'b';
+          cp = pretty_mask(lp->value.cp);
+          break;
+        case MODE_KEY:
+          c = 'k';
+          cp = lp->value.cp;
+          break;
+        case MODE_LIMIT:
+          c = 'l';
+          sprintf(numeric, "%-15d", nusers);
+          if ((cp = strchr(numeric, ' ')))
+            *cp = '\0';
+          cp = numeric;
+          break;
       }
 
       /* What could be added: cp+' '+' '+<TS>+'\0' */
       if (len + strlen(cp) + 13 > (size_t)MODEBUFLEN ||
-         nlen + strlen(cp) + NUMNICKLEN + 12 > (size_t)MODEBUFLEN)
-       break;
+          nlen + strlen(cp) + NUMNICKLEN + 12 > (size_t)MODEBUFLEN)
+        break;
 
       switch (lp->flags & MODE_WPARAS)
       {
-       case MODE_KEY:
-         if (strlen(cp) > (size_t)KEYLEN)
-           *(cp + KEYLEN) = '\0';
-         if ((whatt == MODE_ADD && (*mode->key == '\0' ||
-             strCasediff(mode->key, cp) != 0)) ||
-             (whatt == MODE_DEL && (*mode->key != '\0')))
-         {
-           if (bounce)
-           {
-             if (*mode->key == '\0')
-             {
-               if (bwhatt != MODE_DEL)
-               {
-                 *bmbuf++ = '-';
-                 bwhatt = MODE_DEL;
-               }
-               strcat(bpbuf, cp);
-               blen += strlen(cp);
-               strcat(bpbuf, " ");
-               blen++;
-               strcat(nbpbuf, cp);
-               nblen += strlen(cp);
-               strcat(nbpbuf, " ");
-               nblen++;
-             }
-             else
-             {
-               if (bwhatt != MODE_ADD)
-               {
-                 *bmbuf++ = '+';
-                 bwhatt = MODE_ADD;
-               }
-               strcat(bpbuf, mode->key);
-               blen += strlen(mode->key);
-               strcat(bpbuf, " ");
-               blen++;
-               strcat(nbpbuf, mode->key);
-               nblen += strlen(mode->key);
-               strcat(nbpbuf, " ");
-               nblen++;
-             }
-             *bmbuf++ = c;
-             mbuf--;
-             if (*mbuf != '+' && *mbuf != '-')
-               mbuf++;
-             else
-               whatt = prev_whatt;
-           }
-           else
-           {
-             *mbuf++ = c;
-             strcat(pbuf, cp);
-             len += strlen(cp);
-             strcat(pbuf, " ");
-             len++;
-             strcat(npbuf, cp);
-             nlen += strlen(cp);
-             strcat(npbuf, " ");
-             nlen++;
-             if (whatt == MODE_ADD)
-               strncpy(mode->key, cp, KEYLEN);
-             else
-               *mode->key = '\0';
-           }
-         }
-         break;
-       case MODE_LIMIT:
-         if (nusers && nusers != mode->limit)
-         {
-           if (bounce)
-           {
-             if (mode->limit == 0)
-             {
-               if (bwhatt != MODE_DEL)
-               {
-                 *bmbuf++ = '-';
-                 bwhatt = MODE_DEL;
-               }
-             }
-             else
-             {
-               if (bwhatt != MODE_ADD)
-               {
-                 *bmbuf++ = '+';
-                 bwhatt = MODE_ADD;
-               }
-               sprintf(numeric, "%-15d", mode->limit);
-               if ((cp = strchr(numeric, ' ')))
-                 *cp = '\0';
-               strcat(bpbuf, numeric);
-               blen += strlen(numeric);
-               strcat(bpbuf, " ");
-               blen++;
-               strcat(nbpbuf, numeric);
-               nblen += strlen(numeric);
-               strcat(nbpbuf, " ");
-               nblen++;
-             }
-             *bmbuf++ = c;
-             mbuf--;
-             if (*mbuf != '+' && *mbuf != '-')
-               mbuf++;
-             else
-               whatt = prev_whatt;
-           }
-           else
-           {
-             *mbuf++ = c;
-             strcat(pbuf, cp);
-             len += strlen(cp);
-             strcat(pbuf, " ");
-             len++;
-             strcat(npbuf, cp);
-             nlen += strlen(cp);
-             strcat(npbuf, " ");
-             nlen++;
-             mode->limit = nusers;
-           }
-         }
-         break;
-       case MODE_CHANOP:
-       case MODE_VOICE:
-         tmp = find_user_link(chptr->members, lp->value.cptr);
-         if (lp->flags & MODE_ADD)
-         {
-           change = (~tmp->flags) & CHFL_OVERLAP & lp->flags;
-           if (change && bounce)
-           {
-             if (lp->flags & MODE_CHANOP)
-               tmp->flags |= CHFL_DEOPPED;
-             if (bwhatt != MODE_DEL)
-             {
-               *bmbuf++ = '-';
-               bwhatt = MODE_DEL;
-             }
-             *bmbuf++ = c;
-             strcat(bpbuf, lp->value.cptr->name);
-             blen += strlen(lp->value.cptr->name);
-             strcat(bpbuf, " ");
-             blen++;
-             sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
-             nblen += strlen(nbpbuf + nblen);
-             change = 0;
-           }
-           else if (change)
-           {
-             tmp->flags |= lp->flags & CHFL_OVERLAP;
-             if (lp->flags & MODE_CHANOP)
-             {
-               tmp->flags &= ~CHFL_DEOPPED;
-               if (IsServer(sptr))
-                 tmp->flags &= ~CHFL_SERVOPOK;
-             }
-           }
-         }
-         else
-         {
-           change = tmp->flags & CHFL_OVERLAP & lp->flags;
-           if (change && bounce)
-           {
-             if (lp->flags & MODE_CHANOP)
-               tmp->flags &= ~CHFL_DEOPPED;
-             if (bwhatt != MODE_ADD)
-             {
-               *bmbuf++ = '+';
-               bwhatt = MODE_ADD;
-             }
-             *bmbuf++ = c;
-             strcat(bpbuf, lp->value.cptr->name);
-             blen += strlen(lp->value.cptr->name);
-             strcat(bpbuf, " ");
-             blen++;
-             sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
-             blen += strlen(bpbuf + blen);
-             change = 0;
-           }
-           else
-           {
-             tmp->flags &= ~change;
-             if ((change & MODE_CHANOP) && IsServer(sptr))
-               tmp->flags |= CHFL_DEOPPED;
-           }
-         }
-         if (change || *badop == 2 || *badop == 4)
-         {
-           *mbuf++ = c;
-           strcat(pbuf, cp);
-           len += strlen(cp);
-           strcat(pbuf, " ");
-           len++;
-           sprintf_irc(npbuf + nlen, "%s%s ", NumNick(lp->value.cptr));
-           nlen += strlen(npbuf + nlen);
-           npbuf[nlen++] = ' ';
-           npbuf[nlen] = 0;
-         }
-         else
-         {
-           mbuf--;
-           if (*mbuf != '+' && *mbuf != '-')
-             mbuf++;
-           else
-             whatt = prev_whatt;
-         }
-         break;
-       case MODE_BAN:
+        case MODE_KEY:
+          if (strlen(cp) > (size_t)KEYLEN)
+            *(cp + KEYLEN) = '\0';
+          if ((whatt == MODE_ADD && (*mode->key == '\0' ||
+               0 != ircd_strcmp(mode->key, cp))) ||
+              (whatt == MODE_DEL && (*mode->key != '\0')))
+          {
+            if (bounce)
+            {
+              if (*mode->key == '\0')
+              {
+                if (bwhatt != MODE_DEL)
+                {
+                  *bmbuf++ = '-';
+                  bwhatt = MODE_DEL;
+                }
+                strcat(bpbuf, cp);
+                blen += strlen(cp);
+                strcat(bpbuf, " ");
+                blen++;
+                strcat(nbpbuf, cp);
+                nblen += strlen(cp);
+                strcat(nbpbuf, " ");
+                nblen++;
+              }
+              else
+              {
+                if (bwhatt != MODE_ADD)
+                {
+                  *bmbuf++ = '+';
+                  bwhatt = MODE_ADD;
+                }
+                strcat(bpbuf, mode->key);
+                blen += strlen(mode->key);
+                strcat(bpbuf, " ");
+                blen++;
+                strcat(nbpbuf, mode->key);
+                nblen += strlen(mode->key);
+                strcat(nbpbuf, " ");
+                nblen++;
+              }
+              *bmbuf++ = c;
+              mbuf--;
+              if (*mbuf != '+' && *mbuf != '-')
+                mbuf++;
+              else
+                whatt = prev_whatt;
+            }
+            else
+            {
+              *mbuf++ = c;
+              strcat(pbuf, cp);
+              len += strlen(cp);
+              strcat(pbuf, " ");
+              len++;
+              strcat(npbuf, cp);
+              nlen += strlen(cp);
+              strcat(npbuf, " ");
+              nlen++;
+              if (whatt == MODE_ADD)
+                ircd_strncpy(mode->key, cp, KEYLEN);
+              else
+                *mode->key = '\0';
+            }
+          }
+          break;
+        case MODE_LIMIT:
+          if (nusers && nusers != mode->limit)
+          {
+            if (bounce)
+            {
+              if (mode->limit == 0)
+              {
+                if (bwhatt != MODE_DEL)
+                {
+                  *bmbuf++ = '-';
+                  bwhatt = MODE_DEL;
+                }
+              }
+              else
+              {
+                if (bwhatt != MODE_ADD)
+                {
+                  *bmbuf++ = '+';
+                  bwhatt = MODE_ADD;
+                }
+                sprintf(numeric, "%-15d", mode->limit);
+                if ((cp = strchr(numeric, ' ')))
+                  *cp = '\0';
+                strcat(bpbuf, numeric);
+                blen += strlen(numeric);
+                strcat(bpbuf, " ");
+                blen++;
+                strcat(nbpbuf, numeric);
+                nblen += strlen(numeric);
+                strcat(nbpbuf, " ");
+                nblen++;
+              }
+              *bmbuf++ = c;
+              mbuf--;
+              if (*mbuf != '+' && *mbuf != '-')
+                mbuf++;
+              else
+                whatt = prev_whatt;
+            }
+            else
+            {
+              *mbuf++ = c;
+              strcat(pbuf, cp);
+              len += strlen(cp);
+              strcat(pbuf, " ");
+              len++;
+              strcat(npbuf, cp);
+              nlen += strlen(cp);
+              strcat(npbuf, " ");
+              nlen++;
+              mode->limit = nusers;
+            }
+          }
+          break;
+        case MODE_CHANOP:
+        case MODE_VOICE:
+          member_y = find_member_link(chptr, lp->value.cptr);
+          if (lp->flags & MODE_ADD)
+          {
+            change = (~member_y->status) & CHFL_VOICED_OR_OPPED & lp->flags;
+            if (change && bounce)
+            {
+              if (lp->flags & MODE_CHANOP)
+                SetDeopped(member_y);
+
+              if (bwhatt != MODE_DEL)
+              {
+                *bmbuf++ = '-';
+                bwhatt = MODE_DEL;
+              }
+              *bmbuf++ = c;
+              strcat(bpbuf, lp->value.cptr->name);
+              blen += strlen(lp->value.cptr->name);
+              strcat(bpbuf, " ");
+              blen++;
+              sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
+              nblen += strlen(nbpbuf + nblen);
+              change = 0;
+            }
+            else if (change)
+            {
+              member_y->status |= lp->flags & CHFL_VOICED_OR_OPPED;
+              if (IsChanOp(member_y))
+              {
+                ClearDeopped(member_y);
+                if (IsServer(sptr))
+                  ClearServOpOk(member_y);
+              }
+            }
+          }
+          else
+          {
+            change = member_y->status & CHFL_VOICED_OR_OPPED & lp->flags;
+            if (change && bounce)
+            {
+              if (lp->flags & MODE_CHANOP)
+                ClearDeopped(member_y);
+              if (bwhatt != MODE_ADD)
+              {
+                *bmbuf++ = '+';
+                bwhatt = MODE_ADD;
+              }
+              *bmbuf++ = c;
+              strcat(bpbuf, lp->value.cptr->name);
+              blen += strlen(lp->value.cptr->name);
+              strcat(bpbuf, " ");
+              blen++;
+              sprintf_irc(nbpbuf + nblen, "%s%s ", NumNick(lp->value.cptr));
+              blen += strlen(bpbuf + blen);
+              change = 0;
+            }
+            else
+            {
+              member_y->status &= ~change;
+              if ((change & MODE_CHANOP) && IsServer(sptr))
+                SetDeopped(member_y);
+            }
+          }
+          if (change || *badop == 2 || *badop == 4)
+          {
+            *mbuf++ = c;
+            strcat(pbuf, cp);
+            len += strlen(cp);
+            strcat(pbuf, " ");
+            len++;
+            sprintf_irc(npbuf + nlen, "%s%s ", NumNick(lp->value.cptr));
+            nlen += strlen(npbuf + nlen);
+            npbuf[nlen++] = ' ';
+            npbuf[nlen] = 0;
+          }
+          else
+          {
+            mbuf--;
+            if (*mbuf != '+' && *mbuf != '-')
+              mbuf++;
+            else
+              whatt = prev_whatt;
+          }
+          break;
+        case MODE_BAN:
 /*
  * Only bans aren't bounced, it makes no sense to bounce last second
  * bans while propagating bans done before the net.rejoin. The reason
@@ -1779,65 +1891,65 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
  * certainly makes sense to also bounce 'last second' bans (bans done
  * after the net.junction). -- RunHardWorker
  */
-         if ((change = (whatt & MODE_ADD) &&
-             !add_banid(sptr, chptr, cp, !bounce, !add_banid_called)))
-           add_banid_called = 1;
-         else
-           change = (whatt & MODE_DEL) && !del_banid(chptr, cp, !bounce);
-
-         if (bounce && change)
-         {
-           change = 0;
-           if ((whatt & MODE_ADD))
-           {
-             if (bwhatt != MODE_DEL)
-             {
-               *bmbuf++ = '-';
-               bwhatt = MODE_DEL;
-             }
-           }
-           else if ((whatt & MODE_DEL))
-           {
-             if (bwhatt != MODE_ADD)
-             {
-               *bmbuf++ = '+';
-               bwhatt = MODE_ADD;
-             }
-           }
-           *bmbuf++ = c;
-           strcat(bpbuf, cp);
-           blen += strlen(cp);
-           strcat(bpbuf, " ");
-           blen++;
-           strcat(nbpbuf, cp);
-           nblen += strlen(cp);
-           strcat(nbpbuf, " ");
-           nblen++;
-         }
-         if (change)
-         {
-           *mbuf++ = c;
-           strcat(pbuf, cp);
-           len += strlen(cp);
-           strcat(pbuf, " ");
-           len++;
-           strcat(npbuf, cp);
-           nlen += strlen(cp);
-           strcat(npbuf, " ");
-           nlen++;
-         }
-         else
-         {
-           mbuf--;
-           if (*mbuf != '+' && *mbuf != '-')
-             mbuf++;
-           else
-             whatt = prev_whatt;
-         }
-         break;
+          if ((change = (whatt & MODE_ADD) &&
+              !add_banid(sptr, chptr, cp, !bounce, !add_banid_called)))
+            add_banid_called = 1;
+          else
+            change = (whatt & MODE_DEL) && !del_banid(chptr, cp, !bounce);
+
+          if (bounce && change)
+          {
+            change = 0;
+            if ((whatt & MODE_ADD))
+            {
+              if (bwhatt != MODE_DEL)
+              {
+                *bmbuf++ = '-';
+                bwhatt = MODE_DEL;
+              }
+            }
+            else if ((whatt & MODE_DEL))
+            {
+              if (bwhatt != MODE_ADD)
+              {
+                *bmbuf++ = '+';
+                bwhatt = MODE_ADD;
+              }
+            }
+            *bmbuf++ = c;
+            strcat(bpbuf, cp);
+            blen += strlen(cp);
+            strcat(bpbuf, " ");
+            blen++;
+            strcat(nbpbuf, cp);
+            nblen += strlen(cp);
+            strcat(nbpbuf, " ");
+            nblen++;
+          }
+          if (change)
+          {
+            *mbuf++ = c;
+            strcat(pbuf, cp);
+            len += strlen(cp);
+            strcat(pbuf, " ");
+            len++;
+            strcat(npbuf, cp);
+            nlen += strlen(cp);
+            strcat(npbuf, " ");
+            nlen++;
+          }
+          else
+          {
+            mbuf--;
+            if (*mbuf != '+' && *mbuf != '-')
+              mbuf++;
+            else
+              whatt = prev_whatt;
+          }
+          break;
       }
-    }                          /* for (; i < opcnt; i++) */
-  }                            /* if (opcnt) */
+    }                           /* for (; i < opcnt; i++) */
+  }                             /* if (opcnt) */
 
   *mbuf++ = '\0';
   *bmbuf++ = '\0';
@@ -1845,105 +1957,100 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
   /* Bounce here */
   if (!hacknotice && *bmodebuf && chptr->creationtime)
   {
-    if (Protocol(cptr) < 10)
-      sendto_one(cptr, ":%s MODE %s %s %s " TIME_T_FMT,
-         me.name, chptr->chname, bmodebuf, bparambuf,
-         *badop == 2 ? (time_t) 0 : chptr->creationtime);
-    else
-      sendto_one(cptr, "%s MODE %s %s %s " TIME_T_FMT,
-         NumServ(&me), chptr->chname, bmodebuf, nbparambuf,
-         *badop == 2 ? (time_t) 0 : chptr->creationtime);
+    sendto_one(cptr, "%s " TOK_MODE " %s %s %s " TIME_T_FMT,
+               NumServ(&me), chptr->chname, bmodebuf, nbparambuf,
+               *badop == 2 ? (time_t) 0 : chptr->creationtime);
   }
   /* If there are possibly bans to re-add, bounce them now */
   if (add_banid_called && bounce)
   {
-    Link *ban[6];              /* Max 6 bans at a time */
+    struct SLink *ban[6];               /* Max 6 bans at a time */
     size_t len[6], sblen, total_len;
     int cnt, delayed = 0;
     while (delayed || (ban[0] = next_overlapped_ban()))
     {
       len[0] = strlen(ban[0]->value.ban.banstr);
-      cnt = 1;                 /* We already got one ban :) */
+      cnt = 1;                  /* We already got one ban :) */
       sblen = sprintf_irc(sendbuf, ":%s MODE %s +b",
-         me.name, chptr->chname) - sendbuf;
-      total_len = sblen + 1 + len[0];  /* 1 = ' ' */
+          me.name, chptr->chname) - sendbuf;
+      total_len = sblen + 1 + len[0];   /* 1 = ' ' */
       /* Find more bans: */
       delayed = 0;
       while (cnt < 6 && (ban[cnt] = next_overlapped_ban()))
       {
-       len[cnt] = strlen(ban[cnt]->value.ban.banstr);
-       if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
-       {
-         delayed = cnt + 1;    /* != 0 */
-         break;                /* Flush */
-       }
-       sendbuf[sblen++] = 'b';
-       total_len += 2 + len[cnt++];    /* 2 = "b " */
+        len[cnt] = strlen(ban[cnt]->value.ban.banstr);
+        if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
+        {
+          delayed = cnt + 1;    /* != 0 */
+          break;                /* Flush */
+        }
+        sendbuf[sblen++] = 'b';
+        total_len += 2 + len[cnt++];    /* 2 = "b " */
       }
       while (cnt--)
       {
-       sendbuf[sblen++] = ' ';
-       strcpy(sendbuf + sblen, ban[cnt]->value.ban.banstr);
-       sblen += len[cnt];
+        sendbuf[sblen++] = ' ';
+        strcpy(sendbuf + sblen, ban[cnt]->value.ban.banstr);
+        sblen += len[cnt];
       }
-      sendbufto_one(cptr);     /* Send bounce to uplink */
+      sendbufto_one(cptr);      /* Send bounce to uplink */
       if (delayed)
-       ban[0] = ban[delayed - 1];
+        ban[0] = ban[delayed - 1];
     }
   }
   /* Send -b's of overlapped bans to clients to keep them synchronized */
   if (add_banid_called && !bounce)
   {
-    Link *ban;
-    char *banstr[6];           /* Max 6 bans at a time */
+    struct SLink *ban;
+    char *banstr[6];            /* Max 6 bans at a time */
     size_t len[6], sblen, psblen, total_len;
     int cnt, delayed = 0;
-    Link *lp;
-    aClient *acptr;
+    struct Membership* member_z;
+    struct Client *acptr;
     if (IsServer(sptr))
       psblen = sprintf_irc(sendbuf, ":%s MODE %s -b",
-         sptr->name, chptr->chname) - sendbuf;
-    else                       /* We rely on IsRegistered(sptr) being true for MODE */
+          sptr->name, chptr->chname) - sendbuf;
+    else                        /* We rely on IsRegistered(sptr) being true for MODE */
       psblen = sprintf_irc(sendbuf, ":%s!%s@%s MODE %s -b", sptr->name,
-         sptr->user->username, sptr->user->host, chptr->chname) - sendbuf;
+          sptr->user->username, sptr->user->host, chptr->chname) - sendbuf;
     while (delayed || (ban = next_removed_overlapped_ban()))
     {
       if (!delayed)
       {
-       len[0] = strlen((banstr[0] = ban->value.ban.banstr));
-       ban->value.ban.banstr = NULL;
+        len[0] = strlen((banstr[0] = ban->value.ban.banstr));
+        ban->value.ban.banstr = NULL;
       }
-      cnt = 1;                 /* We already got one ban :) */
+      cnt = 1;                  /* We already got one ban :) */
       sblen = psblen;
-      total_len = sblen + 1 + len[0];  /* 1 = ' ' */
+      total_len = sblen + 1 + len[0];   /* 1 = ' ' */
       /* Find more bans: */
       delayed = 0;
       while (cnt < 6 && (ban = next_removed_overlapped_ban()))
       {
-       len[cnt] = strlen((banstr[cnt] = ban->value.ban.banstr));
-       ban->value.ban.banstr = NULL;
-       if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
-       {
-         delayed = cnt + 1;    /* != 0 */
-         break;                /* Flush */
-       }
-       sendbuf[sblen++] = 'b';
-       total_len += 2 + len[cnt++];    /* 2 = "b " */
+        len[cnt] = strlen((banstr[cnt] = ban->value.ban.banstr));
+        ban->value.ban.banstr = NULL;
+        if (total_len + 5 + len[cnt] > BUFSIZE) /* 5 = "b \r\n\0" */
+        {
+          delayed = cnt + 1;    /* != 0 */
+          break;                /* Flush */
+        }
+        sendbuf[sblen++] = 'b';
+        total_len += 2 + len[cnt++];    /* 2 = "b " */
       }
       while (cnt--)
       {
-       sendbuf[sblen++] = ' ';
-       strcpy(sendbuf + sblen, banstr[cnt]);
-       RunFree(banstr[cnt]);
-       sblen += len[cnt];
+        sendbuf[sblen++] = ' ';
+        strcpy(sendbuf + sblen, banstr[cnt]);
+        MyFree(banstr[cnt]);
+        sblen += len[cnt];
       }
-      for (lp = chptr->members; lp; lp = lp->next)
-       if (MyConnect(acptr = lp->value.cptr) && !(lp->flags & CHFL_ZOMBIE))
-         sendbufto_one(acptr);
+      for (member_z = chptr->members; member_z; member_z = member_z->next_member)
+        if (MyConnect(acptr = member_z->user) && !IsZombie(member_z))
+          sendbufto_one(acptr);
       if (delayed)
       {
-       banstr[0] = banstr[delayed - 1];
-       len[0] = len[delayed - 1];
+        banstr[0] = banstr[delayed - 1];
+        len[0] = len[delayed - 1];
       }
     }
   }
@@ -1959,13 +2066,13 @@ static int set_mode(aClient *cptr, aClient *sptr, aChannel *chptr, int parc,
  */
 static int compall(char *key, char *keyring)
 {
-  register char *p1;
+  char *p1;
 
 top:
-  p1 = key;                    /* point to the key... */
+  p1 = key;                     /* point to the key... */
   while (*p1 && *p1 == *keyring)
-  {                            /* step through the key and ring until they
-                                  don't match... */
+  {                             /* step through the key and ring until they
+                                   don't match... */
     p1++;
     keyring++;
   }
@@ -1975,29 +2082,30 @@ top:
        in the keyring, we have a match */
     return 0;
 
-  if (!*keyring)               /* if we're at the end of the key ring, there
-                                  weren't any matches, so we return 1 */
+  if (!*keyring)                /* if we're at the end of the key ring, there
+                                   weren't any matches, so we return 1 */
     return 1;
 
   /* Not at the end of the key ring, so step
      through to the next key in the ring: */
   while (*keyring && *(keyring++) != ',');
 
-  goto top;                    /* and check it against the key */
+  goto top;                     /* and check it against the key */
 }
 
-static int can_join(aClient *sptr, aChannel *chptr, char *key)
+int can_join(struct Client *sptr, struct Channel *chptr, char *key)
 {
-  Reg1 Link *lp;
+  struct SLink *lp;
   int overrideJoin = 0;  
-  
+
 #ifdef OPER_WALK_THROUGH_LMODES
   /* An oper can force a join on a local channel using "OVERRIDE" as the key. 
      a HACK(4) notice will be sent if he would not have been supposed
      to join normally. */ 
-  if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && 
-       compall("OVERRIDE",key) == 0)
+  if (IsOperOnLocalChannel(sptr,chptr->chname) && !BadPtr(key) && compall("OVERRIDE",key) == 0)
+  {
     overrideJoin = MAGIC_OPER_OVERRIDE;
+  }
 #endif
   /*
    * Now a banned user CAN join if invited -- Nemesi
@@ -2008,23 +2116,25 @@ static int can_join(aClient *sptr, aChannel *chptr, char *key)
   {
     for (lp = sptr->user->invited; lp; lp = lp->next)
       if (lp->value.chptr == chptr)
-       break;
+        break;
     if (!lp)
     {
       if (chptr->mode.limit && chptr->users >= chptr->mode.limit)
-       return (overrideJoin + ERR_CHANNELISFULL);
+        return (overrideJoin + ERR_CHANNELISFULL);
       /*
        * This can return an "Invite only" msg instead of the "You are banned"
        * if _both_ conditions are true, but who can say what is more
        * appropriate ? checking again IsBanned would be _SO_ cpu-xpensive !
        */
       return overrideJoin + ((chptr->mode.mode & MODE_INVITEONLY) ?
-         ERR_INVITEONLYCHAN : ERR_BANNEDFROMCHAN);
+          ERR_INVITEONLYCHAN : ERR_BANNEDFROMCHAN);
     }
   }
 
-  /* now using compall (above) to test against a whole key ring -Kev */
-  if (*chptr->mode.key && (BadPtr(key) || compall(chptr->mode.key, key)))
+  /*
+   * now using compall (above) to test against a whole key ring -Kev
+   */
+  if (*chptr->mode.key && (EmptyString(key) || compall(chptr->mode.key, key)))
     return overrideJoin + (ERR_BADCHANNELKEY);
 
   return 0;
@@ -2033,27 +2143,24 @@ static int can_join(aClient *sptr, aChannel *chptr, char *key)
 /*
  * Remove bells and commas from channel name
  */
-
-static void clean_channelname(char *cn)
+void clean_channelname(char *cn)
 {
-  for (; *cn; cn++)
-  {
-    if (!isIrcCh(*cn))
-    {
+  for (; *cn; ++cn) {
+    if (!IsChannelChar(*cn)) {
       *cn = '\0';
       return;
     }
-    if (isIrcCl(*cn))
-#ifndef FIXME
-    {
-#endif
-      *cn = toLower(*cn);
+    if (IsChannelLower(*cn)) {
+      *cn = ToLower(*cn);
 #ifndef FIXME
-      /* Missed the Icelandic letter ETH last time: */
+      /*
+       * Remove for .08+
+       * toupper(0xd0)
+       */
       if ((unsigned char)(*cn) == 0xd0)
-       *cn = (char)0xf0;
-    }
+        *cn = (char) 0xf0;
 #endif
+    }
   }
 }
 
@@ -2061,12 +2168,12 @@ static void clean_channelname(char *cn)
  *  Get Channel block for i (and allocate a new channel
  *  block, if it didn't exists before).
  */
-static aChannel *get_channel(aClient *cptr, char *chname, int flag)
+struct Channel *get_channel(struct Client *cptr, char *chname, ChannelGetType flag)
 {
-  Reg1 aChannel *chptr;
+  struct Channel *chptr;
   int len;
 
-  if (BadPtr(chname))
+  if (EmptyString(chname))
     return NULL;
 
   len = strlen(chname);
@@ -2077,32 +2184,34 @@ static aChannel *get_channel(aClient *cptr, char *chname, int flag)
   }
   if ((chptr = FindChannel(chname)))
     return (chptr);
-  if (flag == CREATE)
+  if (flag == CGT_CREATE)
   {
-    chptr = (aChannel *)RunMalloc(sizeof(aChannel) + len);
-    ++nrof.channels;
-    memset(chptr, 0, sizeof(aChannel));
+    chptr = (struct Channel*) MyMalloc(sizeof(struct Channel) + len);
+    assert(0 != chptr);
+    ++UserStats.channels;
+    memset(chptr, 0, sizeof(struct Channel));
     strcpy(chptr->chname, chname);
-    if (channel)
-      channel->prevch = chptr;
-    chptr->prevch = NULL;
-    chptr->nextch = channel;
+    if (GlobalChannelList)
+      GlobalChannelList->prev = chptr;
+    chptr->prev = NULL;
+    chptr->next = GlobalChannelList;
     chptr->creationtime = MyUser(cptr) ? TStime() : (time_t) 0;
-    channel = chptr;
+    GlobalChannelList = chptr;
     hAddChannel(chptr);
   }
   return chptr;
 }
 
-static void add_invite(aClient *cptr, aChannel *chptr)
+void add_invite(struct Client *cptr, struct Channel *chptr)
 {
-  Reg1 Link *inv, **tmp;
+  struct SLink *inv, **tmp;
 
   del_invite(cptr, chptr);
   /*
    * Delete last link in chain if the list is max length
    */
-  if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
+  assert(list_length(cptr->user->invited) == cptr->user->invites);
+  if (cptr->user->invites>=MAXCHANNELSPERUSER)
     del_invite(cptr, cptr->user->invited->value.chptr);
   /*
    * Add client to channel invite list
@@ -2119,20 +2228,23 @@ static void add_invite(aClient *cptr, aChannel *chptr)
   inv->value.chptr = chptr;
   inv->next = NULL;
   (*tmp) = inv;
+  cptr->user->invites++;
 }
 
 /*
  * Delete Invite block from channel invite list and client invite list
  */
-void del_invite(aClient *cptr, aChannel *chptr)
+void del_invite(struct Client *cptr, struct Channel *chptr)
 {
-  Reg1 Link **inv, *tmp;
+  struct SLink **inv, *tmp;
 
   for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
     if (tmp->value.cptr == cptr)
     {
       *inv = tmp->next;
       free_link(tmp);
+      tmp = 0;
+      cptr->user->invites--;
       break;
     }
 
@@ -2141,39 +2253,41 @@ void del_invite(aClient *cptr, aChannel *chptr)
     {
       *inv = tmp->next;
       free_link(tmp);
+      tmp = 0;
       break;
     }
 }
 
 /* List and skip all channels that are listen */
-void list_next_channels(aClient *cptr, int nr)
+void list_next_channels(struct Client *cptr, int nr)
 {
-  aListingArgs *args = cptr->listing;
-  aChannel *chptr = args->chptr;
+  struct ListingArgs *args = cptr->listing;
+  struct Channel *chptr = args->chptr;
   chptr->mode.mode &= ~MODE_LISTED;
   while (is_listed(chptr) || --nr >= 0)
   {
-    for (; chptr; chptr = chptr->nextch)
+    for (; chptr; chptr = chptr->next)
     {
-      if (!cptr->user || (SecretChannel(chptr) && !IsMember(cptr, chptr)))
-       continue;
+      if (!cptr->user || (SecretChannel(chptr) && !find_channel_member(cptr, chptr)))
+        continue;
       if (chptr->users > args->min_users && chptr->users < args->max_users &&
-         chptr->creationtime > args->min_time &&
-         chptr->creationtime < args->max_time &&
-         (!args->topic_limits || (*chptr->topic &&
-         chptr->topic_time > args->min_topic_time &&
-         chptr->topic_time < args->max_topic_time)))
+          chptr->creationtime > args->min_time &&
+          chptr->creationtime < args->max_time &&
+          (!args->topic_limits || (*chptr->topic &&
+          chptr->topic_time > args->min_topic_time &&
+          chptr->topic_time < args->max_topic_time)))
       {
-       sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
-           ShowChannel(cptr, chptr) ? chptr->chname : "*",
-           chptr->users, ShowChannel(cptr, chptr) ? chptr->topic : "");
-       chptr = chptr->nextch;
-       break;
+        if (ShowChannel(cptr,chptr))
+          sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
+            chptr->chname,
+            chptr->users, chptr->topic);
+        chptr = chptr->next;
+        break;
       }
     }
     if (!chptr)
     {
-      RunFree(cptr->listing);
+      MyFree(cptr->listing);
       cptr->listing = NULL;
       sendto_one(cptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
       break;
@@ -2186,536 +2300,11 @@ void list_next_channels(aClient *cptr, int nr)
   }
 }
 
-/*
- *  Subtract one user from channel i (and free channel
- *  block, if channel became empty).
- */
-static void sub1_from_channel(aChannel *chptr)
+
+void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
+    int *send_itp, char is_a_ban, int mode)
 {
-  Reg2 Link *tmp;
-  Link *obtmp;
-
-  if (chptr->users > 1)                /* Can be 0, called for an empty channel too */
-  {
-    --chptr->users;
-    return;
-  }
-
-  /* Channel became (or was) empty: Remove channel */
-  if (is_listed(chptr))
-  {
-    int i;
-    for (i = 0; i <= highest_fd; i++)
-    {
-      aClient *acptr;
-      if ((acptr = loc_clients[i]) && acptr->listing &&
-         acptr->listing->chptr == chptr)
-      {
-       list_next_channels(acptr, 1);
-       break;                  /* Only one client can list a channel */
-      }
-    }
-  }
-  /*
-   * Now, find all invite links from channel structure
-   */
-  while ((tmp = chptr->invites))
-    del_invite(tmp->value.cptr, chptr);
-
-  tmp = chptr->banlist;
-  while (tmp)
-  {
-    obtmp = tmp;
-    tmp = tmp->next;
-    RunFree(obtmp->value.ban.banstr);
-    RunFree(obtmp->value.ban.who);
-    free_link(obtmp);
-  }
-  if (chptr->prevch)
-    chptr->prevch->nextch = chptr->nextch;
-  else
-    channel = chptr->nextch;
-  if (chptr->nextch)
-    chptr->nextch->prevch = chptr->prevch;
-  hRemChannel(chptr);
-  --nrof.channels;
-  RunFree((char *)chptr);
-}
-
-/*
- * m_join
- *
- * parv[0] = sender prefix
- * parv[1] = channel
- * parv[2] = channel keys (client), or channel TS (server)
- */
-int m_join(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  static char jbuf[BUFSIZE], mbuf[BUFSIZE];
-  Reg1 Link *lp;
-  Reg3 aChannel *chptr;
-  Reg4 char *name, *keysOrTS = NULL;
-  int i = 0, zombie = 0, sendcreate = 0;
-  unsigned int flags = 0;
-  size_t jlen = 0, mlen = 0;
-  size_t *buflen;
-  char *p = NULL, *bufptr;
-
-  if (parc < 2 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "JOIN");
-    return 0;
-  }
-
-  for (p = parv[1]; *p; p++)   /* find the last "JOIN 0" in the line -Kev */
-    if (*p == '0'
-       && (*(p + 1) == ',' || *(p + 1) == '\0' || !isIrcCh(*(p + 1))))
-    {
-      /* If it's a single "0", remember the place; we will start parsing
-         the channels after the last 0 in the line -Kev */
-      parv[1] = p;
-      if (!*(p + 1))
-       break;
-      p++;
-    }
-    else
-    {                          /* Step through to the next comma or until the
-                                  end of the line, in an attempt to save CPU
-                                  -Kev */
-      while (*p != ',' && *p != '\0')
-       p++;
-      if (!*p)
-       break;
-    }
-
-  keysOrTS = parv[2];          /* Remember where our keys are or the TS is;
-                                  parv[2] needs to be NULL for the call to
-                                  m_names below -Kev */
-  parv[2] = p = NULL;
-
-  *jbuf = *mbuf = '\0';                /* clear both join and mode buffers -Kev */
-  /*
-   *  Rebuild list of channels joined to be the actual result of the
-   *  JOIN.  Note that "JOIN 0" is the destructive problem.
-   */
-  for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ","))
-  {
-    size_t len;
-    if (MyConnect(sptr))
-      clean_channelname(name);
-    else if (IsLocalChannel(name))
-      continue;
-    if (*name == '0' && *(name + 1) == '\0')
-    {
-      /* Remove the user from all his channels -Kev */
-      while ((lp = sptr->user->channel))
-      {
-       chptr = lp->value.chptr;
-       if (!is_zombie(sptr, chptr))
-         sendto_channel_butserv(chptr, sptr, PartFmt2,
-             parv[0], chptr->chname, "Left all channels");
-       remove_user_from_channel(sptr, chptr);
-      }
-      /* Just in case */
-      *mbuf = *jbuf = '\0';
-      mlen = jlen = 0;
-    }
-    else
-    {                          /* not a /join 0, so treat it as
-                                  a /join #channel -Kev */
-      if (!IsChannelName(name))
-      {
-       if (MyUser(sptr))
-         sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
-       continue;
-      }
-
-      if (MyConnect(sptr))
-      { 
-#ifdef BADCHAN
-        if(bad_channel(name) && !IsAnOper(sptr))
-        {
-         sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0],name);
-         continue;
-        }
-#endif
-
-       /*
-        * Local client is first to enter previously nonexistant
-        * channel so make them (rightfully) the Channel Operator.
-        * This looks kind of ugly because we try to avoid calling the strlen()
-        */
-       if (ChannelExists(name))
-       {
-         flags = CHFL_DEOPPED;
-         sendcreate = 0;
-       }
-       else if (strlen(name) > CHANNELLEN)
-       {
-         *(name + CHANNELLEN) = '\0';
-         if (ChannelExists(name))
-         {
-           flags = CHFL_DEOPPED;
-           sendcreate = 0;
-         }
-         else
-         {
-           flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
-           sendcreate = 1;
-         }
-       }
-       else
-       {
-         flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
-         sendcreate = 1;
-       }
-
-#ifdef OPER_NO_CHAN_LIMIT
-        /*
-         * Opers are allowed to join any number of channels
-         */
-        if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
-#else
-        if (sptr->user->joined >= MAXCHANNELSPERUSER)
-#endif
-       {
-         chptr = get_channel(sptr, name, !CREATE);
-         sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
-             me.name, parv[0], chptr ? chptr->chname : name);
-         break;                /* Can't return, else he won't get on ANY
-                                  channels!  Break out of the for loop instead.
-                                  -Kev */
-       }
-      }
-      chptr = get_channel(sptr, name, CREATE);
-      if (chptr && (lp = find_user_link(chptr->members, sptr)))
-      {
-       if (lp->flags & CHFL_ZOMBIE)
-       {
-         zombie = 1;
-         flags = lp->flags & (CHFL_DEOPPED | CHFL_SERVOPOK);
-         remove_user_from_channel(sptr, chptr);
-         chptr = get_channel(sptr, name, CREATE);
-       }
-       else
-         continue;
-      }
-      name = chptr->chname;
-      if (!chptr->creationtime)        /* A remote JOIN created this channel ? */
-       chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
-      if (parc > 2)
-      {
-       if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
-         chptr->creationtime = atoi(keysOrTS);
-       else
-         parc = 2;             /* Don't pass it on */
-      }
-      if (!zombie)
-      {
-       if (!MyConnect(sptr))
-         flags = CHFL_DEOPPED;
-       if (sptr->flags & FLAGS_TS8)
-         flags |= CHFL_SERVOPOK;
-      }
-      if (MyConnect(sptr))
-      {
-       int created = chptr->users == 0;
-       if (check_target_limit(sptr, chptr, chptr->chname, created))
-       {
-         if (created)          /* Did we create the channel? */
-           sub1_from_channel(chptr);   /* Remove it again! */
-         continue;
-       }
-       if ((i = can_join(sptr, chptr, keysOrTS)))
-       {
-#ifdef OPER_WALK_THROUGH_LMODES
-          if (i > MAGIC_OPER_OVERRIDE)
-          {
-            switch(i - MAGIC_OPER_OVERRIDE)
-            {
-              case ERR_CHANNELISFULL: i = 'l'; break;
-              case ERR_INVITEONLYCHAN: i = 'i'; break;
-              case ERR_BANNEDFROMCHAN: i = 'b'; break;
-              case ERR_BADCHANNELKEY: i = 'k'; break;
-            }
-            sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
-          }
-          else
-          {
-            sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
-            continue; 
-          }
-#else    
-          sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
-          continue;
-#endif
-       }
-      }
-      /*
-       * Complete user entry to the new channel (if any)
-       */
-      add_user_to_channel(chptr, sptr, flags);
-
-      /*
-       * Notify all other users on the new channel
-       */
-      sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
-
-      if (MyUser(sptr))
-      {
-       del_invite(sptr, chptr);
-       if (chptr->topic[0] != '\0')
-       {
-         sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
-             parv[0], name, chptr->topic);
-         sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
-             chptr->topic_nick, chptr->topic_time);
-       }
-       parv[1] = name;
-       m_names(cptr, sptr, 2, parv);
-      }
-    }
-
-    /* Select proper buffer; mbuf for creation, jbuf otherwise */
-
-    if (*name == '&')
-      continue;                        /* Head off local channels at the pass */
-
-    bufptr = (sendcreate == 0) ? jbuf : mbuf;
-    buflen = (sendcreate == 0) ? &jlen : &mlen;
-    len = strlen(name);
-    if (*buflen < BUFSIZE - len - 2)
-    {
-      if (*bufptr)
-      {
-       strcat(bufptr, ",");    /* Add to join buf */
-       *buflen += 1;
-      }
-      strncat(bufptr, name, BUFSIZE - *buflen - 1);
-      *buflen += len;
-    }
-    sendcreate = 0;            /* Reset sendcreate */
-  }
-
-#ifndef NO_PROTOCOL9
-  if (*jbuf || *mbuf)          /* Propagate joins to P09 servers */
-    sendto_lowprot_butone(cptr, 9, (*jbuf && *mbuf) ? ":%s JOIN %s,%s" :
-       ":%s JOIN %s%s", parv[0], jbuf, mbuf);
-#endif
-
-  if (*jbuf)                   /* Propgate joins to P10 servers */
-#ifdef NO_PROTOCOL9
-    sendto_serv_butone(cptr,
-       parc > 2 ? ":%s JOIN %s %s" : ":%s JOIN %s", parv[0], jbuf, keysOrTS);
-#else
-    sendto_highprot_butone(cptr, 10,
-       parc > 2 ? ":%s JOIN %s %s" : ":%s JOIN %s", parv[0], jbuf, keysOrTS);
-#endif
-  if (*mbuf)                   /* and now creation events */
-#ifdef NO_PROTOCOL9
-    sendto_serv_butone(cptr, "%s%s CREATE %s " TIME_T_FMT,
-       NumNick(sptr), mbuf, TStime());
-#else
-    sendto_highprot_butone(cptr, 10, "%s%s CREATE %s " TIME_T_FMT,
-       NumNick(sptr), mbuf, TStime());
-#endif
-
-  if (MyUser(sptr))
-  {                            /* shouldn't ever set TS for remote JOIN's */
-    if (*jbuf)
-    {                          /* check for channels that need TS's */
-      p = NULL;
-      for (name = strtoken(&p, jbuf, ","); name; name = strtoken(&p, NULL, ","))
-      {
-       chptr = get_channel(sptr, name, !CREATE);
-       if (chptr && chptr->mode.mode & MODE_SENDTS)
-       {                       /* send a TS? */
-         sendto_serv_butone(cptr, ":%s MODE %s + " TIME_T_FMT, me.name,
-             chptr->chname, chptr->creationtime);      /* ok, send TS */
-         chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
-       }
-      }
-    }
-
-    if (*mbuf)
-    {                          /* ok, send along modes for creation events to P9 */
-      p = NULL;
-      for (name = strtoken(&p, mbuf, ","); name; name = strtoken(&p, NULL, ","))
-      {
-       chptr = get_channel(sptr, name, !CREATE);
-       sendto_lowprot_butone(cptr, 9, ":%s MODE %s +o %s " TIME_T_FMT,
-           me.name, chptr->chname, parv[0], chptr->creationtime);
-      }
-    }
-  }
-  return 0;
-}
-
-/*
- * m_destruct
- *
- * parv[0] = sender prefix
- * parv[1] = channel channelname
- * parv[2] = channel time stamp
- *
- * This function does nothing, it does passes DESTRUCT to the other servers.
- * In the future we will start to use this message.
- *
- */
-int m_destruct(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  time_t chanTS;               /* Creation time of the channel */
-
-  if (parc < 3 || *parv[2] == '\0')
-    return 0;
-
-#ifdef GODMODE
-  /* Allow DESTRUCT from user */
-  if (MyUser(sptr))
-    sptr = &me;
-  else
-#endif
-
-    /* sanity checks: Only accept DESTRUCT messages from servers */
-  if (!IsServer(sptr))
-    return 0;
-
-  /* Don't pass on DESTRUCT messages for channels that exist */
-  if (FindChannel(parv[1]))
-    return 0;
-
-  chanTS = atoi(parv[2]);
-
-  /* Pass on DESTRUCT message */
-  sendto_highprot_butone(cptr, 10, "%s DESTRUCT %s " TIME_T_FMT,
-      NumServ(sptr), parv[1], chanTS);
-
-  return 0;
-}
-
-/*
- * m_create
- *
- * parv[0] = sender prefix
- * parv[1] = channel names
- * parv[2] = channel time stamp
- */
-int m_create(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  char cbuf[BUFSIZE];          /* Buffer for list with channels
-                                  that `sptr' really creates */
-  time_t chanTS;               /* Creation time for all channels
-                                  in the comma seperated list */
-  char *p, *name;
-  Reg5 aChannel *chptr;
-  int badop;
-
-  /* sanity checks: Only accept CREATE messages from servers */
-  if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
-    return 0;
-
-  chanTS = atoi(parv[2]);
-
-  *cbuf = '\0';                        /* Start with empty buffer */
-
-  /* For each channel in the comma seperated list: */
-  for (name = strtoken(&p, parv[1], ","); name; name = strtoken(&p, NULL, ","))
-  {
-    badop = 0;                 /* Default is to accept the op */
-    if ((chptr = FindChannel(name)))
-    {
-      name = chptr->chname;
-      if (TStime() - chanTS > TS_LAG_TIME)
-      {
-       /* A bounce would not be accepted anyway - if we get here something
-          is wrong with the TS clock syncing (or we have more then
-          TS_LAG_TIME lag, or an admin is hacking */
-       badop = 2;
-       /* This causes a HACK notice on all upstream servers: */
-       if (Protocol(cptr) < 10)
-         sendto_one(cptr, ":%s MODE %s -o %s 0", me.name, name, sptr->name);
-       else
-         sendto_one(cptr, ":%s MODE %s -o %s%s 0",
-             me.name, name, NumNick(sptr));
-       /* This causes a WALLOPS on all downstream servers and a notice to our
-          own opers: */
-       parv[1] = name;         /* Corrupt parv[1], it is not used anymore anyway */
-       send_hack_notice(cptr, sptr, parc, parv, badop, 2);
-      }
-      else if (chptr->creationtime && chanTS > chptr->creationtime &&
-         chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
-      {
-       /* We (try) to bounce the mode, because the CREATE is used on an older
-          channel, probably a net.ride */
-       badop = 1;
-       /* Send a deop upstream: */
-       if (Protocol(cptr) < 10)
-         sendto_one(cptr, ":%s MODE %s -o %s " TIME_T_FMT, me.name,
-             name, sptr->name, chptr->creationtime);
-       else
-         sendto_one(cptr, ":%s MODE %s -o %s%s " TIME_T_FMT, me.name,
-             name, NumNick(sptr), chptr->creationtime);
-      }
-    }
-    else                       /* Channel doesn't exist: create it */
-      chptr = get_channel(sptr, name, CREATE);
-
-    /* Add and mark ops */
-    add_user_to_channel(chptr, sptr,
-       (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
-
-    /* Send user join to the local clients (if any) */
-    sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
-
-    if (badop)                 /* handle badop: convert CREATE into JOIN */
-      sendto_serv_butone(cptr, ":%s JOIN %s " TIME_T_FMT,
-         sptr->name, name, chptr->creationtime);
-    else
-    {
-      /* Send the op to local clients:
-         (if any; extremely unlikely, but it CAN happen) */
-      if (!IsModelessChannel(name))
-       sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
-           sptr->user->server->name, name, parv[0]);
-
-      /* Set/correct TS and add the channel to the
-         buffer for accepted channels: */
-      chptr->creationtime = chanTS;
-      if (*cbuf)
-       strcat(cbuf, ",");
-      strcat(cbuf, name);
-    }
-  }
-
-  if (*cbuf)                   /* Any channel accepted with ops ? */
-  {
-#ifdef NO_PROTOCOL9
-    sendto_serv_butone(cptr, "%s%s CREATE %s " TIME_T_FMT,
-       NumNick(sptr), cbuf, chanTS);
-#else
-    /* send CREATEs to 2.10 servers */
-    sendto_highprot_butone(cptr, 10, "%s%s CREATE %s " TIME_T_FMT,
-       NumNick(sptr), cbuf, chanTS);
-
-    /* And JOIN + MODE to 2.9 servers; following
-       is not needed after all are 2.10 */
-    sendto_lowprot_butone(cptr, 9, ":%s JOIN %s", parv[0], cbuf);
-    p = NULL;
-    for (name = strtoken(&p, cbuf, ","); name; name = strtoken(&p, NULL, ","))
-      sendto_lowprot_butone(cptr, 9, ":%s MODE %s +o %s " TIME_T_FMT,
-         sptr->user->server->name, name, parv[0], chanTS);
-#endif
-  }
-
-  return 0;
-}
-
-static size_t prefix_len;
-
-static void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
-    int *send_itp, char is_a_ban, int mode)
-{
-  int first = *firstp;
+  int first = *firstp;
 
   /*
    * Heh - we do not need to test if it still fits in the buffer, because
@@ -2723,1027 +2312,108 @@ static void add_token_to_sendbuf(char *token, size_t *sblenp, int *firstp,
    * it only can become smaller. --Run
    */
 
-  if (*firstp)                 /* First token in this parameter ? */
+  if (*firstp)                  /* First token in this parameter ? */
   {
     *firstp = 0;
     if (*send_itp == 0)
-      *send_itp = 1;           /* Buffer contains data to be sent */
+      *send_itp = 1;            /* Buffer contains data to be sent */
     sendbuf[(*sblenp)++] = ' ';
     if (is_a_ban)
     {
-      sendbuf[(*sblenp)++] = ':';      /* Bans are always the last "parv" */
+      sendbuf[(*sblenp)++] = ':';       /* Bans are always the last "parv" */
       sendbuf[(*sblenp)++] = is_a_ban;
     }
   }
-  else                         /* Of course, 'send_it' is already set here */
+  else                          /* Of course, 'send_it' is already set here */
     /* Seperate banmasks with a space because
        they can contain commas themselfs: */
     sendbuf[(*sblenp)++] = is_a_ban ? ' ' : ',';
   strcpy(sendbuf + *sblenp, token);
   *sblenp += strlen(token);
-  if (!is_a_ban)               /* nick list ? Need to take care
-                                  of modes for nicks: */
+  if (!is_a_ban)                /* nick list ? Need to take care
+                                   of modes for nicks: */
   {
     static int last_mode = 0;
     mode &= CHFL_CHANOP | CHFL_VOICE;
     if (first)
       last_mode = 0;
-    if (last_mode != mode)     /* Append mode like ':ov' if changed */
+    if (last_mode != mode)      /* Append mode like ':ov' if changed */
     {
       last_mode = mode;
       sendbuf[(*sblenp)++] = ':';
       if (mode & CHFL_CHANOP)
-       sendbuf[(*sblenp)++] = 'o';
+        sendbuf[(*sblenp)++] = 'o';
       if (mode & CHFL_VOICE)
-       sendbuf[(*sblenp)++] = 'v';
+        sendbuf[(*sblenp)++] = 'v';
     }
     sendbuf[*sblenp] = '\0';
   }
 }
 
-static void cancel_mode(aClient *sptr, aChannel *chptr, char m,
-    const char *param, int *count)
+void cancel_mode(struct Client *sptr, struct Channel *chptr, char m,
+                        const char *param, int *count)
 {
-  static char *pb, *sbp, *sbpi;
-  int paramdoesntfit = 0;
-  if (*count == -1)            /* initialize ? */
+  static char* pb;
+  static char* sbp;
+  static char* sbpi;
+  int          paramdoesntfit = 0;
+  char parabuf[MODEBUFLEN];
+
+  assert(0 != sptr);
+  assert(0 != chptr);
+  assert(0 != count);
+  
+  if (*count == -1)             /* initialize ? */
   {
     sbp = sbpi =
-       sprintf_irc(sendbuf, ":%s MODE %s -", sptr->name, chptr->chname);
+        sprintf_irc(sendbuf, ":%s MODE %s -", sptr->name, chptr->chname);
     pb = parabuf;
     *count = 0;
   }
-  /* m == 0 means flush */
-  if (m)
-  {
-    if (param)
-    {
-      size_t nplen = strlen(param);
-      if (pb - parabuf + nplen + 23 > MODEBUFLEN)
-       paramdoesntfit = 1;
-      else
-      {
-       *sbp++ = m;
-       *pb++ = ' ';
-       strcpy(pb, param);
-       pb += nplen;
-       ++*count;
-      }
-    }
-    else
-      *sbp++ = m;
-  }
-  else if (*count == 0)
-    return;
-  if (*count == 6 || !m || paramdoesntfit)
-  {
-#ifndef NO_PROTOCOL9
-    Dlink *lp;
-    char *sbe;
-#endif
-    Link *member;
-    strcpy(sbp, parabuf);
-#ifndef NO_PROTOCOL9
-    sbe = sbp + strlen(parabuf);
-#endif
-    for (member = chptr->members; member; member = member->next)
-      if (MyUser(member->value.cptr))
-       sendbufto_one(member->value.cptr);
-#ifndef NO_PROTOCOL9
-    sprintf_irc(sbe, " " TIME_T_FMT, chptr->creationtime);
-    /* Send 'sendbuf' to all 2.9 downlinks: */
-    for (lp = me.serv->down; lp; lp = lp->next)
-      if (Protocol(lp->value.cptr) < 10)
-       sendbufto_one(lp->value.cptr);
-#endif
-    sbp = sbpi;
-    pb = parabuf;
-    *count = 0;
-  }
-  if (paramdoesntfit)
-  {
-    *sbp++ = m;
-    *pb++ = ' ';
-    strcpy(pb, param);
-    pb += strlen(param);
-    ++*count;
-  }
-}
-
-/*
- * m_burst  --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
- *
- * parv[0] = sender prefix
- * parv[1] = channel name
- * parv[2] = channel timestamp
- * The meaning of the following parv[]'s depend on their first character:
- * If parv[n] starts with a '+':
- * Net burst, additive modes
- *   parv[n] = <mode>
- *   parv[n+1] = <param> (optional)
- *   parv[n+2] = <param> (optional)
- * If parv[n] starts with a '%', then n will be parc-1:
- *   parv[n] = %<ban> <ban> <ban> ...
- * If parv[n] starts with another character:
- *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
- *   where <mode> is the channel mode (ov) of nick and all following nicks.
- *
- * Example:
- * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
- *
- * Anti net.ride code.
- *
- * When the channel already exist, and its TS is larger then
- * the TS in the BURST message, then we cancel all existing modes.
- * If its is smaller then the received BURST message is ignored.
- * If it's equal, then the received modes are just added.
- */
-int m_burst(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 aChannel *chptr;
-  time_t timestamp;
-  int netride = 0, wipeout = 0, n;
-  int send_it = 0, add_banid_not_called = 1;
-  Mode *current_mode;
-  size_t sblen, mblen = 0;
-  int mblen2, pblen2, cnt;
-  int prev_mode;
-  char prev_key[KEYLEN + 1];
-  Link *lp;
-#ifndef NO_PROTOCOL9
-  int ts_sent = 0;
-#endif
-
-  /* BURST is only for servers and has at least 4 parameters */
-  if (!IsServer(cptr) || parc < 4)
-    return 0;
-
-  if (!IsBurst(sptr))
-  {
-    int i;
-    char *p;
-    if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
-    {
-      p =
-         sprintf_irc(sendbuf,
-         ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
-         sptr->name, parv[1], parv[2]);
-      for (i = 3; i < parc - 1; ++i)
-       p = sprintf_irc(p, " %s", parv[i]);
-      sprintf_irc(p, " :%s", parv[parc - 1]);
-      sendbufto_op_mask(SNO_HACK4);
-    }
-    else
-    {
-#if 1                          /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
-      SetBurst(sptr);
-      if (MyConnect(sptr))
-#endif
-       return exit_client_msg(cptr, cptr, &me,
-           "HACK: BURST message outside net.burst from %s", sptr->name);
-    }
-  }
-
-  /* Find the channel, or create it - note that the creation time
-   * will be 0 if it has to be created */
-  chptr = get_channel(sptr, parv[1], CREATE);
-  current_mode = &chptr->mode;
-  prev_mode = chptr->mode.mode;
-  if (*chptr->mode.key)
-  {
-    prev_mode |= MODE_KEY;
-    strcpy(prev_key, chptr->mode.key);
-  }
-  if (chptr->mode.limit)
-    prev_mode |= MODE_LIMIT;
-
-  timestamp = atoi(parv[2]);
-
-  /* Copy the new TS when the received creationtime appears to be older */
-  if (!chptr->creationtime || chptr->creationtime > timestamp)
-  {
-    /* Set the new timestamp */
-    chptr->creationtime = timestamp;
-    send_it = 1;               /* Make sure we pass on the different timestamp ! */
-    /* Mark all bans as needed to be wiped out */
-    for (lp = chptr->banlist; lp; lp = lp->next)
-      lp->flags |= CHFL_BURST_BAN_WIPEOUT;
-    /*
-     * Only the first BURST for this channel can have creationtime > timestamp,
-     * so at this moment ALL members are on OUR side, and thus all net.riders:
-     */
-    wipeout = 1;
-  }
-  for (lp = chptr->members; lp; lp = lp->next)
-    lp->flags &= ~CHFL_BURST_JOINED;   /* Set later for nicks in the BURST msg */
-  /* If `wipeout' is set then these will be deopped later. */
-
-  /* If the entering creationtime is younger, ignore the modes */
-  if (chptr->creationtime < timestamp)
-    netride = 1;               /* Only pass on the nicks (so they JOIN) */
-
-  /* Prepare buffers to pass the message */
-  *bparambuf = *bmodebuf = *parabuf = '\0';
-  pblen2 = 0;
-  *modebuf = '+';
-  mblen2 = 1;
-  cnt = 0;
-  prefix_len = sblen = sprintf_irc(sendbuf, "%s BURST %s " TIME_T_FMT,
-      NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
-
-  /* Run over all remaining parameters */
-  for (n = 3; n < parc; n++)
-    switch (*parv[n])          /* What type is it ? mode, nicks or bans ? */
-    {
-      case '+':                /* modes */
-      {
-       char *p = parv[n];
-       while (*(++p))          /* Run over all mode characters */
-       {
-         switch (*p)           /* which mode ? */
-         {
-             /*
-              * The following cases all do the following:
-              * - In case wipeout needed, reset 'prev_mode' to indicate this
-              *   mode should not be cancelled.
-              * - If wipeout or (not netride and the new mode is a change),
-              *   add it to bmodebuf and bparabuf for propagation.
-              * - Else ignore it.
-              * - Add it to modebuf and parabuf for propagation to the
-              *   clients when not netride and the new mode is a change.
-              * Special cases:
-              * - If a +s is received, cancel a +p and sent a -p to the
-              *   clients too (if +p was set).
-              * - If a +p is received and +s is set, ignore the +p.
-              */
-           case 'i':
-           {
-             register int tmp;
-             prev_mode &= ~MODE_INVITEONLY;
-             if (!(tmp = netride ||
-                 (current_mode->mode & MODE_INVITEONLY)) || wipeout)
-             {
-               bmodebuf[mblen++] = 'i';
-               current_mode->mode |= MODE_INVITEONLY;
-             }
-             if (!tmp)
-               modebuf[mblen2++] = 'i';
-             break;
-           }
-           case 'k':
-           {
-             register int tmp;
-             char *param = parv[++n];
-             prev_mode &= ~MODE_KEY;
-             if (!(tmp = netride || (*current_mode->key &&
-                 (!strcmp(current_mode->key, param) ||
-                 (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
-                 wipeout)
-             {
-               bmodebuf[mblen++] = 'k';
-               strcat(bparambuf, " ");
-               strcat(bparambuf, param);
-               strncpy(current_mode->key, param, KEYLEN);
-             }
-             if (!tmp && !wipeout)
-             {
-               modebuf[mblen2++] = 'k';
-               parabuf[pblen2++] = ' ';
-               strcpy(parabuf + pblen2, param);
-               pblen2 += strlen(param);
-               cnt++;
-             }
-             break;
-           }
-           case 'l':
-           {
-             register int tmp;
-             unsigned int param = atoi(parv[++n]);
-             prev_mode &= ~MODE_LIMIT;
-             if (!(tmp = netride || (current_mode->limit &&
-                 (current_mode->limit == param ||
-                 (!wipeout && current_mode->limit < param)))) || wipeout)
-             {
-               bmodebuf[mblen++] = 'l';
-               sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
-               current_mode->limit = param;
-             }
-             if (!tmp)
-             {
-               modebuf[mblen2++] = 'l';
-               pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
-               cnt++;
-             }
-             break;
-           }
-           case 'm':
-           {
-             register int tmp;
-             prev_mode &= ~MODE_MODERATED;
-             if (!(tmp = netride ||
-                 (current_mode->mode & MODE_MODERATED)) || wipeout)
-             {
-               bmodebuf[mblen++] = 'm';
-               current_mode->mode |= MODE_MODERATED;
-             }
-             if (!tmp)
-               modebuf[mblen2++] = 'm';
-             break;
-           }
-           case 'n':
-           {
-             register int tmp;
-             prev_mode &= ~MODE_NOPRIVMSGS;
-             if (!(tmp = netride ||
-                 (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
-             {
-               bmodebuf[mblen++] = 'n';
-               current_mode->mode |= MODE_NOPRIVMSGS;
-             }
-             if (!tmp)
-               modebuf[mblen2++] = 'n';
-             break;
-           }
-           case 'p':
-           {
-             register int tmp;
-
-             /* Special case: */
-             if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
-               break;
-
-             prev_mode &= ~MODE_PRIVATE;
-             if (!(tmp = netride ||
-                 (current_mode->mode & MODE_PRIVATE)) || wipeout)
-             {
-               bmodebuf[mblen++] = 'p';
-               current_mode->mode |= MODE_PRIVATE;
-             }
-             if (!tmp)
-               modebuf[mblen2++] = 'p';
-             break;
-           }
-           case 's':
-           {
-             register int tmp;
-             prev_mode &= ~MODE_SECRET;
-             if (!(tmp = netride ||
-                 (current_mode->mode & MODE_SECRET)) || wipeout)
-             {
-               bmodebuf[mblen++] = 's';
-               current_mode->mode |= MODE_SECRET;
-             }
-             if (!tmp)
-               modebuf[mblen2++] = 's';
-
-             /* Special case: */
-             if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
-             {
-               int i;
-               for (i = mblen2 - 1; i >= 0; --i)
-                 modebuf[i + 2] = modebuf[i];
-               modebuf[0] = '-';
-               modebuf[1] = 'p';
-               mblen2 += 2;
-               current_mode->mode &= ~MODE_PRIVATE;
-             }
-
-             break;
-           }
-           case 't':
-           {
-             register int tmp;
-             prev_mode &= ~MODE_TOPICLIMIT;
-             if (!(tmp = netride ||
-                 (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
-             {
-               bmodebuf[mblen++] = 't';
-               current_mode->mode |= MODE_TOPICLIMIT;
-             }
-             if (!tmp)
-               modebuf[mblen2++] = 't';
-             break;
-           }
-         }
-       }                       /* <-- while over all modes */
-
-       bmodebuf[mblen] = '\0';
-       sendbuf[sblen] = '\0';
-       if (mblen)              /* Anything to send at all ? */
-       {
-         send_it = 1;
-         strcpy(sendbuf + sblen, " +");
-         sblen += 2;
-         strcpy(sendbuf + sblen, bmodebuf);
-         sblen += mblen;
-         strcpy(sendbuf + sblen, bparambuf);
-         sblen += strlen(bparambuf);
-       }
-       break;                  /* Done mode part */
-      }
-      case '%':                /* bans */
-      {
-       char *pv, *p = NULL, *ban;
-       int first = 1;
-       if (netride)
-         break;                /* Ignore bans */
-       /* Run over all bans */
-       for (pv = parv[n] + 1; (ban = strtoken(&p, pv, " ")); pv = NULL)
-       {
-         int ret;
-         /*
-          * The following part should do the following:
-          * - If the new (un)ban is not a _change_ it is ignored.
-          * - Else, add it to sendbuf for later use.
-          * - If sendbuf is full, send it, and prepare a new
-          *   message in sendbuf.
-          */
-         ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
-         if (ret == 0)
-         {
-           add_banid_not_called = 0;
-           /* Mark this new ban so we can send it to the clients later */
-           chptr->banlist->flags |= CHFL_BURST_BAN;
-         }
-         if (ret != -1)
-           /* A new ban was added or an existing one needs to be passed on.
-            * Also add it to sendbuf: */
-           add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
-       }
-       break;                  /* Done bans part */
-      }
-      default:                 /* nicks */
-      {
-       char *pv, *p = NULL, *nick, *ptr;
-       int first = 1;
-       /* Default mode: */
-       int default_mode = CHFL_DEOPPED;
-       /* Run over all nicks */
-       for (pv = parv[n]; (nick = strtoken(&p, pv, ",")); pv = NULL)
-       {
-         aClient *acptr;
-         if ((ptr = strchr(nick, ':')))        /* New default mode ? */
-         {
-           *ptr = '\0';        /* Fix 'nick' */
-           acptr = findNUser(nick);
-           if (!netride)
-           {
-             /* Calculate new mode change: */
-             default_mode = CHFL_DEOPPED;
-             while (*(++ptr))
-               if (*ptr == 'o')
-               {
-                 default_mode |= CHFL_CHANOP;
-                 default_mode &= ~CHFL_DEOPPED;
-               }
-               else if (*ptr == 'v')
-                 default_mode |= CHFL_VOICE;
-               else
-                 break;
-           }
-         }
-         else
-           acptr = findNUser(nick);
-         /*
-          * Note that at this point we already received a 'NICK' for any
-          * <nick> numeric that is joining (and possibly opped) here.
-          * Therefore we consider the following situations:
-          * - The <nick> numeric exists and is from the direction of cptr: ok
-          * - The <nick> numeric does not exist:
-          *   Apparently this previous <nick> numeric was killed (upstream)
-          *   or it collided with an existing <nick> name.
-          * - The <nick> numeric exists but is from another direction:
-          *   Apparently this previous <nick> numeric was killed,
-          *   and due to a reroute it signed on via another link (probably
-          *   a nick [numeric] collision).
-          * Note that it can't be a QUIT or SQUIT, because a QUIT would
-          * come from the same direction as the BURST (cptr) while an
-          * upstream SQUIT removes the source (server) and we would thus
-          * have this BURST ignored already.
-          * This means that if we find the nick and it is from the correct
-          * direction, it joins. If it doesn't exist or is from another
-          * direction, we have to ignore it. If all nicks are ignored, we
-          * remove the channel again when it is empty and don't propagate
-          * the BURST message.
-          */
-         if (acptr && acptr->from == cptr)
-         {
-           /*
-            * The following should do the following:
-            * - Add it to sendbuf for later use.
-            * - If sendbuf is full, send it, and prepare a new
-            *   message in sendbuf.
-            */
-           add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
-               default_mode);
-           /* Let is take effect: (Note that in the case of a netride
-            * 'default_mode' is always CHFL_DEOPPED here). */
-           add_user_to_channel(chptr, acptr, default_mode);
-           chptr->members->flags |= CHFL_BURST_JOINED;
-         }
-       }                       /* <-- Next nick */
-       if (!chptr->members)    /* All nicks collided and channel is empty ? */
-       {
-         sub1_from_channel(chptr);
-         return 0;             /* Forget about the (rest of the) message... */
-       }
-       break;                  /* Done nicks part */
-      }
-    }                          /* <-- Next parameter if any */
-  if (!chptr->members)         /* This message only contained bans (then the previous
-                                  message only contained collided nicks, see above) */
-  {
-    sub1_from_channel(chptr);
-    if (!add_banid_not_called)
-      while (next_removed_overlapped_ban());
-    return 0;                  /* Forget about the (rest of the) message... */
-  }
-
-  /* The last (possibly only) message is always send here */
-  if (send_it)                 /* Anything (left) to send ? */
-  {
-    Dlink *lp;
-    Link *member;
-
-    /* send 'sendbuf' to all downlinks */
-    for (lp = me.serv->down; lp; lp = lp->next)
-    {
-      if (lp->value.cptr == cptr)
-       continue;
-      if (Protocol(lp->value.cptr) > 9)
-       sendbufto_one(lp->value.cptr);
-    }
-
-    /*
-     * Now we finally can screw sendbuf again...
-     * Send all changes to the local clients:
-     *
-     * First send all joins and op them, because 2.9 servers
-     * would protest with a HACK if we first de-opped people.
-     * However, we don't send the +b bans yes, because we
-     * DO first want to -b the old bans (otherwise it's confusing).
-     */
-
-    /* Send all joins: */
-    for (member = chptr->members; member; member = member->next)
-      if (member->flags & CHFL_BURST_JOINED)
-      {
-       sendto_channel_butserv(chptr, member->value.cptr, ":%s JOIN :%s",
-           member->value.cptr->name, chptr->chname);
-#ifndef NO_PROTOCOL9
-       /* And to 2.9 servers: */
-       sendto_lowprot_butone(cptr, 9, ":%s JOIN %s",
-           member->value.cptr->name, chptr->chname);
-#endif
-      }
-
-    if (!netride)
-    {
-      /* Send all +o and +v modes: */
-      for (member = chptr->members; member; member = member->next)
-      {
-       if ((member->flags & CHFL_BURST_JOINED))
-       {
-         int mode = CHFL_CHANOP;
-         for (;;)
-         {
-           if ((member->flags & mode))
-           {
-             modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
-             parabuf[pblen2++] = ' ';
-             strcpy(parabuf + pblen2, member->value.cptr->name);
-             pblen2 += strlen(member->value.cptr->name);
-             if (6 == ++cnt)
-             {
-               modebuf[mblen2] = 0;
-               sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
-                   parv[0], chptr->chname, modebuf, parabuf);
-#ifndef NO_PROTOCOL9
-               sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
-                   parv[0], chptr->chname, modebuf, parabuf,
-                   chptr->creationtime);
-               ts_sent = 1;
-#endif
-               *parabuf = 0;
-               pblen2 = 0;
-               mblen2 = 1;
-               cnt = 0;
-             }
-           }
-           if (mode == CHFL_CHANOP)
-             mode = CHFL_VOICE;
-           else
-             break;
-         }
-       }
-      }
-      /* Flush MODEs: */
-      if (cnt > 0 || mblen2 > 1)
-      {
-       modebuf[mblen2] = 0;
-       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
-           parv[0], chptr->chname, modebuf, parabuf);
-#ifndef NO_PROTOCOL9
-       sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
-           parv[0], chptr->chname, modebuf, parabuf, chptr->creationtime);
-       ts_sent = 1;
-#endif
-      }
-#ifndef NO_PROTOCOL9
-      else if (send_it && !ts_sent)
-      {
-       sendto_lowprot_butone(cptr, 9, ":%s MODE %s + " TIME_T_FMT,
-           parv[0], chptr->chname, chptr->creationtime);
-       ts_sent = 1;
-      }
-#endif
-    }
-  }
-
-  if (wipeout)
-  {
-    Link *lp;
-    Link **ban;
-    int mode;
-    char m;
-    int count = -1;
-
-    /* Now cancel all previous simple modes */
-    if ((prev_mode & MODE_SECRET))
-      cancel_mode(sptr, chptr, 's', NULL, &count);
-    if ((prev_mode & MODE_PRIVATE))
-      cancel_mode(sptr, chptr, 'p', NULL, &count);
-    if ((prev_mode & MODE_MODERATED))
-      cancel_mode(sptr, chptr, 'm', NULL, &count);
-    if ((prev_mode & MODE_TOPICLIMIT))
-      cancel_mode(sptr, chptr, 't', NULL, &count);
-    if ((prev_mode & MODE_INVITEONLY))
-      cancel_mode(sptr, chptr, 'i', NULL, &count);
-    if ((prev_mode & MODE_NOPRIVMSGS))
-      cancel_mode(sptr, chptr, 'n', NULL, &count);
-    if ((prev_mode & MODE_LIMIT))
-    {
-      current_mode->limit = 0;
-      cancel_mode(sptr, chptr, 'l', NULL, &count);
-    }
-    if ((prev_mode & MODE_KEY))
-    {
-      *current_mode->key = 0;
-      cancel_mode(sptr, chptr, 'k', prev_key, &count);
-    }
-    current_mode->mode &= ~prev_mode;
-
-    /* And deop and devoice all net.riders on my side */
-    mode = CHFL_CHANOP;
-    m = 'o';
-    for (;;)
-    {
-      for (lp = chptr->members; lp; lp = lp->next)
-      {
-       if ((lp->flags & CHFL_BURST_JOINED))
-         continue;             /* This is not a net.rider from
-                                  this side of the net.junction */
-       if ((lp->flags & mode))
-       {
-         lp->flags &= ~mode;
-         if (mode == CHFL_CHANOP)
-           lp->flags |= CHFL_DEOPPED;
-         cancel_mode(sptr, chptr, m, lp->value.cptr->name, &count);
-       }
-      }
-      if (mode == CHFL_VOICE)
-       break;
-      mode = CHFL_VOICE;
-      m = 'v';
-    }
-
-    /* And finally wipeout all bans that are left */
-    for (ban = &chptr->banlist; *ban;)
-    {
-      Link *tmp = *ban;
-      if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT))
-      {
-       cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
-       /* Copied from del_banid(): */
-       *ban = tmp->next;
-       RunFree(tmp->value.ban.banstr);
-       RunFree(tmp->value.ban.who);
-       free_link(tmp);
-       /* Erase ban-valid-bit, for channel members that are banned */
-       for (tmp = chptr->members; tmp; tmp = tmp->next)
-         if ((tmp->flags & (CHFL_BANNED | CHFL_BANVALID)) ==
-             (CHFL_BANNED | CHFL_BANVALID))
-           tmp->flags &= ~CHFL_BANVALID;       /* `tmp' == channel member */
-      }
-      else
-       ban = &tmp->next;
-    }
-    /* Also wipeout overlapped bans */
-    if (!add_banid_not_called)
-    {
-      Link *ban;
-      while ((ban = next_removed_overlapped_ban()))
-       cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
-    }
-    cancel_mode(sptr, chptr, 0, NULL, &count); /* flush */
-  }
-
-  if (send_it && !netride)
-  {
-    Link *bl;
-    int deban;
-
-    if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
-    {
-      deban = 0;
-      bl = chptr->banlist;
-      *modebuf = '+';
-    }
-    else
-    {
-      deban = 1;
-      *modebuf = '-';
-    }
-
-    mblen2 = 1;
-    pblen2 = 0;
-    cnt = 0;
-    for (;;)
-    {
-      size_t nblen = 0;
-      if (bl)
-       nblen = strlen(bl->value.ban.banstr);
-      if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN)        /* The last check is to make sure
-                                                                          that the receiving 2.9 will
-                                                                          still process this */
-      {
-       /* Time to send buffer */
-       modebuf[mblen2] = 0;
-       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
-           parv[0], chptr->chname, modebuf, parabuf);
-#ifndef NO_PROTOCOL9
-       sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s",
-           parv[0], chptr->chname, modebuf, parabuf);
-#endif
-       *modebuf = deban ? '-' : '+';
-       mblen2 = 1;
-       pblen2 = 0;
-       cnt = 0;
-      }
-      if (!bl)                 /* Done ? */
-       break;
-      if (deban || (bl->flags & CHFL_BURST_BAN))
-      {
-       /* Add ban to buffers and remove it */
-       modebuf[mblen2++] = 'b';
-       parabuf[pblen2++] = ' ';
-       strcpy(parabuf + pblen2, bl->value.ban.banstr);
-       pblen2 += nblen;
-       cnt++;
-       bl->flags &= ~CHFL_BURST_BAN;
-      }
-      if (deban)
-      {
-       if (!(bl = next_removed_overlapped_ban()))
-       {
-         deban = 0;
-         modebuf[mblen2++] = '+';
-         bl = chptr->banlist;
-       }
-      }
-      else
-       bl = bl->next;
-    }
-    /* Flush MODE [-b]+b ...: */
-    if (cnt > 0 || mblen2 > 1)
-    {
-      modebuf[mblen2] = 0;
-      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
-         parv[0], chptr->chname, modebuf, parabuf);
-#ifndef NO_PROTOCOL9
-      sendto_lowprot_butone(cptr, 9, ":%s MODE %s %s%s " TIME_T_FMT,
-         parv[0], chptr->chname, modebuf, parabuf, chptr->creationtime);
-#endif
-    }
-#ifndef NO_PROTOCOL9
-    else if (send_it && !ts_sent)
-      sendto_lowprot_butone(cptr, 9, ":%s MODE %s + " TIME_T_FMT,
-         parv[0], chptr->chname, chptr->creationtime);
-#endif
-  }
-
-  return 0;
-}
-
-/*
- * m_part
- *
- * parv[0] = sender prefix
- * parv[1] = channel
- * parv[parc - 1] = comment
- */
-int m_part(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 aChannel *chptr;
-  Reg2 Link *lp;
-  char *p = NULL, *name, pbuf[BUFSIZE];
-  char *comment = (parc > 2 && !BadPtr(parv[parc - 1])) ? parv[parc - 1] : NULL;
-
-  *pbuf = '\0';                        /* Initialize the part buffer... -Kev */
-
-  sptr->flags &= ~FLAGS_TS8;
-
-  if (parc < 2 || parv[1][0] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PART");
-    return 0;
-  }
-
-  for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
-  {
-    chptr = get_channel(sptr, name, !CREATE);
-    if (!chptr)
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
-      continue;
-    }
-    if (*name == '&' && !MyUser(sptr))
-      continue;
-    /* Do not use IsMember here: zombies must be able to part too */
-    if (!(lp = find_user_link(chptr->members, sptr)))
-    {
-      /* Normal to get when our client did a kick
-         for a remote client (who sends back a PART),
-         so check for remote client or not --Run */
-      if (MyUser(sptr))
-       sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
-           chptr->chname);
-      continue;
-    }
-    /* Recreate the /part list for sending to servers */
-    if (*name != '&')
-    {
-      if (*pbuf)
-       strcat(pbuf, ",");
-      strcat(pbuf, name);
-    }
-    if (can_send(sptr, chptr) != 0)    /* Returns 0 if we CAN send */
-      comment = NULL;
-    /* Send part to all clients */
-    if (!(lp->flags & CHFL_ZOMBIE))
-    {
-      if (comment)
-       sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
-           comment);
-      else
-       sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
-    }
-    else if (MyUser(sptr))
-    {
-      if (comment)
-       sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
-      else
-       sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
-    }
-    remove_user_from_channel(sptr, chptr);
-  }
-  /* Send out the parts to all servers... -Kev */
-  if (*pbuf)
-  {
-    if (comment)
-      sendto_serv_butone(cptr, PartFmt2, parv[0], pbuf, comment);
-    else
-      sendto_serv_butone(cptr, PartFmt1, parv[0], pbuf);
-  }
-  return 0;
-}
-
-/*
- * m_kick
- *
- * parv[0] = sender prefix
- * parv[1] = channel
- * parv[2] = client to kick
- * parv[parc-1] = kick comment
- */
-int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient *who;
-  aChannel *chptr;
-  char *comment;
-  Link *lp, *lp2;
-
-  sptr->flags &= ~FLAGS_TS8;
-
-  if (parc < 3 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KICK");
-    return 0;
-  }
-
-  if (IsServer(sptr))
-    send_hack_notice(cptr, sptr, parc, parv, 1, 3);
-
-  comment = (BadPtr(parv[parc - 1])) ? parv[0] : parv[parc - 1];
-  if (strlen(comment) > (size_t)TOPICLEN)
-    comment[TOPICLEN] = '\0';
-
-  *nickbuf = *buf = '\0';
-
-  chptr = get_channel(sptr, parv[1], !CREATE);
-  if (!chptr)
-  {
-    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]);
-    return 0;
-  }
-  if (IsLocalChannel(parv[1]) && !MyUser(sptr))
-    return 0;
-  if (IsModelessChannel(parv[1]))
-  {
-    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
-       chptr->chname);
-    return 0;
-  }
-  if (!IsServer(cptr) && !is_chan_op(sptr, chptr))
-  {
-    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
-       me.name, parv[0], chptr->chname);
-    return 0;
-  }
-
-  lp2 = find_user_link(chptr->members, sptr);
-  if (MyUser(sptr) || Protocol(cptr) < 10)
-  {
-    if (!(who = find_chasing(sptr, parv[2], NULL)))
-      return 0;                        /* No such user left! */
-  }
-  else if (!(who = findNUser(parv[2])))
-    return 0;                  /* No such user left! */
-  /* if the user is +k, prevent a kick from local user */
-  if (IsChannelService(who) && MyUser(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
-       parv[0], who->name, chptr->chname);
-    return 0;
-  }
-#ifdef NO_OPER_DEOP_LCHAN
-  /*
-   * Prevent kicking opers from local channels -DM-
-   */
-  if (IsOperOnLocalChannel(who, chptr->chname))
-  {
-    sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
-               parv[0], who->name, chptr->chname);
-    return 0;
-  }
-#endif
-
-  if (((lp = find_user_link(chptr->members, who)) &&
-      !(lp->flags & CHFL_ZOMBIE)) || IsServer(sptr))
+  /* m == 0 means flush */
+  if (m)
   {
-    if (who->from != cptr &&
-       ((lp2 && (lp2->flags & CHFL_DEOPPED)) || (!lp2 && IsUser(sptr))))
+    if (param)
     {
-      /*
-       * Bounce here:
-       * cptr must be a server (or cptr == sptr and
-       * sptr->flags can't have DEOPPED set
-       * when CHANOP is set).
-       */
-      sendto_one(cptr, ":%s JOIN %s", who->name, parv[1]);
-      if (lp->flags & CHFL_CHANOP)
-      {
-       if (Protocol(cptr) < 10)
-         sendto_one(cptr, ":%s MODE %s +o %s " TIME_T_FMT,
-             me.name, parv[1], who->name, chptr->creationtime);
-       else
-         sendto_one(cptr, "%s MODE %s +o %s%s " TIME_T_FMT,
-             NumServ(&me), parv[1], NumNick(who), chptr->creationtime);
-      }
-      if (lp->flags & CHFL_VOICE)
+      size_t nplen = strlen(param);
+      if (pb - parabuf + nplen + 23 > MODEBUFLEN)
+        paramdoesntfit = 1;
+      else
       {
-       if (Protocol(cptr) < 10)
-         sendto_one(cptr, ":%s MODE %s +v %s " TIME_T_FMT,
-             me.name, chptr->chname, who->name, chptr->creationtime);
-       else
-         sendto_one(cptr, "%s MODE %s +v %s%s " TIME_T_FMT,
-             NumServ(&me), parv[1], NumNick(who), chptr->creationtime);
+        *sbp++ = m;
+        *pb++ = ' ';
+        strcpy(pb, param);
+        pb += nplen;
+        ++*count;
       }
     }
     else
-    {
-      if (lp)
-       sendto_channel_butserv(chptr, sptr,
-           ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
-      if (!IsLocalChannel(parv[1]))
-      {
-       sendto_lowprot_butone(cptr, 9, ":%s KICK %s %s :%s",
-           parv[0], chptr->chname, who->name, comment);
-       sendto_highprot_butone(cptr, 10, ":%s KICK %s %s%s :%s",
-           parv[0], parv[1], NumNick(who), comment);
-      }
-      if (lp)
-      {
+      *sbp++ = m;
+  }
+  else if (*count == 0)
+    return;
+  if (*count == 6 || !m || paramdoesntfit)
+  {
+    struct Membership* member;
+    strcpy(sbp, parabuf);
+    for (member = chptr->members; member; member = member->next_member)
+      if (MyUser(member->user))
+        sendbufto_one(member->user);
+    sbp = sbpi;
+    pb = parabuf;
+    *count = 0;
+  }
+  if (paramdoesntfit)
+  {
+    *sbp++ = m;
+    *pb++ = ' ';
+    strcpy(pb, param);
+    pb += strlen(param);
+    ++*count;
+  }
+}
+
+
 /*
  * Consider:
  *
@@ -3789,694 +2459,90 @@ int m_kick(aClient *cptr, aClient *sptr, int parc, char *parv[])
  *
  * --Run
  */
-       /* Default for case a): */
-       lp->flags |= CHFL_ZOMBIE;
-       /* Case b) or c) ?: */
-       if (MyUser(who))        /* server 4 */
-       {
-         if (IsServer(cptr))   /* Case b) ? */
-           sendto_one(cptr, PartFmt1, who->name, parv[1]);
-         remove_user_from_channel(who, chptr);
-         return 0;
-       }
-       if (who->from == cptr)  /* True on servers 1, 5 and 6 */
-       {
-         aClient *acptr = IsServer(sptr) ? sptr : sptr->user->server;
-         for (; acptr != &me; acptr = acptr->serv->up)
-           if (acptr == who->user->server)     /* Case d) (server 5) */
-           {
-             remove_user_from_channel(who, chptr);
-             return 0;
-           }
-       }
-       /* Case a) (servers 1, 2, 3 and 6) */
-       for (lp = chptr->members; lp; lp = lp->next)
-         if (!(lp->flags & CHFL_ZOMBIE))
-           break;
-       if (!lp)
-         remove_user_from_channel(who, chptr);
-#ifdef GODMODE
-       else
-         sendto_op_mask(SNO_HACK2, "%s is now a zombie on %s",
-             who->name, chptr->chname);
-#endif
-      }
-    }
-  }
-  else if (MyUser(sptr))
-    sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
-       me.name, parv[0], who->name, chptr->chname);
-
-  return 0;
-}
-
-/*
- * m_topic
- *
- * parv[0]        = sender prefix
- * parv[1]        = channel
- * parv[parc - 1] = topic (if parc > 2)
- */
-int m_topic(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aChannel *chptr;
-  char *topic = NULL, *name, *p = NULL;
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "TOPIC");
-    return 0;
-  }
-
-  if (parc > 2)
-    topic = parv[parc - 1];
-
-  for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
-  {
-    chptr = NULL;
-    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
-       ((topic || SecretChannel(chptr)) && !IsMember(sptr, chptr)))
-    {
-      sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
-         me.name, parv[0], chptr ? chptr->chname : name);
-      continue;
-    }
-    if (IsModelessChannel(name))
-    {
-      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
-         chptr->chname);
-      continue;
-    }
-    if (IsLocalChannel(name) && !MyUser(sptr))
-      continue;
-
-    if (!topic)                        /* only asking  for topic  */
-    {
-      if (chptr->topic[0] == '\0')
-       sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname);
-      else
-      {
-       sendto_one(sptr, rpl_str(RPL_TOPIC),
-           me.name, parv[0], chptr->chname, chptr->topic);
-       sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
-           me.name, parv[0], chptr->chname,
-           chptr->topic_nick, chptr->topic_time);
-      }
-    }
-    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
-       is_chan_op(sptr, chptr)) && topic)
-    {
-      /* setting a topic */
-      strncpy(chptr->topic, topic, TOPICLEN);
-      strncpy(chptr->topic_nick, sptr->name, NICKLEN);
-      chptr->topic_time = now;
-      sendto_serv_butone(cptr, ":%s TOPIC %s :%s",
-         parv[0], chptr->chname, chptr->topic);
-      sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
-         parv[0], chptr->chname, chptr->topic);
-    }
-    else
-      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
-         me.name, parv[0], chptr->chname);
-  }
-  return 0;
-}
-
-/*
- * m_invite
- *   parv[0] - sender prefix
- *   parv[1] - user to invite
- *   parv[2] - channel name
- *
- * - INVITE now is accepted only if who does it is chanop (this of course
- *   implies that channel must exist and he must be on it).
- *
- * - On the other side it IS processed even if channel is NOT invite only
- *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
- *
- */
-int m_invite(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr;
-  aChannel *chptr;
-
-  if (parc < 3 || *parv[2] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "INVITE");
-    return 0;
-  }
-
-  if (!(acptr = FindUser(parv[1])))
-  {
-    sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
-    return 0;
-  }
-
-  if (is_silenced(sptr, acptr))
-    return 0;
-
-  if (MyUser(sptr))
-    clean_channelname(parv[2]);
-  else if (IsLocalChannel(parv[2]))
-    return 0;
-
-  if (*parv[2] == '0' || !IsChannelName(parv[2]))
-    return 0;
-
-  if (!(chptr = FindChannel(parv[2])))
-  {
-    if (IsModelessChannel(parv[2]) || IsLocalChannel(parv[2]))
-    {
-      sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[2]);
-      return 0;
-    }
-
-    /* Do not disallow to invite to non-existant #channels, otherwise they
-       would simply first be created, causing only MORE bandwidth usage. */
-    if (MyConnect(sptr))
-    {
-      if (check_target_limit(sptr, acptr, acptr->name, 0))
-       return 0;
-
-      sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
-         acptr->name, parv[2]);
-
-      if (acptr->user->away)
-       sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
-           acptr->name, acptr->user->away);
-    }
-
-    sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
-       acptr->name, parv[2]);
-
-    return 0;
-  }
-
-  if (!IsMember(sptr, chptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
-       chptr->chname);
-    return 0;
-  }
-
-  if (IsMember(acptr, chptr))
-  {
-    sendto_one(sptr, err_str(ERR_USERONCHANNEL),
-       me.name, parv[0], acptr->name, chptr->chname);
-    return 0;
-  }
-
-  if (MyConnect(sptr))
-  {
-    if (!is_chan_op(sptr, chptr))
-    {
-      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
-         me.name, parv[0], chptr->chname);
-      return 0;
-    }
-
-    /* If we get here, it was a VALID and meaningful INVITE */
-
-    if (check_target_limit(sptr, acptr, acptr->name, 0))
-      return 0;
-
-    sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
-       acptr->name, chptr->chname);
-
-    if (acptr->user->away)
-      sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
-         acptr->name, acptr->user->away);
-  }
-
-  if (MyConnect(acptr))
-    add_invite(acptr, chptr);
-
-  sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
-      acptr->name, chptr->chname);
-
-  return 0;
-}
-
-static int number_of_zombies(aChannel *chptr)
-{
-  Reg1 Link *lp;
-  Reg2 int count = 0;
-  for (lp = chptr->members; lp; lp = lp->next)
-    if (lp->flags & CHFL_ZOMBIE)
-      count++;
-  return count;
-}
-
-/*
- * m_list
- *
- * parv[0] = sender prefix
- * parv[1] = channel list or user/time limit
- * parv[2...] = more user/time limits
- */
-int m_list(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
+void make_zombie(struct Membership* member, struct Client* who, struct Client* cptr,
+                 struct Client* sptr, struct Channel* chptr)
 {
-  aChannel *chptr;
-  char *name, *p = NULL;
-  int show_usage = 0, show_channels = 0, param;
-  aListingArgs args = {
-    2147483647,                        /* max_time */
-    0,                         /* min_time */
-    4294967295U,               /* max_users */
-    0,                         /* min_users */
-    0,                         /* topic_limits */
-    2147483647,                        /* max_topic_time */
-    0,                         /* min_topic_time */
-    NULL                       /* chptr */
-  };
-
-  if (sptr->listing)           /* Already listing ? */
-  {
-    sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
-    RunFree(sptr->listing);
-    sptr->listing = NULL;
-    sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
-    if (parc < 2)
-      return 0;                        /* Let LIST abort a listing. */
-  }
-
-  if (parc < 2)                        /* No arguments given to /LIST ? */
-  {
-#ifdef DEFAULT_LIST_PARAM
-    static char *defparv[MAXPARA + 1];
-    static int defparc = 0;
-    static char lp[] = DEFAULT_LIST_PARAM;
-    int i;
-
-    if (!defparc)
-    {
-      char *s = lp, *t;
-
-      defparc = 1;
-      defparv[defparc++] = t = strtok(s, " ");
-      while (t && defparc < MAXPARA)
-      {
-       if ((t = strtok(NULL, " ")))
-         defparv[defparc++] = t;
-      }
-    }
-    for (i = 1; i < defparc; i++)
-      parv[i] = defparv[i];
-    parv[i] = NULL;
-    parc = defparc;
-#endif /* DEFAULT_LIST_PARAM */
-  }
+  assert(0 != member);
+  assert(0 != who);
+  assert(0 != cptr);
+  assert(0 != chptr);
 
-  /* Decode command */
-  for (param = 1; !show_usage && parv[param]; param++)
-  {
-    char *p = parv[param];
-    do
-    {
-      int is_time = 0;
-      switch (*p)
-      {
-       case 'T':
-       case 't':
-         is_time++;
-         args.topic_limits = 1;
-         /* Fall through */
-       case 'C':
-       case 'c':
-         is_time++;
-         p++;
-         if (*p != '<' && *p != '>')
-         {
-           show_usage = 1;
-           break;
-         }
-         /* Fall through */
-       case '<':
-       case '>':
-       {
-         p++;
-         if (!isDigit(*p))
-           show_usage = 1;
-         else
-         {
-           if (is_time)
-           {
-             time_t val = atoi(p);
-             if (p[-1] == '<')
-             {
-               if (val < 80000000)     /* Toggle UTC/offset */
-               {
-                 /*
-                  * Demands that
-                  * 'TStime() - chptr->creationtime < val * 60'
-                  * Which equals
-                  * 'chptr->creationtime > TStime() - val * 60'
-                  */
-                 if (is_time == 1)
-                   args.min_time = TStime() - val * 60;
-                 else
-                   args.min_topic_time = TStime() - val * 60;
-               }
-               else if (is_time == 1)  /* Creation time in UTC was entered */
-                 args.max_time = val;
-               else            /* Topic time in UTC was entered */
-                 args.max_topic_time = val;
-             }
-             else if (val < 80000000)
-             {
-               if (is_time == 1)
-                 args.max_time = TStime() - val * 60;
-               else
-                 args.max_topic_time = TStime() - val * 60;
-             }
-             else if (is_time == 1)
-               args.min_time = val;
-             else
-               args.min_topic_time = val;
-           }
-           else if (p[-1] == '<')
-             args.max_users = atoi(p);
-           else
-             args.min_users = atoi(p);
-           if ((p = strchr(p, ',')))
-             p++;
-         }
-         break;
-       }
-       default:
-         if (!IsChannelName(p))
-         {
-           show_usage = 1;
-           break;
-         }
-         if (parc != 2)        /* Don't allow a mixture of channels with <,> */
-           show_usage = 1;
-         show_channels = 1;
-         p = NULL;
-         break;
-      }
-    }
-    while (!show_usage && p);  /* p points after comma, or is NULL */
-  }
+  /* Default for case a): */
+  SetZombie(member);
 
-  if (show_usage)
+  /* Case b) or c) ?: */
+  if (MyUser(who))      /* server 4 */
   {
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       "Usage: \002/QUOTE LIST\002 \037parameters\037");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       "Where \037parameters\037 is a space or comma seperated "
-       "list of one or more of:");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       " \002<\002\037max_users\037    ; Show all channels with less "
-       "than \037max_users\037.");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       " \002>\002\037min_users\037    ; Show all channels with more "
-       "than \037min_users\037.");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       " \002C<\002\037max_minutes\037 ; Channels that exist less "
-       "than \037max_minutes\037.");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       " \002C>\002\037min_minutes\037 ; Channels that exist more "
-       "than \037min_minutes\037.");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       " \002T<\002\037max_minutes\037 ; Channels with a topic last "
-       "set less than \037max_minutes\037 ago.");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       " \002T>\002\037min_minutes\037 ; Channels with a topic last "
-       "set more than \037min_minutes\037 ago.");
-    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
-       "Example: LIST <3,>1,C<10,T>0  ; 2 users, younger than 10 min., "
-       "topic set.");
-    return 0;
+    if (IsServer(cptr)) /* Case b) ? */
+      sendto_one(cptr, PartFmt1, who->name, chptr->chname);
+    remove_user_from_channel(who, chptr);
+    return;
   }
-
-  sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
-
-  if (!show_channels)
+  if (who->from == cptr)        /* True on servers 1, 5 and 6 */
   {
-    if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
-       args.max_topic_time > args.min_topic_time)      /* Sanity check */
-    {
-      if ((sptr->listing = (aListingArgs *)RunMalloc(sizeof(aListingArgs))))
+    struct Client *acptr = IsServer(sptr) ? sptr : sptr->user->server;
+    for (; acptr != &me; acptr = acptr->serv->up)
+      if (acptr == who->user->server)   /* Case d) (server 5) */
       {
-       memcpy(sptr->listing, &args, sizeof(aListingArgs));
-       if ((sptr->listing->chptr = channel))
-       {
-         int m = channel->mode.mode & MODE_LISTED;
-         list_next_channels(sptr, 64);
-         channel->mode.mode |= m;
-         return 0;
-       }
-       RunFree(sptr->listing);
-       sptr->listing = NULL;
+        remove_user_from_channel(who, chptr);
+        return;
       }
-    }
-    sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
-    return 0;
   }
 
-  for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
-  {
-    chptr = FindChannel(name);
-    if (chptr && ShowChannel(sptr, chptr) && sptr->user)
-      sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
-         ShowChannel(sptr, chptr) ? chptr->chname : "*",
-         chptr->users - number_of_zombies(chptr), chptr->topic);
-  }
+  /* Case a) (servers 1, 2, 3 and 6) */
+  if (channel_all_zombies(chptr))
+    remove_user_from_channel(who, chptr);
 
-  sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
-  return 0;
+  Debug((DEBUG_INFO, "%s is now a zombie on %s", who->name, chptr->chname));
 }
 
-/*
- * m_names                              - Added by Jto 27 Apr 1989
- *
- * parv[0] = sender prefix
- * parv[1] = channel
- */
-int m_names(aClient *cptr, aClient *sptr, int parc, char *parv[])
+int number_of_zombies(struct Channel *chptr)
 {
-  Reg1 aChannel *chptr;
-  Reg2 aClient *c2ptr;
-  Reg3 Link *lp;
-  aChannel *ch2ptr = NULL;
-  int idx, flag, len, mlen;
-  char *s, *para = parc > 1 ? parv[1] : NULL;
-
-  if (parc > 2 && hunt_server(1, cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
-    return 0;
-
-  mlen = strlen(me.name) + 10 + strlen(sptr->name);
-
-  if (!BadPtr(para))
-  {
-    s = strchr(para, ',');
-    if (s)
-    {
-      parv[1] = ++s;
-      m_names(cptr, sptr, parc, parv);
-    }
-    clean_channelname(para);
-    ch2ptr = FindChannel(para);
-  }
-
-  /*
-   * First, do all visible channels (public and the one user self is)
-   */
-
-  for (chptr = channel; chptr; chptr = chptr->nextch)
-  {
-    if ((chptr != ch2ptr) && !BadPtr(para))
-      continue;                        /* -- wanted a specific channel */
-    if (!MyConnect(sptr) && BadPtr(para))
-      continue;
-#ifndef GODMODE
-    if (!ShowChannel(sptr, chptr))
-      continue;                        /* -- users on this are not listed */
-#endif
-
-    /* Find users on same channel (defined by chptr) */
-
-    strcpy(buf, "* ");
-    len = strlen(chptr->chname);
-    strcpy(buf + 2, chptr->chname);
-    strcpy(buf + 2 + len, " :");
-
-    if (PubChannel(chptr))
-      *buf = '=';
-    else if (SecretChannel(chptr))
-      *buf = '@';
-    idx = len + 4;
-    flag = 1;
-    for (lp = chptr->members; lp; lp = lp->next)
-    {
-      c2ptr = lp->value.cptr;
-#ifndef GODMODE
-      if (sptr != c2ptr && IsInvisible(c2ptr) && !IsMember(sptr, chptr))
-       continue;
-#endif
-      if (lp->flags & CHFL_ZOMBIE)
-      {
-       if (lp->value.cptr != sptr)
-         continue;
-       else
-       {
-         strcat(buf, "!");
-         idx++;
-       }
-      }
-      else if (lp->flags & CHFL_CHANOP)
-      {
-       strcat(buf, "@");
-       idx++;
-      }
-      else if (lp->flags & CHFL_VOICE)
-      {
-       strcat(buf, "+");
-       idx++;
-      }
-      strcat(buf, c2ptr->name);
-      strcat(buf, " ");
-      idx += strlen(c2ptr->name) + 1;
-      flag = 1;
-#ifdef GODMODE
-      {
-       char yxx[6];
-       sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
-       if (c2ptr != findNUser(yxx))
-         MyCoreDump;
-       sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
-       idx += 6;
-      }
-      if (mlen + idx + NICKLEN + 11 > BUFSIZE)
-#else
-      if (mlen + idx + NICKLEN + 5 > BUFSIZE)
-#endif
-       /* space, modifier, nick, \r \n \0 */
-      {
-       sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
-       strcpy(buf, "* ");
-       strncpy(buf + 2, chptr->chname, len + 1);
-       buf[len + 2] = 0;
-       strcat(buf, " :");
-       if (PubChannel(chptr))
-         *buf = '=';
-       else if (SecretChannel(chptr))
-         *buf = '@';
-       idx = len + 4;
-       flag = 0;
-      }
-    }
-    if (flag)
-      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
-  }
-  if (!BadPtr(para))
-  {
-    sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0],
-       ch2ptr ? ch2ptr->chname : para);
-    return (1);
-  }
-
-  /* Second, do all non-public, non-secret channels in one big sweep */
-
-  strcpy(buf, "* * :");
-  idx = 5;
-  flag = 0;
-  for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
-  {
-    aChannel *ch3ptr;
-    int showflag = 0, secret = 0;
+  struct Membership* member;
+  int                count = 0;
 
-#ifndef GODMODE
-    if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
-#else
-    if (!IsUser(c2ptr))
-#endif
-      continue;
-    lp = c2ptr->user->channel;
-    /*
-     * Don't show a client if they are on a secret channel or when
-     * they are on a channel sptr is on since they have already
-     * been show earlier. -avalon
-     */
-    while (lp)
-    {
-      ch3ptr = lp->value.chptr;
-#ifndef GODMODE
-      if (PubChannel(ch3ptr) || IsMember(sptr, ch3ptr))
-#endif
-       showflag = 1;
-      if (SecretChannel(ch3ptr))
-       secret = 1;
-      lp = lp->next;
-    }
-    if (showflag)              /* Have we already shown them ? */
-      continue;
-#ifndef GODMODE
-    if (secret)                        /* On any secret channels ? */
-      continue;
-#endif
-    strcat(buf, c2ptr->name);
-    strcat(buf, " ");
-    idx += strlen(c2ptr->name) + 1;
-    flag = 1;
-#ifdef GODMODE
-    {
-      char yxx[6];
-      sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
-      if (c2ptr != findNUser(yxx))
-       MyCoreDump;
-      sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
-      idx += 6;
-    }
-#endif
-#ifdef GODMODE
-    if (mlen + idx + NICKLEN + 9 > BUFSIZE)
-#else
-    if (mlen + idx + NICKLEN + 3 > BUFSIZE)    /* space, \r\n\0 */
-#endif
-    {
-      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
-      strcpy(buf, "* * :");
-      idx = 5;
-      flag = 0;
-    }
+  assert(0 != chptr);
+  for (member = chptr->members; member; member = member->next_member) {
+    if (IsZombie(member))
+      ++count;
   }
-  if (flag)
-    sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
-  sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
-  return (1);
+  return count;
 }
 
-void send_user_joins(aClient *cptr, aClient *user)
+void send_user_joins(struct Client *cptr, struct Client *user)
 {
-  Reg1 Link *lp;
-  Reg2 aChannel *chptr;
-  Reg3 int cnt = 0, len = 0, clen;
-  char *mask;
+  struct Membership* chan;
+  struct Channel*    chptr;
+  int   cnt = 0;
+  int   len = 0;
+  int   clen;
+  char* mask;
+  char  buf[BUFSIZE];
 
   *buf = ':';
   strcpy(buf + 1, user->name);
   strcat(buf, " JOIN ");
   len = strlen(user->name) + 7;
 
-  for (lp = user->user->channel; lp; lp = lp->next)
+  for (chan = user->user->channel; chan; chan = chan->next_channel)
   {
-    chptr = lp->value.chptr;
+    chptr = chan->channel;
+    assert(0 != chptr);
+
     if ((mask = strchr(chptr->chname, ':')))
       if (match(++mask, cptr->name))
-       continue;
+        continue;
     if (*chptr->chname == '&')
       continue;
-    if (is_zombie(user, chptr))
+    if (IsZombie(chan))
       continue;
     clen = strlen(chptr->chname);
     if (clen + 1 + len > BUFSIZE - 3)
     {
       if (cnt)
       {
-       buf[len - 1] = '\0';
-       sendto_one(cptr, "%s", buf);
+        buf[len - 1] = '\0';
+        sendto_one(cptr, "%s", buf);
       }
       *buf = ':';
       strcpy(buf + 1, user->name);
@@ -4487,7 +2553,7 @@ void send_user_joins(aClient *cptr, aClient *user)
     strcpy(buf + len, chptr->chname);
     cnt++;
     len += clen;
-    if (lp->next)
+    if (chan->next_channel)
     {
       len++;
       strcat(buf, ",");
@@ -4495,8 +2561,6 @@ void send_user_joins(aClient *cptr, aClient *user)
   }
   if (*buf && cnt)
     sendto_one(cptr, "%s", buf);
-
-  return;
 }
 
 /*
@@ -4509,112 +2573,86 @@ void send_user_joins(aClient *cptr, aClient *user)
  *   to be sent for all hacks.  -Ghostwolf 18-May-97
  */
 
-static void send_hack_notice(aClient *cptr, aClient *sptr, int parc,
-    char *parv[], int badop, int mtype)
+void send_hack_notice(struct Client *cptr, struct Client *sptr, int parc,
+                      char *parv[], int badop, int mtype)
 {
-  aChannel *chptr;
+  struct Channel *chptr;
   static char params[MODEBUFLEN];
   int i = 3;
   chptr = FindChannel(parv[1]);
   *params = '\0';
 
-  if (Protocol(cptr) < 10)     /* We don't get numeric nicks from P09  */
-  {                            /* servers, so this can be sent "As Is" */
-    if (mtype == 1)
+  /* P10 servers require numeric nick conversion before sending. */
+  switch (mtype)
+  {
+    case 1:                     /* Convert nicks for MODE HACKs here  */
     {
+      char *mode = parv[2];
       while (i < parc)
       {
-       strcat(params, " ");
-       strcat(params, parv[i++]);
+        while (*mode && *mode != 'o' && *mode != 'v')
+          ++mode;
+        strcat(params, " ");
+        if (*mode == 'o' || *mode == 'v')
+        {
+          /*
+           * blindly stumble through parameter list hoping one of them
+           * might turn out to be a numeric nick
+           * NOTE: this should not cause a problem but _may_ end up finding
+           * something we aren't looking for. findNUser should be able to
+           * handle any garbage that is thrown at it, but may return a client
+           * if we happen to get lucky with a mode string or a timestamp
+           */
+          struct Client *acptr;
+          if ((acptr = findNUser(parv[i])) != NULL)     /* Convert nicks here */
+            strcat(params, acptr->name);
+          else
+          {
+            strcat(params, "<");
+            strcat(params, parv[i]);
+            strcat(params, ">");
+          }
+        }
+        else                    /* If it isn't a numnick, send it 'as is' */
+          strcat(params, parv[i]);
+        i++;
       }
       sprintf_irc(sendbuf,
-         ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s [" TIME_T_FMT
-         "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop, parv[0],
-         parv[1], parv[2], params, chptr->creationtime);
+          ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s ["
+          TIME_T_FMT "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop,
+          parv[0], parv[1], parv[2], params, chptr->creationtime);
       sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop ==
-         4) ? SNO_HACK4 : SNO_HACK2);
+          4) ? SNO_HACK4 : SNO_HACK2);
 
       if ((IsServer(sptr)) && (badop == 2))
       {
-       sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
-           me.name, parv[0], parv[1], parv[2], params);
-       sendbufto_serv_butone(cptr);
+        sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
+            me.name, parv[0], parv[1], parv[2], params);
+        sendbufto_serv_butone(cptr);
       }
+      break;
     }
-    else if (mtype == 3)
+    case 2:                     /* No conversion is needed for CREATE; the only numnick is sptr */
     {
-      sprintf_irc(sendbuf,
-         ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
-         me.name, sptr->name, parv[1], parv[2], parv[3]);
-      sendbufto_op_mask(SNO_HACK4);
+      sendto_serv_butone(cptr, ":%s DESYNCH :HACK: %s CREATE %s %s",
+          me.name, sptr->name, chptr->chname, parv[2]);
+      sendto_op_mask(SNO_HACK2, "HACK(2): %s CREATE %s %s",
+          sptr->name, chptr->chname, parv[2]);
+      break;
     }
-  }
-  else
-  {
-    /* P10 servers require numeric nick conversion before sending. */
-    switch (mtype)
-    {
-      case 1:                  /* Convert nicks for MODE HACKs here  */
-      {
-       char *mode = parv[2];
-       while (i < parc)
-       {
-         while (*mode && *mode != 'o' && *mode != 'v')
-           ++mode;
-         strcat(params, " ");
-         if (*mode == 'o' || *mode == 'v')
-         {
-           register aClient *acptr;
-           if ((acptr = findNUser(parv[i])) != NULL)   /* Convert nicks here */
-             strcat(params, acptr->name);
-           else
-           {
-             strcat(params, "<");
-             strcat(params, parv[i]);
-             strcat(params, ">");
-           }
-         }
-         else                  /* If it isn't a numnick, send it 'as is' */
-           strcat(params, parv[i]);
-         i++;
-       }
-       sprintf_irc(sendbuf,
-           ":%s NOTICE * :*** Notice -- %sHACK(%d): %s MODE %s %s%s ["
-           TIME_T_FMT "]", me.name, (badop == 3) ? "BOUNCE or " : "", badop,
-           parv[0], parv[1], parv[2], params, chptr->creationtime);
-       sendbufto_op_mask((badop == 3) ? SNO_HACK3 : (badop ==
-           4) ? SNO_HACK4 : SNO_HACK2);
-
-       if ((IsServer(sptr)) && (badop == 2))
-       {
-         sprintf_irc(sendbuf, ":%s DESYNCH :HACK: %s MODE %s %s%s",
-             me.name, parv[0], parv[1], parv[2], params);
-         sendbufto_serv_butone(cptr);
-       }
-       break;
-      }
-      case 2:                  /* No conversion is needed for CREATE; the only numnick is sptr */
-      {
-       sendto_serv_butone(cptr, ":%s DESYNCH :HACK: %s CREATE %s %s",
-           me.name, sptr->name, chptr->chname, parv[2]);
-       sendto_op_mask(SNO_HACK2, "HACK(2): %s CREATE %s %s",
-           sptr->name, chptr->chname, parv[2]);
-       break;
-      }
-      case 3:                  /* Convert nick in KICK message */
-      {
-       aClient *acptr;
-       if ((acptr = findNUser(parv[2])) != NULL)       /* attempt to convert nick */
-         sprintf_irc(sendbuf,
-             ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
-             me.name, sptr->name, parv[1], acptr->name, parv[3]);
-       else                    /* if conversion fails, send it 'as is' in <>'s */
-         sprintf_irc(sendbuf,
-             ":%s NOTICE * :*** Notice -- HACK: %s KICK %s <%s> :%s",
-             me.name, sptr->name, parv[1], parv[2], parv[3]);
-       sendbufto_op_mask(SNO_HACK4);
-       break;
-      }
+    case 3:                     /* Convert nick in KICK message */
+    {
+      struct Client *acptr;
+      if ((acptr = findNUser(parv[2])) != NULL) /* attempt to convert nick */
+        sprintf_irc(sendbuf,
+            ":%s NOTICE * :*** Notice -- HACK: %s KICK %s %s :%s",
+            me.name, sptr->name, parv[1], acptr->name, parv[3]);
+      else                      /* if conversion fails, send it 'as is' in <>'s */
+        sprintf_irc(sendbuf,
+            ":%s NOTICE * :*** Notice -- HACK: %s KICK %s <%s> :%s",
+            me.name, sptr->name, parv[1], parv[2], parv[3]);
+      sendbufto_op_mask(SNO_HACK4);
+      break;
     }
   }
 }
index 97eb4416201dab797a996ed1a23c2a32e96d8992..7d0fdb0a89b7eccbbdcc45f449ab442075578c95 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HPUX
-#include <arpa/inet.h>
-#endif /* HPUX */
-#ifdef R_LINES
-#include <signal.h>
-#endif
-#include "h.h"
 #include "s_conf.h"
+#include "client.h"
 #include "class.h"
-#include "common.h"
-#include "ircd.h"
 #include "fileio.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
+#include "sys.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-RCSTAG_CC("$Id$");
 
 /*
  * For the connect rule patch..  these really should be in a header,
@@ -53,9 +50,9 @@ void crule_free(char **elem);
 static void new_class(int cn);
 static char confchar(unsigned int status);
 static char *getfield(char *newline);
-static int validate(aConfItem *top);
-static aConfItem *chk_initconf(void);
-static aConfClass *get_class(int cn, int ism);
+static int validate(struct ConfItem *top);
+static struct ConfItem *chk_initconf(void);
+static struct ConfClass *get_class(int cn, int ism);
 
 static int numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
 static char *chk_configfile = CPATH;
@@ -63,12 +60,9 @@ static char nullfield[] = "";
 static char maxsendq[12];
 
 /* A few dummy variables and functions needed to link with runmalloc.o */
-time_t now;
-struct Client {
-  time_t since;
-  char name[1];
-} me;
-void debug(int UNUSED(level), const char *form, ...)
+time_t CurrentTime;
+struct Client me;
+void debug(int level, const char *form, ...)
 {
   va_list vl;
   va_start(vl, form);
@@ -79,10 +73,10 @@ void debug(int UNUSED(level), const char *form, ...)
   }
   va_end(vl);
 }
-void sendto_one(aClient *UNUSED(to), char *UNUSED(pattern), ...)
+void sendto_one(struct Client *to, char *pattern, ...)
 {
 }
-char *rpl_str(int UNUSED(numeric))
+char *rpl_str(int numeric)
 {
   return "";
 }
@@ -98,26 +92,26 @@ int main(int argc, char *argv[])
     {
       switch (argv[1][1])
       {
-       case 'd':
-         if (argc > 2)
-         {
-           dpath = argv[2];
-           --argc;
-           ++argv;
-         }
-         else
-         {
-           fprintf(stderr, "-d: Missing path\n");
-           exit(-1);
-         }
-         break;
-       case 'x':
-         debugflag = 1;
-         if (isdigit(argv[1][2]))
-           debugflag = atoi(&argv[1][2]);
-         break;
-       default:
-         fprintf(stderr, "Ignoring unknown option -%c\n", argv[1][1]);
+        case 'd':
+          if (argc > 2)
+          {
+            dpath = argv[2];
+            --argc;
+            ++argv;
+          }
+          else
+          {
+            fprintf(stderr, "-d: Missing path\n");
+            exit(-1);
+          }
+          break;
+        case 'x':
+          debugflag = 1;
+          if (isdigit(argv[1][2]))
+            debugflag = atoi(&argv[1][2]);
+          break;
+        default:
+          fprintf(stderr, "Ignoring unknown option -%c\n", argv[1][1]);
       }
     }
     else
@@ -147,12 +141,12 @@ int main(int argc, char *argv[])
  * Returns -1, if file cannot be opened
  *          0, if file opened.
  */
-static aConfItem *chk_initconf(void)
+static struct ConfItem *chk_initconf(void)
 {
   FBFILE *file;
   char line[512], *tmp, *s, *crule;
-  int ccount = 0, ncount = 0, flags = 0;
-  aConfItem *aconf = NULL, *ctop = NULL;
+  int ccount = 0, flags = 0;
+  struct ConfItem *aconf = NULL, *ctop = NULL;
 
   fprintf(stderr, "chk_initconf(): ircd.conf = %s\n", chk_configfile);
   if (NULL == (file = fbopen(chk_configfile, "r")))
@@ -163,21 +157,24 @@ static aConfItem *chk_initconf(void)
 
   while (fbgets(line, sizeof(line) - 1, file))
   {
-    if (aconf)
-    {
+    if (aconf) {
       if (aconf->host)
-       RunFree(aconf->host);
+        MyFree(aconf->host);
       if (aconf->passwd)
-       RunFree(aconf->passwd);
+        MyFree(aconf->passwd);
       if (aconf->name)
-       RunFree(aconf->name);
+        MyFree(aconf->name);
     }
-    else
-      aconf = (aConfItem *)RunMalloc(sizeof(*aconf));
-    aconf->host = (char *)NULL;
-    aconf->passwd = (char *)NULL;
-    aconf->name = (char *)NULL;
-    aconf->confClass = (aConfClass *) NULL;
+    else {
+      aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem));
+      assert(0 != aconf);
+    }
+    aconf->host        = NULL;
+    aconf->passwd      = NULL;
+    aconf->name        = NULL;
+    aconf->confClass   = NULL;
+    aconf->dns_pending = 0;
+
     if ((tmp = strchr(line, '\n')))
       *tmp = 0;
     /*
@@ -187,36 +184,36 @@ static aConfItem *chk_initconf(void)
     {
       if (*tmp == '\\')
       {
-       switch (*(tmp + 1))
-       {
-         case 'n':
-           *tmp = '\n';
-           break;
-         case 'r':
-           *tmp = '\r';
-           break;
-         case 't':
-           *tmp = '\t';
-           break;
-         case '0':
-           *tmp = '\0';
-           break;
-         default:
-           *tmp = *(tmp + 1);
-           break;
-       }
-       if (!*(tmp + 1))
-         break;
-       else
-         for (s = tmp; (*s = *++s);)
-           ;
-       tmp++;
+        switch (*(tmp + 1))
+        {
+          case 'n':
+            *tmp = '\n';
+            break;
+          case 'r':
+            *tmp = '\r';
+            break;
+          case 't':
+            *tmp = '\t';
+            break;
+          case '0':
+            *tmp = '\0';
+            break;
+          default:
+            *tmp = *(tmp + 1);
+            break;
+        }
+        if (!*(tmp + 1))
+          break;
+        else
+          for (s = tmp; (*s = *++s);)
+            ;
+        tmp++;
       }
       else if (*tmp == '#')
-       *tmp = '\0';
+        *tmp = '\0';
     }
     if (!*line || *line == '#' || *line == '\n' ||
-       *line == ' ' || *line == '\t')
+        *line == ' ' || *line == '\t')
       continue;
 
     if (line[1] != ':')
@@ -240,121 +237,109 @@ static aConfItem *chk_initconf(void)
 
     switch (*tmp)
     {
-      case 'A':                /* Name, e-mail address of administrator */
-      case 'a':                /* of this server. */
-       aconf->status = CONF_ADMIN;
-       break;
-      case 'C':                /* Server where I should try to connect */
-      case 'c':                /* in case of lp failures             */
-       ccount++;
-       aconf->status = CONF_CONNECT_SERVER;
-       break;
-       /* Connect rule */
+      case 'A':         /* Name, e-mail address of administrator */
+      case 'a':         /* of this server. */
+        aconf->status = CONF_ADMIN;
+        break;
+      case 'C':         /* Server where I should try to connect */
+      case 'c':         /* in case of lp failures             */
+        ccount++;
+        aconf->status = CONF_SERVER;
+        break;
+        /* Connect rule */
       case 'D':
-       aconf->status = CONF_CRULEALL;
-       break;
-       /* Connect rule - autos only */
+        aconf->status = CONF_CRULEALL;
+        break;
+        /* Connect rule - autos only */
       case 'd':
-       aconf->status = CONF_CRULEAUTO;
-       break;
-      case 'H':                /* Hub server line */
+        aconf->status = CONF_CRULEAUTO;
+        break;
+      case 'H':         /* Hub server line */
       case 'h':
-       aconf->status = CONF_HUB;
-       break;
-      case 'I':                /* Just plain normal irc client trying  */
-      case 'i':                /* to connect me */
-       aconf->status = CONF_CLIENT;
-       break;
-      case 'K':                /* Kill user line on irc.conf           */
-       aconf->status = CONF_KILL;
-       break;
-      case 'k':                /* Kill user line based on IP in ircd.conf */
-       aconf->status = CONF_IPKILL;
-       break;
-       /* Operator. Line should contain at least */
-       /* password and host where connection is  */
-      case 'L':                /* guaranteed leaf server */
+        aconf->status = CONF_HUB;
+        break;
+      case 'I':         /* Just plain normal irc client trying  */
+      case 'i':         /* to connect me */
+        aconf->status = CONF_CLIENT;
+        break;
+      case 'K':         /* Kill user line on irc.conf           */
+        aconf->status = CONF_KILL;
+        break;
+      case 'k':         /* Kill user line based on IP in ircd.conf */
+        aconf->status = CONF_IPKILL;
+        break;
+        /* Operator. Line should contain at least */
+        /* password and host where connection is  */
+      case 'L':         /* guaranteed leaf server */
       case 'l':
-       aconf->status = CONF_LEAF;
-       break;
-       /* Me. Host field is name used for this host */
-       /* and port number is the number of the port */
+        aconf->status = CONF_LEAF;
+        break;
+        /* Me. Host field is name used for this host */
+        /* and port number is the number of the port */
       case 'M':
       case 'm':
-       aconf->status = CONF_ME;
-       break;
-      case 'N':                /* Server where I should NOT try to     */
-      case 'n':                /* connect in case of lp failures     */
-       /* but which tries to connect ME        */
-       ++ncount;
-       aconf->status = CONF_NOCONNECT_SERVER;
-       break;
+        aconf->status = CONF_ME;
+        break;
       case 'O':
-       aconf->status = CONF_OPERATOR;
-       break;
-       /* Local Operator, (limited privs --SRB) */
+        aconf->status = CONF_OPERATOR;
+        break;
+        /* Local Operator, (limited privs --SRB) */
       case 'o':
-       aconf->status = CONF_LOCOP;
-       break;
-      case 'P':                /* listen port line */
+        aconf->status = CONF_LOCOP;
+        break;
+      case 'P':         /* listen port line */
       case 'p':
-       aconf->status = CONF_LISTEN_PORT;
-       break;
-#ifdef R_LINES
-      case 'R':                /* extended K line */
-      case 'r':                /* Offers more options of how to restrict */
-       aconf->status = CONF_RESTRICT;
-       break;
-#endif
+        aconf->status = CONF_LISTEN_PORT;
+        break;
       case 'T':
       case 't':
-       aconf->status = CONF_TLINES;
-       break;
+        aconf->status = CONF_TLINES;
+        break;
       case 'U':
       case 'u':
-       aconf->status = CONF_UWORLD;
-       break;
+        aconf->status = CONF_UWORLD;
+        break;
       case 'Y':
       case 'y':
-       aconf->status = CONF_CLASS;
-       break;
+        aconf->status = CONF_CLASS;
+        break;
       default:
-       fprintf(stderr, "\tERROR: unknown conf line letter (%c)\n", *tmp);
-       break;
+        fprintf(stderr, "\tERROR: unknown conf line letter (%c)\n", *tmp);
+        break;
     }
 
     if (IsIllegal(aconf))
       continue;
 
-    for (;;)                   /* Fake loop, that I can use break here --msa */
+    for (;;)                    /* Fake loop, that I can use break here --msa */
     {
       if ((tmp = getfield(NULL)) == NULL)
-       break;
+        break;
       DupString(aconf->host, tmp);
       if ((tmp = getfield(NULL)) == NULL)
-       break;
+        break;
       DupString(aconf->passwd, tmp);
       if ((tmp = getfield(NULL)) == NULL)
-       break;
+        break;
       DupString(aconf->name, tmp);
       if ((tmp = getfield(NULL)) == NULL)
-       break;
+        break;
       aconf->port = atoi(tmp);
       if ((tmp = getfield(NULL)) == NULL)
-       break;
+        break;
       if (!(aconf->status & (CONF_CLASS | CONF_ME)))
       {
-       aconf->confClass = get_class(atoi(tmp), 0);
-       break;
+        aconf->confClass = get_class(atoi(tmp), 0);
+        break;
       }
       if (aconf->status & CONF_ME)
-       aconf->confClass = get_class(atoi(tmp), 1);
+        aconf->confClass = get_class(atoi(tmp), 1);
       break;
     }
-    if (!aconf->confClass && (aconf->status & (CONF_CONNECT_SERVER |
-       CONF_ME | CONF_NOCONNECT_SERVER | CONF_OPS | CONF_CLIENT)))
+    if (!aconf->confClass && (aconf->status & (CONF_SERVER |
+        CONF_ME | CONF_OPS | CONF_CLIENT)))
     {
-      fprintf(stderr, "\tWARNING: No class.     Default 0\n");
+      fprintf(stderr, "\tWARNING: No class.      Default 0\n");
       aconf->confClass = get_class(0, 0);
     }
     /*
@@ -365,17 +350,17 @@ static aConfItem *chk_initconf(void)
     {
       if (!aconf->host)
       {
-       fprintf(stderr, "\tERROR: no class #\n");
-       continue;
+        fprintf(stderr, "\tERROR: no class #\n");
+        continue;
       }
       if (!tmp)
       {
-       fprintf(stderr, "\tWARNING: missing sendq field\n");
-       fprintf(stderr, "\t\t default: %d\n", DEFAULTMAXSENDQLENGTH);
-       sprintf(maxsendq, "%d", DEFAULTMAXSENDQLENGTH);
+        fprintf(stderr, "\tWARNING: missing sendq field\n");
+        fprintf(stderr, "\t\t default: %d\n", DEFAULTMAXSENDQLENGTH);
+        sprintf(maxsendq, "%d", DEFAULTMAXSENDQLENGTH);
       }
       else
-       sprintf(maxsendq, "%d", atoi(tmp));
+        sprintf(maxsendq, "%d", atoi(tmp));
       new_class(atoi(aconf->host));
       aconf->confClass = get_class(atoi(aconf->host), 0);
       goto print_confline;
@@ -383,62 +368,45 @@ static aConfItem *chk_initconf(void)
 
     if (aconf->status & CONF_LISTEN_PORT)
     {
-#ifdef UNIXPORT
-      struct stat sb;
-
       if (!aconf->host)
-       fprintf(stderr, "\tERROR: %s\n", "null host field in P-line");
+        fprintf(stderr, "\tERROR: %s\n", "null host field in P-line");
       else if (strchr(aconf->host, '/'))
-      {
-       if (stat(aconf->host, &sb) == -1)
-       {
-         fprintf(stderr, "\tERROR: (%s) ", aconf->host);
-         perror("stat");
-       }
-       else if ((sb.st_mode & S_IFMT) != S_IFDIR)
-         fprintf(stderr, "\tERROR: %s not directory\n", aconf->host);
-      }
-#else
-      if (!aconf->host)
-       fprintf(stderr, "\tERROR: %s\n", "null host field in P-line");
-      else if (strchr(aconf->host, '/'))
-       fprintf(stderr, "\t%s\n", "WARNING: / present in P-line "
-           "for non-UNIXPORT configuration");
-#endif
+        fprintf(stderr, "\t%s\n", "WARNING: / present in P-line "
+            "for non-UNIXPORT configuration");
       aconf->confClass = get_class(0, 0);
       goto print_confline;
     }
 
-    if (aconf->status & CONF_SERVER_MASK &&
-       (!aconf->host || strchr(aconf->host, '*') || strchr(aconf->host, '?')))
+    if (aconf->status & CONF_SERVER &&
+        (!aconf->host || strchr(aconf->host, '*') || strchr(aconf->host, '?')))
     {
       fprintf(stderr, "\tERROR: bad host field\n");
       continue;
     }
 
-    if (aconf->status & CONF_SERVER_MASK && BadPtr(aconf->passwd))
+    if (aconf->status & CONF_SERVER && BadPtr(aconf->passwd))
     {
       fprintf(stderr, "\tERROR: empty/no password field\n");
       continue;
     }
 
-    if (aconf->status & CONF_SERVER_MASK && !aconf->name)
+    if (aconf->status & CONF_SERVER && !aconf->name)
     {
       fprintf(stderr, "\tERROR: bad name field\n");
       continue;
     }
 
-    if (aconf->status & (CONF_SERVER_MASK | CONF_OPS))
+    if (aconf->status & (CONF_OPS))
       if (!strchr(aconf->host, '@'))
       {
-       char *newhost;
-       int len = 3;            /* *@\0 = 3 */
-
-       len += strlen(aconf->host);
-       newhost = (char *)RunMalloc(len);
-       sprintf(newhost, "*@%s", aconf->host);
-       RunFree(aconf->host);
-       aconf->host = newhost;
+        char *newhost;
+        int len = 3;            /* *@\0 = 3 */
+
+        len += strlen(aconf->host);
+        newhost = (char *)MyMalloc(len);
+        sprintf(newhost, "*@%s", aconf->host);
+        MyFree(aconf->host);
+        aconf->host = newhost;
       }
 
     /* parse the connect rules to detect errors, but free
@@ -446,14 +414,14 @@ static aConfItem *chk_initconf(void)
      *  for errors..  */
     if (aconf->status & CONF_CRULE)
       if ((crule = (char *)crule_parse(aconf->name)) != NULL)
-       crule_free(&crule);
+        crule_free(&crule);
 
     if (!aconf->confClass)
       aconf->confClass = get_class(0, 0);
     sprintf(maxsendq, "%d", ConfClass(aconf));
 
     if ((aconf->status & CONF_ADMIN) && (!aconf->name ||
-       !aconf->passwd || !aconf->host))
+        !aconf->passwd || !aconf->host))
       fprintf(stderr, "ERROR: Your A: line must have 4 fields!\n");
 
     if (!aconf->name)
@@ -465,18 +433,18 @@ static aConfItem *chk_initconf(void)
     if (aconf->status & (CONF_ME | CONF_ADMIN))
     {
       if (flags & aconf->status)
-       fprintf(stderr, "ERROR: multiple %c-lines\n",
-           toUpper(confchar(aconf->status)));
+        fprintf(stderr, "ERROR: multiple %c-lines\n",
+                ToUpper(confchar(aconf->status)));
       else
-       flags |= aconf->status;
+        flags |= aconf->status;
     }
-  print_confline:
+print_confline:
     if (debugflag > 8)
       printf("(%d) (%s) (%s) (%s) (%u) (%s)\n",
-         aconf->status, aconf->host, aconf->passwd,
-         aconf->name, aconf->port, maxsendq);
+          aconf->status, aconf->host, aconf->passwd,
+          aconf->name, aconf->port, maxsendq);
     fflush(stdout);
-    if (aconf->status & (CONF_SERVER_MASK | CONF_HUB | CONF_LEAF))
+    if (aconf->status & (CONF_SERVER | CONF_HUB | CONF_LEAF))
     {
       aconf->next = ctop;
       ctop = aconf;
@@ -487,9 +455,9 @@ static aConfItem *chk_initconf(void)
   return ctop;
 }
 
-static aConfClass *get_class(int cn, int ism)
+static struct ConfClass *get_class(int cn, int ism)
 {
-  static aConfClass cls;
+  static struct ConfClass cls;
   if (ism == 1)
   {
     cls.conClass = (unsigned int)-1;
@@ -505,8 +473,8 @@ static aConfClass *get_class(int cn, int ism)
     for (; i >= 0; i--)
       if (classarr[i] == cn)
       {
-       cls.conClass = cn;
-       break;
+        cls.conClass = cn;
+        break;
       }
     if (i == -1)
       fprintf(stderr, "\tWARNING: class %d not found\n", cn);
@@ -518,9 +486,9 @@ static void new_class(int cn)
 {
   numclasses++;
   if (classarr)
-    classarr = (int *)RunRealloc(classarr, sizeof(int) * numclasses);
+    classarr = (int *)MyRealloc(classarr, sizeof(int) * numclasses);
   else
-    classarr = (int *)RunMalloc(sizeof(int));
+    classarr = (int *)MyMalloc(sizeof(int));
   classarr[numclasses - 1] = cn;
 }
 
@@ -550,9 +518,9 @@ static char *getfield(char *newline)
   return (field);
 }
 
-static int validate(aConfItem *top)
+static int validate(struct ConfItem *top)
 {
-  Reg1 aConfItem *aconf, *bconf;
+  struct ConfItem *aconf, *bconf;
   unsigned int otype, valid = 0;
 
   if (!top)
@@ -563,49 +531,45 @@ static int validate(aConfItem *top)
     if (aconf->status & CONF_MATCH)
       continue;
 
-    if (aconf->status & CONF_SERVER_MASK)
+    if (aconf->status & CONF_SERVER)
     {
-      if (aconf->status & CONF_CONNECT_SERVER)
-       otype = CONF_NOCONNECT_SERVER;
-      else if (aconf->status & CONF_NOCONNECT_SERVER)
-       otype = CONF_CONNECT_SERVER;
-      else                     /* Does this ever happen ? */
-       continue;
+      otype = CONF_SERVER;
 
       for (bconf = top; bconf; bconf = bconf->next)
       {
-       if (bconf == aconf || !(bconf->status & otype))
-         continue;
-       if (bconf->confClass == aconf->confClass &&
-           !strCasediff(bconf->name, aconf->name) &&
-           !strCasediff(bconf->host, aconf->host))
-       {
-         aconf->status |= CONF_MATCH;
-         bconf->status |= CONF_MATCH;
-         break;
-       }
+        if (bconf == aconf || !(bconf->status & otype))
+          continue;
+        if (bconf->confClass == aconf->confClass &&
+            0 == ircd_strcmp(bconf->name, aconf->name) &&
+            0 == ircd_strcmp(bconf->host, aconf->host))
+        {
+          aconf->status |= CONF_MATCH;
+          bconf->status |= CONF_MATCH;
+          break;
+        }
       }
     }
     else
       for (bconf = top; bconf; bconf = bconf->next)
       {
-       if ((bconf == aconf) || !(bconf->status & CONF_SERVER_MASK))
-         continue;
-       if (!strCasediff(bconf->name, aconf->name))
-       {
-         aconf->status |= CONF_MATCH;
-         break;
-       }
+        if ((bconf == aconf) || !(bconf->status & CONF_SERVER))
+          continue;
+        if (0 == ircd_strcmp(bconf->name, aconf->name))
+        {
+          aconf->status |= CONF_MATCH;
+          break;
+        }
       }
   }
 
   fprintf(stderr, "\n");
-  for (aconf = top; aconf; aconf = aconf->next)
+  for (aconf = top; aconf; aconf = aconf->next) {
     if (aconf->status & CONF_MATCH)
       valid++;
-    else
+    else if ('N' != confchar(aconf->status)) 
       fprintf(stderr, "Unmatched %c:%s:%s:%s\n",
-         confchar(aconf->status), aconf->host, aconf->passwd, aconf->name);
+          confchar(aconf->status), aconf->host, aconf->passwd, aconf->name);
+  }
   return valid ? 0 : -1;
 }
 
index 257f359e006a32e480314f9f227675596cb9d022..74da2202909876313dbe42d868785217c2ee0119 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
 #include "class.h"
+#include "client.h"
+#include "ircd.h"
+#include "list.h"
+#include "numeric.h"
 #include "s_conf.h"
-#include "s_serv.h"
+#include "s_debug.h"
 #include "send.h"
-#include "s_err.h"
-#include "numeric.h"
-#include "ircd.h"
+#include "struct.h"
 
-RCSTAG_CC("$Id$");
+#include <assert.h>
 
-#define BAD_CONF_CLASS         ((unsigned int)-1)
-#define BAD_PING               ((unsigned int)-2)
-#define BAD_CLIENT_CLASS       ((unsigned int)-3)
+#define BAD_CONF_CLASS          ((unsigned int)-1)
+#define BAD_PING                ((unsigned int)-2)
+#define BAD_CLIENT_CLASS        ((unsigned int)-3)
 
-aConfClass *classes;
+struct ConfClass *classes;
 
-unsigned int get_conf_class(aConfItem *aconf)
+unsigned int get_conf_class(struct ConfItem *aconf)
 {
   if ((aconf) && (aconf->confClass))
     return (ConfClass(aconf));
@@ -47,7 +47,7 @@ unsigned int get_conf_class(aConfItem *aconf)
 
 }
 
-static unsigned int get_conf_ping(aConfItem *aconf)
+static unsigned int get_conf_ping(struct ConfItem *aconf)
 {
   if ((aconf) && (aconf->confClass))
     return (ConfPingFreq(aconf));
@@ -57,19 +57,19 @@ static unsigned int get_conf_ping(aConfItem *aconf)
   return (BAD_PING);
 }
 
-unsigned int get_client_class(aClient *acptr)
+unsigned int get_client_class(struct Client *acptr)
 {
-  Reg1 Link *tmp;
-  Reg2 aConfClass *cl;
+  struct SLink *tmp;
+  struct ConfClass *cl;
   unsigned int retc = BAD_CLIENT_CLASS;
 
-  if (acptr && !IsMe(acptr) && !IsPing(acptr) && (acptr->confs))
+  if (acptr && !IsMe(acptr) && (acptr->confs))
     for (tmp = acptr->confs; tmp; tmp = tmp->next)
     {
       if (!tmp->value.aconf || !(cl = tmp->value.aconf->confClass))
-       continue;
+        continue;
       if (ConClass(cl) > retc || retc == BAD_CLIENT_CLASS)
-       retc = ConClass(cl);
+        retc = ConClass(cl);
     }
 
   Debug((DEBUG_DEBUG, "Returning Class %d For %s", retc, acptr->name));
@@ -77,31 +77,29 @@ unsigned int get_client_class(aClient *acptr)
   return (retc);
 }
 
-int unsigned get_client_ping(aClient *acptr)
+unsigned int get_client_ping(struct Client *acptr)
 {
-  unsigned int ping = 0, ping2;
-  aConfItem *aconf;
-  Link *link;
+  unsigned int ping = 0;
+  unsigned int ping2;
+  struct ConfItem *aconf;
+  struct SLink *link;
 
   link = acptr->confs;
 
-  if (link)
-    while (link)
-    {
+  if (link) {
+    while (link) {
       aconf = link->value.aconf;
-      if (aconf->status &
-         (CONF_CLIENT | CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER))
-      {
-       ping2 = get_conf_ping(aconf);
-       if ((ping2 != BAD_PING) && ((ping > ping2) || !ping))
-         ping = ping2;
+      if (aconf->status & (CONF_CLIENT | CONF_SERVER)) {
+        ping2 = get_conf_ping(aconf);
+        if ((ping2 != BAD_PING) && ((ping > ping2) || !ping))
+          ping = ping2;
       }
       link = link->next;
     }
-  else
-  {
+  }
+  else {
     ping = PINGFREQUENCY;
-    Debug((DEBUG_DEBUG, "No Attached Confs"));
+    Debug((DEBUG_DEBUG, "No Attached Confs for: %s", acptr->name));
   }
   if (ping <= 0)
     ping = PINGFREQUENCY;
@@ -109,7 +107,7 @@ int unsigned get_client_ping(aClient *acptr)
   return (ping);
 }
 
-unsigned int get_con_freq(aConfClass * clptr)
+unsigned int get_con_freq(struct ConfClass * clptr)
 {
   if (clptr)
     return (ConFreq(clptr));
@@ -127,12 +125,12 @@ unsigned int get_con_freq(aConfClass * clptr)
 void add_class(unsigned int conClass, unsigned int ping, unsigned int confreq,
     unsigned int maxli, size_t sendq)
 {
-  aConfClass *t, *p;
+  struct ConfClass *t, *p;
 
   t = find_class(conClass);
   if ((t == classes) && (conClass != 0))
   {
-    p = (aConfClass *) make_class();
+    p = (struct ConfClass *) make_class();
     NextClass(p) = NextClass(t);
     NextClass(t) = p;
   }
@@ -149,9 +147,9 @@ void add_class(unsigned int conClass, unsigned int ping, unsigned int confreq,
     Links(p) = 0;
 }
 
-aConfClass *find_class(unsigned int cclass)
+struct ConfClass *find_class(unsigned int cclass)
 {
-  aConfClass *cltmp;
+  struct ConfClass *cltmp;
 
   for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
     if (ConClass(cltmp) == cclass)
@@ -161,21 +159,21 @@ aConfClass *find_class(unsigned int cclass)
 
 void check_class(void)
 {
-  aConfClass *cltmp, *cltmp2;
+  struct ConfClass *cltmp, *cltmp2;
 
   Debug((DEBUG_DEBUG, "Class check:"));
 
   for (cltmp2 = cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp2))
   {
     Debug((DEBUG_DEBUG,
-       "Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %d",
-       ConClass(cltmp), ConFreq(cltmp), PingFreq(cltmp),
-       MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp)));
+        "Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %d",
+        ConClass(cltmp), ConFreq(cltmp), PingFreq(cltmp),
+        MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp)));
     if (IsMarkedDelete(cltmp))
     {
       NextClass(cltmp2) = NextClass(cltmp);
       if (Links(cltmp) == 0)
-       free_class(cltmp);
+        free_class(cltmp);
     }
     else
       cltmp2 = cltmp;
@@ -184,7 +182,7 @@ void check_class(void)
 
 void initclass(void)
 {
-  classes = (aConfClass *) make_class();
+  classes = (struct ConfClass *) make_class();
 
   ConClass(FirstClass()) = 0;
   ConFreq(FirstClass()) = CONNECTFREQUENCY;
@@ -195,29 +193,37 @@ void initclass(void)
   NextClass(FirstClass()) = NULL;
 }
 
-void report_classes(aClient *sptr)
+void report_classes(struct Client *sptr)
 {
-  aConfClass *cltmp;
+  struct ConfClass *cltmp;
 
   for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
     sendto_one(sptr, rpl_str(RPL_STATSYLINE), me.name, sptr->name,
-       'Y', ConClass(cltmp), PingFreq(cltmp), ConFreq(cltmp),
-       MaxLinks(cltmp), MaxSendq(cltmp));
+        'Y', ConClass(cltmp), PingFreq(cltmp), ConFreq(cltmp),
+        MaxLinks(cltmp), MaxSendq(cltmp));
 }
 
-size_t get_sendq(aClient *cptr)
+size_t get_sendq(struct Client *cptr)
 {
-  size_t sendq = DEFAULTMAXSENDQLENGTH;
-  Link *tmp;
-  aConfClass *cl;
+  assert(0 != cptr);
+  assert(0 != cptr->local);
 
-  if (cptr && !IsMe(cptr) && (cptr->confs))
-    for (tmp = cptr->confs; tmp; tmp = tmp->next)
-    {
+  if (cptr->max_sendq)
+    return cptr->max_sendq;
+
+  else if (cptr->confs) {
+    struct SLink*     tmp;
+    struct ConfClass* cl;
+
+    for (tmp = cptr->confs; tmp; tmp = tmp->next) {
       if (!tmp->value.aconf || !(cl = tmp->value.aconf->confClass))
-       continue;
-      if (ConClass(cl) != BAD_CLIENT_CLASS)
-       sendq = MaxSendq(cl);
+        continue;
+      if (ConClass(cl) != BAD_CLIENT_CLASS) {
+        cptr->max_sendq = MaxSendq(cl);
+        return cptr->max_sendq;
+      }
     }
-  return sendq;
+  }
+  return DEFAULTMAXSENDQLENGTH;
 }
+
diff --git a/ircd/common.c b/ircd/common.c
deleted file mode 100644 (file)
index bd12fe7..0000000
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * IRC - Internet Relay Chat, include/common.c
- * Copyright (C) 1998 Andrea Cocito
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * CODERS WARNING: DO _NOT_ EDIT THE TABLES IN THIS FILE
- * Instead:
- * a) Edit the table generator below, specifically the makeTables() function
- * b) Recreate the common.c tables with 'make ctables'.
- */
-
-
-/*=============================================================================
- * Actual source of the library stuff, not generated when making the tables
- */
-
-#ifndef MAKETABLES
-
-/*=============================================================================
- * Headers needed in this source file
- */
-
-#include "common.h"
-
-/*=============================================================================
- * Functions eventually inlined or visible externally
- */
-
-#ifndef FORCEINLINE
-/* *INDENT-OFF* */
-NTL_HDR_strChattr { NTL_SRC_strChattr }
-NTL_HDR_strCasediff { NTL_SRC_strCasediff }
-/* *INDENT-ON* */
-#endif /* !FORCEINLINE */
-
-/*=============================================================================
- * Other functions visible externally
- */
-
-int strnChattr(const char *s, const size_t n)
-{
-  register const char *rs = s;
-  register int x = ~0;
-  register int r = n;
-  while (*rs && r--)
-    x &= NTL_char_attrib[*rs++ - CHAR_MIN];
-  return x;
-}
-
-int strCasecmp(const char *a, const char *b)
-{
-  register const char *ra = a;
-  register const char *rb = b;
-  while (toLower(*ra) == toLower(*rb))
-    if (!*ra++)
-      return 0;
-    else
-      rb++;
-  return (*ra - *rb);
-}
-
-int strnCasecmp(const char *a, const char *b, const size_t n)
-{
-  register const char *ra = a;
-  register const char *rb = b;
-  register int left = n;
-  if (!left--)
-    return 0;
-  while (toLower(*ra) == toLower(*rb))
-    if ((!(*(ra++))) || (!(left--)))
-      return 0;
-    else
-      rb++;
-  return (*ra - *rb);
-}
-
-/*=============================================================================
- * Automatically generated tables, don't touch these by hand !
- */
-
-/* *INDENT-OFF* */
-/*
- * DO not touch anything below this line !
- * NTL_TOK_START
- */
-const char NTL_tolower_tab[] = {
-#if (CHAR_MIN<0)
-/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
-/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
-/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
-/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
-/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
-/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
-/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
-/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
-/* xc0-xc7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
-/* xc8-xcf */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
-/* xd0-xd7 */ '\xd0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xd7',
-/* xd8-xdf */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xdf',
-/* xe0-xe7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
-/* xe8-xef */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
-/* xf0-xf7 */ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
-/* xf8-xff */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff'
-                ,
-#endif /* (CHAR_MIN<0) */
-/* x00-x07 */ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
-/* x08-x0f */ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
-/* x10-x17 */ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
-/* x18-x1f */ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
-/* ' '-x27 */    ' ',    '!',    '"',    '#',    '$',    '%',    '&', '\x27',
-/* '('-'/' */    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
-/* '0'-'7' */    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
-/* '8'-'?' */    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
-/* '@'-'G' */    '@',    'a',    'b',    'c',    'd',    'e',    'f',    'g',
-/* 'H'-'O' */    'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
-/* 'P'-'W' */    'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
-/* 'X'-'_' */    'x',    'y',    'z',    '{',    '|',    '}',    '~',    '_',
-/* '`'-'g' */    '`',    'a',    'b',    'c',    'd',    'e',    'f',    'g',
-/* 'h'-'o' */    'h',    'i',    'j',    'k',    'l',    'm',    'n',    'o',
-/* 'p'-'w' */    'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
-/* 'x'-x7f */    'x',    'y',    'z',    '{',    '|',    '}',    '~', '\x7f'
-#if (!(CHAR_MIN<0))
-                ,
-/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
-/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
-/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
-/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
-/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
-/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
-/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
-/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
-/* xc0-xc7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
-/* xc8-xcf */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
-/* xd0-xd7 */ '\xd0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xd7',
-/* xd8-xdf */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xdf',
-/* xe0-xe7 */ '\xe0', '\xe1', '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7',
-/* xe8-xef */ '\xe8', '\xe9', '\xea', '\xeb', '\xec', '\xed', '\xee', '\xef',
-/* xf0-xf7 */ '\xf0', '\xf1', '\xf2', '\xf3', '\xf4', '\xf5', '\xf6', '\xf7',
-/* xf8-xff */ '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff'
-#endif /* (!(CHAR_MIN<0)) */
-  };
-
-const char NTL_toupper_tab[] = {
-#if (CHAR_MIN<0)
-/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
-/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
-/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
-/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
-/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
-/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
-/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
-/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
-/* xc0-xc7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
-/* xc8-xcf */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
-/* xd0-xd7 */ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
-/* xd8-xdf */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
-/* xe0-xe7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
-/* xe8-xef */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
-/* xf0-xf7 */ '\xf0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xf7',
-/* xf8-xff */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xff'
-                ,
-#endif /* (CHAR_MIN<0) */
-/* x00-x07 */ '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
-/* x08-x0f */ '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
-/* x10-x17 */ '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
-/* x18-x1f */ '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
-/* ' '-x27 */    ' ',    '!',    '"',    '#',    '$',    '%',    '&', '\x27',
-/* '('-'/' */    '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
-/* '0'-'7' */    '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
-/* '8'-'?' */    '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
-/* '@'-'G' */    '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
-/* 'H'-'O' */    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
-/* 'P'-'W' */    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
-/* 'X'-'_' */    'X',    'Y',    'Z',    '[', '\x5c',    ']',    '^',    '_',
-/* '`'-'g' */    '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
-/* 'h'-'o' */    'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
-/* 'p'-'w' */    'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
-/* 'x'-x7f */    'X',    'Y',    'Z',    '[', '\x5c',    ']',    '^', '\x7f'
-#if (!(CHAR_MIN<0))
-                ,
-/* x80-x87 */ '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87',
-/* x88-x8f */ '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f',
-/* x90-x97 */ '\x90', '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97',
-/* x98-x9f */ '\x98', '\x99', '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f',
-/* xa0-xa7 */ '\xa0', '\xa1', '\xa2', '\xa3', '\xa4', '\xa5', '\xa6', '\xa7',
-/* xa8-xaf */ '\xa8', '\xa9', '\xaa', '\xab', '\xac', '\xad', '\xae', '\xaf',
-/* xb0-xb7 */ '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', '\xb5', '\xb6', '\xb7',
-/* xb8-xbf */ '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', '\xbe', '\xbf',
-/* xc0-xc7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
-/* xc8-xcf */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
-/* xd0-xd7 */ '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7',
-/* xd8-xdf */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf',
-/* xe0-xe7 */ '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', '\xc7',
-/* xe8-xef */ '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf',
-/* xf0-xf7 */ '\xf0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xf7',
-/* xf8-xff */ '\xd8', '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xff'
-#endif /* (!(CHAR_MIN<0)) */
-  };
-
-const unsigned int NTL_char_attrib[] = {
-#if (CHAR_MIN<0)
-/* x80-x87 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* x88-x8f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* x90-x97 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* x98-x9f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xa0-xa7 */ 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xa8-xaf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xb0-xb7 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xb8-xbf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xc0-xc7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
-/* xc8-xcf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
-/* xd0-xd7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
-/* xd8-xdf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
-/* xe0-xe7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
-/* xe8-xef */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
-/* xf0-xf7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400,
-/* xf8-xff */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400
-                ,
-#endif /* (CHAR_MIN<0) */
-/* x00-x07 */ 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0004,
-/* x08-x0f */ 0x0404, 0x0504, 0x10504, 0x0504, 0x0504, 0x10504, 0x0404, 0x0404,
-/* x10-x17 */ 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404,
-/* x18-x1f */ 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404, 0x0404,
-/* ' '-x27 */ 0x0140, 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x24d0,
-/* '('-'/' */ 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x00d0, 0x74d0, 0xe4d0, 0x04d0,
-/* '0'-'7' */ 0xf459, 0xf459, 0xf459, 0xf459, 0xf459, 0xf459, 0xf459, 0xf459,
-/* '8'-'?' */ 0xf459, 0xf459, 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x04d0, 0x04d0,
-/* '@'-'G' */ 0x04d0, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653,
-/* 'H'-'O' */ 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653,
-/* 'P'-'W' */ 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653,
-/* 'X'-'_' */ 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x7653, 0x74d0,
-/* '`'-'g' */ 0x34d0, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473,
-/* 'h'-'o' */ 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473,
-/* 'p'-'w' */ 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473,
-/* 'x'-x7f */ 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x7473, 0x0400
-#if (!(CHAR_MIN<0))
-                ,
-/* x80-x87 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* x88-x8f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* x90-x97 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* x98-x9f */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xa0-xa7 */ 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xa8-xaf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xb0-xb7 */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xb8-xbf */ 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
-/* xc0-xc7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
-/* xc8-xcf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00,
-/* xd0-xd7 */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
-/* xd8-xdf */ 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x2c00, 0x0400,
-/* xe0-xe7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
-/* xe8-xef */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400,
-/* xf0-xf7 */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400,
-/* xf8-xff */ 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x2400, 0x0400
-#endif /* (!(CHAR_MIN<0)) */
-  };
-
-/*
- * NTL_TOK_END
- * DO not touch anything above this line !
- */
-/* *INDENT-ON* */
-
-#endif /* !MAKETABLES */
-
-/*=============================================================================
- * TABLE GENERATOR
- * The following part of code is NOT included in the actual server's
- * or library source, it's just used to build the above tables
- *
- * This should rebuild the actual tables and automatically place them
- * into this source file, note that this part of code is for developers
- * only, it's supposed to work on both signed and unsigned chars but I
- * actually tested it only on signed-char architectures, the code and
- * macros actually used by the server instead DO work and have been tested
- * on platforms where0 char is both signed or unsigned, this is true as long
- * as the <limits.h> macros are set properly and without any need to rebuild
- * the tables (wich as said an admin should NEVER do, tables need to be rebuilt
- * only when one wants to really change the results or when one has to
- * compile on architectures where a char is NOT eight bits [?!], yes
- * it all is supposed to work in that case too... but I can't test it
- * because I've not found a machine in the world where this happes).
- *
- * NEVER -f[un]signed-char on gcc since that does NOT fix the named macros
- * and you end up in a non-ANSI environment where CHAR_MIN and CHAR_MAX
- * are _not_ the real limits of a default 'char' type. This is true for
- * both admins and coders.
- *
- */
-
-#ifdef MAKETABLES
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-
-#include "common.h"
-
-static void zeroTables(void);
-static void markString(int macro, const char *s);
-static void unMarkString(int macro, const char *s);
-static void markRange(int macro, char from, char to);
-static void moveMacro(int from, int to);
-static void setLowHi(const char firstlow, const char lastlow,
-    const char firsthi);
-
-char NTL_tolower_tab[1 + CHAR_MAX - CHAR_MIN]; /* 256 bytes */
-char NTL_toupper_tab[1 + CHAR_MAX - CHAR_MIN]; /* 256 bytes */
-int NTL_char_attrib[1 + CHAR_MAX - CHAR_MIN];  /* 256 ints = 0.5 to 2 kilobytes */
-
-/*
- * makeTables() 
- * Where we make the tables, edit ONLY this to change the tables.
- */
-
-static void makeTables(void)
-{
-
-  /* Start from a known status */
-  zeroTables();
-
-  /* Make the very elementary sets */
-  markRange(NTL_LOWER, 'a', 'z');
-  markString(NTL_LOWER, "{|}~");
-
-  markRange(NTL_UPPER, 'A', 'Z');
-  markString(NTL_UPPER, "[\\]^");
-
-  markRange(NTL_DIGIT, '0', '9');
-
-  markRange(NTL_CNTRL, '\000', '\037');
-
-  markString(NTL_PUNCT, "!\"#$%&'()*+,-./:;<=>?@_`");
-
-  markString(NTL_SPACE, "\011\012\013\014\015\040");
-
-  /* Make the derived sets, 
-   * WARNING: The order of these calls is important, some depend on 
-   * the results of the previous ones ! */
-
-  moveMacro(NTL_LOWER | NTL_UPPER, NTL_ALPHA);
-  moveMacro(NTL_ALPHA | NTL_DIGIT, NTL_ALNUM);
-  moveMacro(NTL_ALNUM | NTL_PUNCT, NTL_GRAPH);
-
-  moveMacro(NTL_GRAPH, NTL_PRINT);
-  markString(NTL_PRINT, " ");
-
-  markRange(NTL_IRCCH, 0, UCHAR_MAX);
-  unMarkString(NTL_IRCCH, "\007\040\054\240");
-
-  markRange(NTL_IRCCL, '\300', '\326');
-  markRange(NTL_IRCCL, '\330', '\336');
-
-  moveMacro(NTL_ALNUM, NTL_IRCHN);
-  markString(NTL_IRCHN, "-_.");        /* Some DNS might allow '_' per RFC 1033 ! */
-
-  moveMacro(NTL_DIGIT, NTL_IRCIP);
-  markString(NTL_IRCIP, ".");
-
-  moveMacro(NTL_DIGIT | NTL_ALPHA, NTL_IRCNK);
-  markString(NTL_IRCNK, "-_`");
-
-  moveMacro(NTL_ALNUM, NTL_IRCUI);
-  markRange(NTL_IRCUI, '\xe0', '\xf6');
-  markRange(NTL_IRCUI, '\xf8', '\xfe');
-  markRange(NTL_IRCUI, '\xc0', '\xd6');
-  markRange(NTL_IRCUI, '\xd8', '\xde');
-  markString(NTL_IRCUI, ".-_^'`~");
-  markString(NTL_EOL, "\n\r");
-
-  /* And finally let's take care of the toLower/toUpper stuff */
-
-  setLowHi('a', 'z', 'A');
-  setLowHi('\xe0', '\xf6', '\xc0');
-  setLowHi('\xf8', '\xfe', '\xd8');
-  setLowHi('{', '~', '[');
-
-#ifndef FIXME                  /* Just to remember that this is to be removed in u10.06 */
-  setLowHi('\xd0', '\xd0', '\xd0');    /* Freeze the 0xD0 lower/upper */
-  setLowHi('\xf0', '\xf0', '\xf0');    /* Freeze the 0xF0 lower/upper */
-#endif /* FIXME */
-
-
-}
-
-/* 
- * main()
- * This is the main program to be executed for -DMAKETABLES
- */
-
-static void dumphw(int *p, int beg);
-static void dumphb(char *p, int beg);
-
-int main(void)
-{
-  int i, j, k;
-  char c, c1, c2;
-
-  /* Make the tables */
-  makeTables();
-
-  /* Dump them as ANSI C source to be included below */
-
-  /* NTL_tolower_tab */
-  printf("const char NTL_tolower_tab[] = {\n");
-  printf("#if (CHAR_MIN<0)\n");
-  i = (int)((char)SCHAR_MIN);
-  dumphb(NTL_tolower_tab, i);
-  printf("                ,\n");
-  printf("#endif /* (CHAR_MIN<0) */\n");
-  i = 0;
-  dumphb(NTL_tolower_tab, i);
-  printf("#if (!(CHAR_MIN<0))\n");
-  printf("                ,\n");
-  i = (int)((char)SCHAR_MIN);
-  dumphb(NTL_tolower_tab, i);
-  printf("#endif /* (!(CHAR_MIN<0)) */\n");
-  printf("  };\n\n");
-
-  /* NTL_toupper_tab */
-  printf("const char NTL_toupper_tab[] = {\n");
-  printf("#if (CHAR_MIN<0)\n");
-  i = (int)((char)SCHAR_MIN);
-  dumphb(NTL_toupper_tab, i);
-  printf("                ,\n");
-  printf("#endif /* (CHAR_MIN<0) */\n");
-  i = 0;
-  dumphb(NTL_toupper_tab, i);
-  printf("#if (!(CHAR_MIN<0))\n");
-  printf("                ,\n");
-  i = (int)((char)SCHAR_MIN);
-  dumphb(NTL_toupper_tab, i);
-  printf("#endif /* (!(CHAR_MIN<0)) */\n");
-  printf("  };\n\n");
-
-  /* NTL_char_attrib */
-  printf("const unsigned int NTL_char_attrib[] = {\n");
-  printf("#if (CHAR_MIN<0)\n");
-  i = (int)((char)SCHAR_MIN);
-  dumphw(NTL_char_attrib, i);
-  printf("                ,\n");
-  printf("#endif /* (CHAR_MIN<0) */\n");
-  i = 0;
-  dumphw(NTL_char_attrib, i);
-  printf("#if (!(CHAR_MIN<0))\n");
-  printf("                ,\n");
-  i = (int)((char)SCHAR_MIN);
-  dumphw(NTL_char_attrib, i);
-  printf("#endif /* (!(CHAR_MIN<0)) */\n");
-  printf("  };\n\n");
-
-  return 0;
-
-}
-
-/* A few utility functions for makeTables() */
-
-static void zeroTables(void)
-{
-  int i;
-  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
-  {
-    NTL_tolower_tab[i - CHAR_MIN] = (char)i;   /* Unchanged */
-    NTL_toupper_tab[i - CHAR_MIN] = (char)i;   /* Unchanged */
-    NTL_char_attrib[i - CHAR_MIN] = 0x0000;    /* Nothing */
-  };
-}
-
-static void markString(int macro, const char *s)
-{
-  while (*s)
-    NTL_char_attrib[*(s++) - CHAR_MIN] |= macro;
-}
-
-static void unMarkString(int macro, const char *s)
-{
-  while (*s)
-    NTL_char_attrib[*(s++) - CHAR_MIN] &= ~macro;
-}
-
-static void markRange(int macro, char from, char to)
-{
-  int i;
-  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
-    if (((unsigned char)i >= (unsigned char)from)
-       && ((unsigned char)i <= (unsigned char)to))
-      NTL_char_attrib[(char)i - CHAR_MIN] |= macro;
-}
-
-static void moveMacro(int from, int to)
-{
-  int i;
-  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
-    if (NTL_char_attrib[i - CHAR_MIN] & from)
-      NTL_char_attrib[i - CHAR_MIN] |= to;
-}
-
-static void setLowHi(const char firstlow, const char lastlow,
-    const char firsthi)
-{
-  int i, j;
-  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
-    if (((unsigned char)i >= (unsigned char)firstlow)
-       && ((unsigned char)i <= (unsigned char)lastlow))
-    {
-      j = ((int)((char)(i + (int)(firsthi - firstlow))));
-      NTL_tolower_tab[((char)j) - CHAR_MIN] = (char)i;
-      NTL_toupper_tab[((char)i) - CHAR_MIN] = (char)j;
-    };
-}
-
-/* These are used in main() to actually dump the tables, each function
-   dumps half table as hex/char constants... */
-
-#define ROWSIZE 8
-
-static void dumphb(char *tbl, int beg)
-{
-  int i, j, k, z;
-  char *p = &tbl[beg - CHAR_MIN];
-  char c;
-  for (i = 0; i <= SCHAR_MAX; i += ROWSIZE)
-  {
-    k = i + ROWSIZE - 1;
-    if (k > SCHAR_MAX)
-      k = SCHAR_MAX;
-
-    c = (char)(beg + i);
-    printf("/*");
-    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
-       && (c != '\''))
-      printf(" '%c'", c);
-    else
-      printf(" x%02x", ((int)((unsigned char)c)));
-
-    c = (char)(beg + k);
-    printf("-");
-    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
-       && (c != '\''))
-      printf("'%c'", c);
-    else
-      printf("x%02x", ((int)((unsigned char)c)));
-    printf(" */");
-
-    for (j = i; j <= k; j++)
-    {
-      c = p[j];
-      if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
-         && (c != '\''))
-       printf("    '%c'", c);
-      else
-       printf(" '\\x%02x'", ((int)((unsigned char)c)));
-      if (j < SCHAR_MAX)
-       printf(",");
-    };
-    printf("\n");
-  };
-}
-
-static void dumphw(int *tbl, int beg)
-{
-  int i, j, k, z;
-  int *p = &tbl[beg - CHAR_MIN];
-  char c;
-  for (i = 0; i <= SCHAR_MAX; i += ROWSIZE)
-  {
-    k = i + ROWSIZE - 1;
-    if (k > SCHAR_MAX)
-      k = SCHAR_MAX;
-
-    c = (char)(beg + i);
-    printf("/*");
-    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
-       && (c != '\''))
-      printf(" '%c'", c);
-    else
-      printf(" x%02x", ((int)((unsigned char)c)));
-
-    c = (char)(beg + k);
-    printf("-");
-    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
-       && (c != '\''))
-      printf("'%c'", c);
-    else
-      printf("x%02x", ((int)((unsigned char)c)));
-    printf(" */");
-
-    for (j = i; j <= k; j++)
-    {
-      printf(" 0x%04x", p[j] & 0xffffffff);
-      if (j < SCHAR_MAX)
-       printf(",");
-    };
-    printf("\n");
-  };
-}
-
-#endif /* MAKETABLES */
index ccacadfda7ed470cf57dc6bae71e2fa32745b7f4..a38dc48455c46c78c9f2b17b10a3a6df1a053bd6 100644 (file)
  * more closely simulate the actual ircd environment).  crule_eval and
  * the rule functions are made empty functions as in the stand-alone
  * test parser.
+ *
+ * $Id$
  */
-
+#include "crule.h"
 #ifndef CR_DEBUG
 
 /* ircd functions and types we need */
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
-#include "s_serv.h"
+#include "client.h"
 #include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
 #include "match.h"
 #include "s_bsd.h"
-#include "common.h"
-#include "crule.h"
+#include "s_debug.h"
+#include "struct.h"
+
+#include <stdio.h>
+#include <stdlib.h>
 
 #else /* includes and defines to make the stand-alone test parser */
 
-#include "sys.h"
 #include <stdio.h>
-#include "h.h"
+#include <stdlib.h>
 
 #define BadPtr(x) (!(x) || (*(x) == '\0'))
 #define DupString(x,y) \
-       do { \
-         x = (char *)RunMalloc(strlen(y)+1); \
-       strcpy(x,y); \
-       } while(0)
+        do { \
+          x = (char*) MyMalloc(strlen(y)+1); \
+        strcpy(x,y); \
+        } while(0)
 
 /* We don't care about collation discrepacies here, it seems.... */
-#define strCasediff strcasecmp
+#define ircd_strcmp strcasecmp
 
 #endif
 
-RCSTAG_CC("$Id$");
+#include <string.h>
+
 
 #if defined(CR_DEBUG) || defined(CR_CHKCONF)
-#undef RunMalloc
+#undef MyMalloc
 #undef malloc
-#define RunMalloc malloc
-#undef RunFree
+#define MyMalloc malloc
+#undef MyFree
 #undef free
-#define RunFree free
+#define MyFree free
 #endif
 
 /* some constants and shared data types */
-#define CR_MAXARGLEN 80                /* why 80? why not? it's > hostname lengths */
-#define CR_MAXARGS 3           /* There's a better way to do this,
-                                  but not now. */
+#define CR_MAXARGLEN 80         /* why 80? why not? it's > hostname lengths */
+#define CR_MAXARGS 3            /* There's a better way to do this,
+                                   but not now. */
 
 /*
  * Some symbols for easy reading
@@ -100,8 +105,8 @@ typedef int (*crule_funcptr) (int, void **);
 struct crule_treestruct {
   crule_funcptr funcptr;
   int numargs;
-  void *arg[CR_MAXARGS];       /* For operators arg points to a tree element;
-                                  for functions arg points to a char string. */
+  void *arg[CR_MAXARGS];        /* For operators arg points to a tree element;
+                                   for functions arg points to a char string. */
 };
 
 typedef struct crule_treestruct crule_treeelem;
@@ -138,21 +143,21 @@ void print_tree(crule_treeptr);
 
 /* error messages */
 char *crule_errstr[] = {
-  "Unknown error",             /* NOERR? - for completeness */
-  "Unexpected token",          /* UNEXPCTTOK */
-  "Unknown token",             /* UNKNWTOK */
-  "And expr expected",         /* EXPCTAND */
-  "Or expr expected",          /* EXPCTOR */
-  "Primary expected",          /* EXPCTPRIM */
-  "( expected",                        /* EXPCTOPEN */
-  ") expected",                        /* EXPCTCLOSE */
-  "Unknown function",          /* UNKNWFUNC */
-  "Argument mismatch"          /* ARGMISMAT */
+  "Unknown error",              /* NOERR? - for completeness */
+  "Unexpected token",           /* UNEXPCTTOK */
+  "Unknown token",              /* UNKNWTOK */
+  "And expr expected",          /* EXPCTAND */
+  "Or expr expected",           /* EXPCTOR */
+  "Primary expected",           /* EXPCTPRIM */
+  "( expected",                 /* EXPCTOPEN */
+  ") expected",                 /* EXPCTCLOSE */
+  "Unknown function",           /* UNKNWFUNC */
+  "Argument mismatch"           /* ARGMISMAT */
 };
 
 /* function table - null terminated */
 struct crule_funclistent {
-  char name[15];               /* MAXIMUM FUNCTION NAME LENGTH IS 14 CHARS!! */
+  char name[15];                /* MAXIMUM FUNCTION NAME LENGTH IS 14 CHARS!! */
   int reqnumargs;
   crule_funcptr funcptr;
 };
@@ -163,16 +168,16 @@ struct crule_funclistent crule_funclist[] = {
   {"directcon", 1, crule_directcon},
   {"via", 2, crule_via},
   {"directop", 0, crule_directop},
-  {"", 0, NULL}                        /* this must be here to mark end of list */
+  {"", 0, NULL}                 /* this must be here to mark end of list */
 };
 
 #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
-static int crule_connected(int UNUSED(numargs), void *crulearg[])
+static int crule_connected(int numargs, void *crulearg[])
 {
-  aClient *acptr;
+  struct Client *acptr;
 
   /* taken from m_links */
-  for (acptr = client; acptr; acptr = acptr->next)
+  for (acptr = GlobalClientList; acptr; acptr = acptr->next)
   {
     if (!IsServer(acptr) && !IsMe(acptr))
       continue;
@@ -183,22 +188,22 @@ static int crule_connected(int UNUSED(numargs), void *crulearg[])
   return (0);
 }
 #else
-static int crule_connected(int UNUSED(numargs), void **UNUSED(crulearg))
+static int crule_connected(int numargs, void **crulearg)
 {
   return (0);
 }
 #endif
 
 #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
-static int crule_directcon(int UNUSED(numargs), void *crulearg[])
+static int crule_directcon(int numargs, void *crulearg[])
 {
   int i;
-  aClient *acptr;
+  struct Client *acptr;
 
   /* adapted from m_trace and exit_one_client */
-  for (i = 0; i <= highest_fd; i++)
+  for (i = 0; i <= HighestFd; i++)
   {
-    if (!(acptr = loc_clients[i]) || !IsServer(acptr))
+    if (!(acptr = LocalClientArray[i]) || !IsServer(acptr))
       continue;
     if (match((char *)crulearg[0], acptr->name))
       continue;
@@ -207,47 +212,47 @@ static int crule_directcon(int UNUSED(numargs), void *crulearg[])
   return (0);
 }
 #else
-static int crule_directcon(int UNUSED(numargs), void **UNUSED(crulearg))
+static int crule_directcon(int numargs, void **crulearg)
 {
   return (0);
 }
 #endif
 
 #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
-static int crule_via(int UNUSED(numargs), void *crulearg[])
+static int crule_via(int numargs, void *crulearg[])
 {
-  aClient *acptr;
+  struct Client *acptr;
 
   /* adapted from m_links */
-  for (acptr = client; acptr; acptr = acptr->next)
+  for (acptr = GlobalClientList; acptr; acptr = acptr->next)
   {
     if (!IsServer(acptr) && !IsMe(acptr))
       continue;
     if (match((char *)crulearg[1], acptr->name))
       continue;
-    if (match((char *)crulearg[0], (loc_clients[acptr->from->fd])->name))
+    if (match((char *)crulearg[0], (LocalClientArray[acptr->from->fd])->name))
       continue;
     return (1);
   }
   return (0);
 }
 #else
-static int crule_via(int UNUSED(numargs), void **UNUSED(crulearg))
+static int crule_via(int numargs, void **crulearg)
 {
   return (0);
 }
 #endif
 
-static int crule_directop(int UNUSED(numargs), void **UNUSED(crulearg))
+static int crule_directop(int numargs, void **crulearg)
 {
 #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
   int i;
-  aClient *acptr;
+  struct Client *acptr;
 
   /* adapted from m_trace */
-  for (i = 0; i <= highest_fd; i++)
+  for (i = 0; i <= HighestFd; i++)
   {
-    if (!(acptr = loc_clients[i]) || !IsAnOper(acptr))
+    if (!(acptr = LocalClientArray[i]) || !IsAnOper(acptr))
       continue;
     return (1);
   }
@@ -255,26 +260,26 @@ static int crule_directop(int UNUSED(numargs), void **UNUSED(crulearg))
   return (0);
 }
 
-static int crule__andor(int UNUSED(numargs), void *crulearg[])
+static int crule__andor(int numargs, void *crulearg[])
 {
   int result1;
 
   result1 = ((crule_treeptr) crulearg[0])->funcptr
       (((crule_treeptr) crulearg[0])->numargs,
       ((crule_treeptr) crulearg[0])->arg);
-  if (crulearg[2])             /* or */
+  if (crulearg[2])              /* or */
     return (result1 ||
-       ((crule_treeptr) crulearg[1])->funcptr
-       (((crule_treeptr) crulearg[1])->numargs,
-       ((crule_treeptr) crulearg[1])->arg));
+        ((crule_treeptr) crulearg[1])->funcptr
+        (((crule_treeptr) crulearg[1])->numargs,
+        ((crule_treeptr) crulearg[1])->arg));
   else
     return (result1 &&
-       ((crule_treeptr) crulearg[1])->funcptr
-       (((crule_treeptr) crulearg[1])->numargs,
-       ((crule_treeptr) crulearg[1])->arg));
+        ((crule_treeptr) crulearg[1])->funcptr
+        (((crule_treeptr) crulearg[1])->numargs,
+        ((crule_treeptr) crulearg[1])->arg));
 }
 
-static int crule__not(int UNUSED(numargs), void *crulearg[])
+static int crule__not(int numargs, void *crulearg[])
 {
   return (!((crule_treeptr) crulearg[0])->funcptr
       (((crule_treeptr) crulearg[0])->numargs,
@@ -299,49 +304,49 @@ static int crule_gettoken(int *next_tokp, char **ruleptr)
     {
       case ' ':
       case '\t':
-       break;
+        break;
       case '&':
-       if (pending == '\0')
-         pending = '&';
-       else if (pending == '&')
-         *next_tokp = CR_AND;
-       else
-         return (CR_UNKNWTOK);
-       break;
+        if (pending == '\0')
+          pending = '&';
+        else if (pending == '&')
+          *next_tokp = CR_AND;
+        else
+          return (CR_UNKNWTOK);
+        break;
       case '|':
-       if (pending == '\0')
-         pending = '|';
-       else if (pending == '|')
-         *next_tokp = CR_OR;
-       else
-         return (CR_UNKNWTOK);
-       break;
+        if (pending == '\0')
+          pending = '|';
+        else if (pending == '|')
+          *next_tokp = CR_OR;
+        else
+          return (CR_UNKNWTOK);
+        break;
       case '!':
-       *next_tokp = CR_NOT;
-       break;
+        *next_tokp = CR_NOT;
+        break;
       case '(':
-       *next_tokp = CR_OPENPAREN;
-       break;
+        *next_tokp = CR_OPENPAREN;
+        break;
       case ')':
-       *next_tokp = CR_CLOSEPAREN;
-       break;
+        *next_tokp = CR_CLOSEPAREN;
+        break;
       case ',':
-       *next_tokp = CR_COMMA;
-       break;
+        *next_tokp = CR_COMMA;
+        break;
       case '\0':
-       (*ruleptr)--;
-       *next_tokp = CR_END;
-       break;
+        (*ruleptr)--;
+        *next_tokp = CR_END;
+        break;
       case ':':
-       *next_tokp = CR_END;
-       break;
+        *next_tokp = CR_END;
+        break;
       default:
-       if ((isAlpha(*(--(*ruleptr)))) || (**ruleptr == '*') ||
-           (**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
-         *next_tokp = CR_WORD;
-       else
-         return (CR_UNKNWTOK);
-       break;
+        if ((IsAlpha(*(--(*ruleptr)))) || (**ruleptr == '*') ||
+            (**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
+          *next_tokp = CR_WORD;
+        else
+          return (CR_UNKNWTOK);
+        break;
     }
   return CR_NOERR;
 }
@@ -353,7 +358,7 @@ static void crule_getword(char *word, int *wordlenp, size_t maxlen,
 
   word_ptr = word;
   while ((size_t)(word_ptr - word) < maxlen
-      && (isAlnum(**ruleptr)
+      && (IsAlnum(**ruleptr)
       || **ruleptr == '*' || **ruleptr == '?'
       || **ruleptr == '.' || **ruleptr == '-'))
     *word_ptr++ = *(*ruleptr)++;
@@ -392,17 +397,17 @@ char *crule_parse(char *rule)
   if ((errcode = crule_gettoken(&next_tok, &ruleptr)) == CR_NOERR)
   {
     if ((errcode = crule_parseorexpr(&ruleroot, &next_tok, &ruleptr))
-       == CR_NOERR)
+        == CR_NOERR)
     {
       if (ruleroot != NULL)
       {
-       if (next_tok == CR_END)
-         return ((char *)ruleroot);
-       else
-         errcode = CR_UNEXPCTTOK;
+        if (next_tok == CR_END)
+          return ((char *)ruleroot);
+        else
+          errcode = CR_UNEXPCTTOK;
       }
       else
-       errcode = CR_EXPCTOR;
+        errcode = CR_EXPCTOR;
     }
   }
   if (ruleroot != NULL)
@@ -428,7 +433,7 @@ static int crule_parseorexpr(crule_treeptr * orrootp, int *next_tokp,
     errcode = crule_parseandexpr(&andexpr, next_tokp, ruleptr);
     if ((errcode == CR_NOERR) && (*next_tokp == CR_OR))
     {
-      orptr = (crule_treeptr) RunMalloc(sizeof(crule_treeelem));
+      orptr = (crule_treeptr) MyMalloc(sizeof(crule_treeelem));
 #ifdef CR_DEBUG
       fprintf(stderr, "allocating or element at %ld\n", orptr);
 #endif
@@ -437,32 +442,32 @@ static int crule_parseorexpr(crule_treeptr * orrootp, int *next_tokp,
       orptr->arg[2] = (void *)1;
       if (*orrootp != NULL)
       {
-       (*orrootp)->arg[1] = andexpr;
-       orptr->arg[0] = *orrootp;
+        (*orrootp)->arg[1] = andexpr;
+        orptr->arg[0] = *orrootp;
       }
       else
-       orptr->arg[0] = andexpr;
+        orptr->arg[0] = andexpr;
       *orrootp = orptr;
     }
     else
     {
       if (*orrootp != NULL)
       {
-       if (andexpr != NULL)
-       {
-         (*orrootp)->arg[1] = andexpr;
-         return (errcode);
-       }
-       else
-       {
-         (*orrootp)->arg[1] = NULL;    /* so free doesn't seg fault */
-         return (CR_EXPCTAND);
-       }
+        if (andexpr != NULL)
+        {
+          (*orrootp)->arg[1] = andexpr;
+          return (errcode);
+        }
+        else
+        {
+          (*orrootp)->arg[1] = NULL;    /* so free doesn't seg fault */
+          return (CR_EXPCTAND);
+        }
       }
       else
       {
-       *orrootp = andexpr;
-       return (errcode);
+        *orrootp = andexpr;
+        return (errcode);
       }
     }
     if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
@@ -484,7 +489,7 @@ static int crule_parseandexpr(crule_treeptr * androotp, int *next_tokp,
     errcode = crule_parseprimary(&primary, next_tokp, ruleptr);
     if ((errcode == CR_NOERR) && (*next_tokp == CR_AND))
     {
-      andptr = (crule_treeptr) RunMalloc(sizeof(crule_treeelem));
+      andptr = (crule_treeptr) MyMalloc(sizeof(crule_treeelem));
 #ifdef CR_DEBUG
       fprintf(stderr, "allocating and element at %ld\n", andptr);
 #endif
@@ -493,32 +498,32 @@ static int crule_parseandexpr(crule_treeptr * androotp, int *next_tokp,
       andptr->arg[2] = (void *)0;
       if (*androotp != NULL)
       {
-       (*androotp)->arg[1] = primary;
-       andptr->arg[0] = *androotp;
+        (*androotp)->arg[1] = primary;
+        andptr->arg[0] = *androotp;
       }
       else
-       andptr->arg[0] = primary;
+        andptr->arg[0] = primary;
       *androotp = andptr;
     }
     else
     {
       if (*androotp != NULL)
       {
-       if (primary != NULL)
-       {
-         (*androotp)->arg[1] = primary;
-         return (errcode);
-       }
-       else
-       {
-         (*androotp)->arg[1] = NULL;   /* so free doesn't seg fault */
-         return (CR_EXPCTPRIM);
-       }
+        if (primary != NULL)
+        {
+          (*androotp)->arg[1] = primary;
+          return (errcode);
+        }
+        else
+        {
+          (*androotp)->arg[1] = NULL;   /* so free doesn't seg fault */
+          return (CR_EXPCTPRIM);
+        }
       }
       else
       {
-       *androotp = primary;
-       return (errcode);
+        *androotp = primary;
+        return (errcode);
       }
     }
     if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
@@ -540,44 +545,44 @@ static int crule_parseprimary(crule_treeptr * primrootp,
     switch (*next_tokp)
     {
       case CR_OPENPAREN:
-       if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
-         break;
-       if ((errcode = crule_parseorexpr(insertionp, next_tokp,
-           ruleptr)) != CR_NOERR)
-         break;
-       if (*insertionp == NULL)
-       {
-         errcode = CR_EXPCTAND;
-         break;
-       }
-       if (*next_tokp != CR_CLOSEPAREN)
-       {
-         errcode = CR_EXPCTCLOSE;
-         break;
-       }
-       errcode = crule_gettoken(next_tokp, ruleptr);
-       break;
+        if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+          break;
+        if ((errcode = crule_parseorexpr(insertionp, next_tokp,
+            ruleptr)) != CR_NOERR)
+          break;
+        if (*insertionp == NULL)
+        {
+          errcode = CR_EXPCTAND;
+          break;
+        }
+        if (*next_tokp != CR_CLOSEPAREN)
+        {
+          errcode = CR_EXPCTCLOSE;
+          break;
+        }
+        errcode = crule_gettoken(next_tokp, ruleptr);
+        break;
       case CR_NOT:
-       *insertionp = (crule_treeptr) RunMalloc(sizeof(crule_treeelem));
+        *insertionp = (crule_treeptr) MyMalloc(sizeof(crule_treeelem));
 #ifdef CR_DEBUG
-       fprintf(stderr, "allocating primary element at %ld\n", *insertionp);
+        fprintf(stderr, "allocating primary element at %ld\n", *insertionp);
 #endif
-       (*insertionp)->funcptr = crule__not;
-       (*insertionp)->numargs = 1;
-       (*insertionp)->arg[0] = NULL;
-       insertionp = (crule_treeptr *) & ((*insertionp)->arg[0]);
-       if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
-         break;
-       continue;
+        (*insertionp)->funcptr = crule__not;
+        (*insertionp)->numargs = 1;
+        (*insertionp)->arg[0] = NULL;
+        insertionp = (crule_treeptr *) & ((*insertionp)->arg[0]);
+        if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
+          break;
+        continue;
       case CR_WORD:
-       errcode = crule_parsefunction(insertionp, next_tokp, ruleptr);
-       break;
+        errcode = crule_parsefunction(insertionp, next_tokp, ruleptr);
+        break;
       default:
-       if (*primrootp == NULL)
-         errcode = CR_NOERR;
-       else
-         errcode = CR_EXPCTPRIM;
-       break;
+        if (*primrootp == NULL)
+          errcode = CR_NOERR;
+        else
+          errcode = CR_EXPCTPRIM;
+        break;
     }
     return (errcode);
   }
@@ -600,25 +605,25 @@ static int crule_parsefunction(crule_treeptr * funcrootp,
   {
     for (funcnum = 0;; funcnum++)
     {
-      if (strCasediff(crule_funclist[funcnum].name, funcname) == 0)
-       break;
+      if (0 == ircd_strcmp(crule_funclist[funcnum].name, funcname))
+        break;
       if (crule_funclist[funcnum].name[0] == '\0')
-       return (CR_UNKNWFUNC);
+        return (CR_UNKNWFUNC);
     }
     if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
       return (errcode);
-    *funcrootp = (crule_treeptr) RunMalloc(sizeof(crule_treeelem));
+    *funcrootp = (crule_treeptr) MyMalloc(sizeof(crule_treeelem));
 #ifdef CR_DEBUG
     fprintf(stderr, "allocating function element at %ld\n", *funcrootp);
 #endif
-    (*funcrootp)->funcptr = NULL;      /* for freeing aborted trees */
+    (*funcrootp)->funcptr = NULL;       /* for freeing aborted trees */
     if ((errcode =
-       crule_parsearglist(*funcrootp, next_tokp, ruleptr)) != CR_NOERR)
+        crule_parsearglist(*funcrootp, next_tokp, ruleptr)) != CR_NOERR)
       return (errcode);
     if (*next_tokp != CR_CLOSEPAREN)
       return (CR_EXPCTCLOSE);
     if ((crule_funclist[funcnum].reqnumargs != (*funcrootp)->numargs) &&
-       (crule_funclist[funcnum].reqnumargs != -1))
+        (crule_funclist[funcnum].reqnumargs != -1))
       return (CR_ARGMISMAT);
     if ((errcode = crule_gettoken(next_tokp, ruleptr)) != CR_NOERR)
       return (errcode);
@@ -646,37 +651,37 @@ static int crule_parsearglist(crule_treeptr argrootp, int *next_tokp,
     switch (*next_tokp)
     {
       case CR_WORD:
-       crule_getword(word, &wordlen, CR_MAXARGLEN - 1, ruleptr);
-       if (currarg[0] != '\0')
-       {
-         if ((arglen + wordlen) < (CR_MAXARGLEN - 1))
-         {
-           strcat(currarg, " ");
-           strcat(currarg, word);
-           arglen += wordlen + 1;
-         }
-       }
-       else
-       {
-         strcpy(currarg, word);
-         arglen = wordlen;
-       }
-       errcode = crule_gettoken(next_tokp, ruleptr);
-       break;
+        crule_getword(word, &wordlen, CR_MAXARGLEN - 1, ruleptr);
+        if (currarg[0] != '\0')
+        {
+          if ((arglen + wordlen) < (CR_MAXARGLEN - 1))
+          {
+            strcat(currarg, " ");
+            strcat(currarg, word);
+            arglen += wordlen + 1;
+          }
+        }
+        else
+        {
+          strcpy(currarg, word);
+          arglen = wordlen;
+        }
+        errcode = crule_gettoken(next_tokp, ruleptr);
+        break;
       default:
 #if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
-       collapse(currarg);
+        collapse(currarg);
 #endif
-       if (!BadPtr(currarg))
-       {
-         DupString(argelemp, currarg);
-         argrootp->arg[argrootp->numargs++] = (void *)argelemp;
-       }
-       if (*next_tokp != CR_COMMA)
-         return (CR_NOERR);
-       currarg[0] = '\0';
-       errcode = crule_gettoken(next_tokp, ruleptr);
-       break;
+        if (!BadPtr(currarg))
+        {
+          DupString(argelemp, currarg);
+          argrootp->arg[argrootp->numargs++] = (void *)argelemp;
+        }
+        if (*next_tokp != CR_COMMA)
+          return (CR_NOERR);
+        currarg[0] = '\0';
+        errcode = crule_gettoken(next_tokp, ruleptr);
+        break;
     }
   }
   return (errcode);
@@ -708,12 +713,12 @@ void crule_free(char **elem)
   {
     numargs = (*((crule_treeptr *) elem))->numargs;
     for (arg = 0; arg < numargs; arg++)
-      RunFree((char *)(*((crule_treeptr *) elem))->arg[arg]);
+      MyFree((*((crule_treeptr *) elem))->arg[arg]);
   }
 #ifdef CR_DEBUG
   fprintf(stderr, "freeing element at %ld\n", *elem);
 #endif
-  RunFree(*elem);
+  MyFree(*elem);
   *elem = NULL;
 }
 
@@ -744,15 +749,15 @@ static void print_tree(crule_treeptr printelem)
     for (funcnum = 0;; funcnum++)
     {
       if (printelem->funcptr == crule_funclist[funcnum].funcptr)
-       break;
+        break;
       if (crule_funclist[funcnum].funcptr == NULL)
-       MyCoreDump;
+        MyCoreDump;
     }
     printf("%s(", crule_funclist[funcnum].name);
     for (arg = 0; arg < printelem->numargs; arg++)
     {
       if (arg != 0)
-       printf(",");
+        printf(",");
       printf("%s", (char *)printelem->arg[arg]);
     }
     printf(") ");
@@ -770,7 +775,7 @@ int main(void)
   printf("rule: ");
   while (fgets(indata, 256, stdin) != NULL)
   {
-    indata[strlen(indata) - 1] = '\0'; /* lose the newline */
+    indata[strlen(indata) - 1] = '\0';  /* lose the newline */
     if ((rule = crule_parse(indata)) != NULL)
     {
       printf("equivalent rule: ");
index ee65d9b0a85021eb1503838902184a755cc81c55..dfe6305e48c49b180dbff1be96f25fb4b641bb99 100644 (file)
@@ -2,24 +2,14 @@
  * copyright 1991, all rights reserved.
  * You can use this code as long as my name stays with it.
  */
-
+#define _XOPEN_SOURCE
+#define _XOPEN_VERSION 4
+#define _XOPEN_SOURCE_EXTENDED
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <time.h>
-#if HAVE_UNISTD_H
 #include <unistd.h>
-#endif
-#include "../../config/setup.h"
-#if STDC_HEADERS
-# include <string.h>
-#else
-# ifndef HAVE_STRCHR
-#  define strchr index
-# endif
-char *strchr();
-#endif
-
-extern char *getpass();
 
 int main(int argc, char *argv[])
 {
index 95aedd9ad6be01668423160603e7c3ec40e2c625..b9dd0b88b041ce31fa2897001df5dd06579df3ec 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
 #include "dbuf.h"
-#include "common.h"
-#include "sys.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "send.h"
+#include "sys.h"       /* MIN */
 
 #include <assert.h>
 #include <string.h>
 
-RCSTAG_CC("$Id$");
-
 /*
  * dbuf is a collection of functions which can be used to
  * maintain a dynamic buffering of a byte stream.
@@ -42,10 +43,10 @@ static struct DBufBuffer *dbufFreeList = 0;
 #define DBUF_SIZE 2048
 
 struct DBufBuffer {
-  struct DBufBuffer *next;     /* Next data buffer, NULL if last */
-  char *start;                 /* data starts here */
-  char *end;                   /* data ends here */
-  char data[DBUF_SIZE];                /* Actual data stored here */
+  struct DBufBuffer *next;      /* Next data buffer, NULL if last */
+  char *start;                  /* data starts here */
+  char *end;                    /* data ends here */
+  char data[DBUF_SIZE];         /* Actual data stored here */
 };
 
 void dbuf_count_memory(size_t *allocated, size_t *used)
@@ -62,20 +63,17 @@ void dbuf_count_memory(size_t *allocated, size_t *used)
  */
 static struct DBufBuffer *dbuf_alloc(void)
 {
-  struct DBufBuffer *db = dbufFreeList;
+  struct DBufBufferdb = dbufFreeList;
 
-  if (db)
-  {
-    ++DBufUsedCount;
+  if (db) {
     dbufFreeList = db->next;
+    ++DBufUsedCount;
   }
-  else if (DBufAllocCount * DBUF_SIZE < BUFFERPOOL)
-  {
-    if ((db = (struct DBufBuffer *)RunMalloc(sizeof(struct DBufBuffer))))
-    {
-      ++DBufAllocCount;
-      ++DBufUsedCount;
-    }
+  else if (DBufAllocCount * DBUF_SIZE < BUFFERPOOL) {
+    db = (struct DBufBuffer*) MyMalloc(sizeof(struct DBufBuffer));
+    assert(0 != db);
+    ++DBufAllocCount;
+    ++DBufUsedCount;
   }
   return db;
 }
@@ -125,8 +123,8 @@ static int dbuf_malloc_error(struct DBuf *dyn)
  */
 int dbuf_put(struct DBuf *dyn, const char *buf, size_t length)
 {
-  struct DBufBuffer **h;
-  struct DBufBuffer *db;
+  struct DBufBuffer** h;
+  struct DBufBuffer*  db;
   size_t chunk;
 
   assert(0 != dyn);
@@ -146,23 +144,41 @@ int dbuf_put(struct DBuf *dyn, const char *buf, size_t length)
    */
   dyn->length += length;
 
-  for (; length > 0; h = &(db->next))
-  {
-    if (0 == (db = *h))
-    {
-      if (0 == (db = dbuf_alloc()))
-       return dbuf_malloc_error(dyn);
-
+  for (; length > 0; h = &(db->next)) {
+    if (0 == (db = *h)) {
+      if (0 == (db = dbuf_alloc())) {
+#if defined(HAS_FERGUSON_FLUSHER)
+        /*
+         * from "Married With Children" episode were Al bought a REAL toilet
+         * on the black market because he was tired of the wimpy water
+         * conserving toilets they make these days --Bleep
+         */
+        /*
+         * Apparently this doesn't work, the server _has_ to
+         * dump a few clients to handle the load. A fully loaded
+         * server cannot handle a net break without dumping some
+         * clients. If we flush the connections here under a full
+         * load we may end up starving the kernel for mbufs and
+         * crash the machine
+         */
+        /*
+         * attempt to recover from buffer starvation before
+         * bailing this may help servers running out of memory
+         */
+        flush_sendq_except(dyn);
+        if (0 == (db = dbuf_alloc()))
+#endif
+          return dbuf_malloc_error(dyn);
+      }
       dyn->tail = db;
       *h = db;
       db->next = 0;
       db->start = db->end = db->data;
     }
     chunk = (db->data + DBUF_SIZE) - db->end;
-    if (chunk)
-    {
+    if (chunk) {
       if (chunk > length)
-       chunk = length;
+        chunk = length;
 
       memcpy(db->end, buf, chunk);
 
@@ -308,7 +324,7 @@ static size_t dbuf_flush(struct DBuf *dyn)
   /*
    * flush extra line terms
    */
-  while (isEol(*db->start))
+  while (IsEol(*db->start))
   {
     if (++db->start == db->end)
     {
@@ -316,9 +332,9 @@ static size_t dbuf_flush(struct DBuf *dyn)
       dbuf_free(db);
       if (0 == (db = dyn->head))
       {
-       dyn->tail = 0;
-       dyn->length = 0;
-       break;
+        dyn->tail = 0;
+        dyn->length = 0;
+        break;
       }
     }
     --dyn->length;
@@ -361,8 +377,8 @@ size_t dbuf_getmsg(struct DBuf *dyn, char *buf, size_t length)
    */
   while (length > 0)
   {
-    end = MIN(db->end, (start + length));
-    while (start < end && !isEol(*start))
+    end = IRCD_MIN(db->end, (start + length));
+    while (start < end && !IsEol(*start))
       *buf++ = *start++;
 
     count = start - db->start;
diff --git a/ircd/fda.c b/ircd/fda.c
new file mode 100644 (file)
index 0000000..6349384
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * fda.c - Free Debug Allocator
+ * Copyright (C) 1997 Thomas Helvey <tomh@inxpress.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * NOTE: Do not include fda.h here
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if !defined(NDEBUG)
+
+#ifndef HTABLE_SIZE
+#define HTABLE_SIZE 65539
+/* #define HTABLE_SIZE 16339 */ /* prime around 16K */
+/* #define HTABLE_SIZE 251 */
+#endif
+
+#define SHRED_BYTE 0xcd
+#if 0
+#if defined(_i386)
+#define SHRED_BYTE 0xcd
+#else
+#define SHRED_BYTE 0xa3
+#endif /* !_i386 */
+#endif /* 0 */
+
+#define SHRED_MEM(a,s)  memset((a), SHRED_BYTE, (s))
+
+#define S_SIZE sizeof(size_t)
+#define BYTE_PTR(x) (unsigned char*)((x))
+
+#define BASE_PTR(p) (BYTE_PTR(p) - S_SIZE)
+#define BASE_SIZE(s) ((((s) + (S_SIZE - 1) + 2 * S_SIZE) / S_SIZE) * S_SIZE)
+
+struct Location {
+  struct Location* next;     /* list next pointer */
+  struct Location* prev;     /* list prev pointer */
+  const char* file;          /* file name for allocation */
+  int         line;          /* line allocated on */
+  int         count;         /* number of allocations for this location */
+};
+
+struct BlkHdr {
+  struct BlkHdr*   next;       /* Next block in list */
+  void*            buf;        /* Allocated buffer */
+  size_t           size;       /* Size of allocated buffer */
+  int              ref;        /* Buffer referenced flag */
+  time_t           timestamp;  /* Time memory was allocated */
+  struct Location* location;   /* Where the allocation took place */
+}; 
+
+typedef struct BlkHdr   BlkHdr;
+typedef struct Location Location;
+
+/*
+ * lowmem_fn - default low memory handler
+ */
+static void lowmem_fn(void)
+{
+  return;
+}
+
+/*
+ * nomem_fn - default no memory handler
+ */
+static void nomem_fn(void)
+{
+  exit(2);
+}
+
+static void (*lowMemFn)(void) = lowmem_fn;  /* default low memory handler */
+static void (*noMemFn)(void)  = nomem_fn;   /* default no memory handler */
+
+/* begin/end marker signature */
+static const size_t DEADBEEF = 0xdeadbeef; 
+static size_t  byteCount = 0;          /* count of currently allocated bytes */
+static size_t  blockCount = 0;         /* count of allocated blocks */
+static size_t  byteLimit = 0xffffffff; /* memory size limiter */
+static BlkHdr* bhTab[HTABLE_SIZE];     /* hash table for allocated blocks */
+static Location* locationList = 0;     /* linked list of memory locations */
+
+/*
+ * fda_set_lowmem_handler - set handler for low memory conditions 
+ *  this will be called if malloc fails once
+ */
+void fda_set_lowmem_handler(void (*fn)(void))
+{
+  lowMemFn = (fn) ? fn : lowmem_fn;
+}
+
+/*
+ * set_nomem_handler - set handler for no memory conditions
+ * The nomem_handler is called if lowMemFn returns and malloc fails a second
+ * time, the library will assert if lowMemFn is allowed to return
+ */
+void fda_set_nomem_handler(void (*fn)(void))
+{
+  noMemFn = (fn) ? fn : nomem_fn;
+}
+
+/*
+ * fda_get_byte_count - returns the client memory allocated in bytes
+ */
+size_t fda_get_byte_count(void)
+{
+  return byteCount;
+}
+
+/*
+ * fda_get_block_count - returns the number of blocks allocated
+ */
+size_t fda_get_block_count(void)
+{
+  return blockCount;
+}
+
+/*
+ * findLocation - finds a location on the list, this
+ * only compares pointers so it should only be used with
+ * ANSI __FILE__ and __LINE__ macros.
+ */
+static Location* findLocation(const char* file, int line)
+{
+  Location* location = locationList;
+  for ( ; location; location = location->next) {
+    if (file == location->file && line == location->line)
+      return location;
+  }
+  return 0;
+}
+
+/*
+ * addLocation - adds a allocation location to the list
+ * returns a pointer to the new location
+ */
+static Location* addLocation(const char* file, int line)
+{
+  Location* location;
+  assert(0 != file);
+  if ((location = (Location*) malloc(sizeof(Location))) != 0) {
+    location->next = locationList;
+    location->prev = 0;
+    location->file = file;
+    location->line = line;
+    location->count = 0;
+    if (location->next)
+      location->next->prev = location;
+    locationList = location;
+  }
+  return location;
+}
+
+/*
+ * freeLocation - frees a file/line info location
+ */
+static void freeLocation(Location* location)
+{
+  assert(0 != location);
+  assert(0 == location->count);
+
+  if (0 != location->next)
+    location->next->prev = location->prev;
+  if (0 != location->prev)
+    location->prev->next = location->next;
+  else
+    locationList = location->next;
+  free(location);
+}
+
+/*
+ * hash_ptr - simple pointer hash function
+ */
+static unsigned long hash_ptr(const void* p)
+{
+  return ((unsigned long) p >> 3) % HTABLE_SIZE;
+#if 0
+  return (((unsigned long) p >> 3) ^ ~((unsigned long) p)) % HTABLE_SIZE;
+  return (((unsigned long) p >> 3) | ((unsigned long) p) << 3) % HTABLE_SIZE;
+#endif
+}
+
+/*
+ * find_blk_exhaustive - find a block by scanning the
+ * entire hash table. This function finds blocks that do not
+ * start at the pointer returned from Malloc.
+ */
+static BlkHdr* find_blk_exhaustive(const void* p)
+{
+  int i;
+  BlkHdr* bh;
+
+  for (i = 0; i < HTABLE_SIZE; ++i) {
+    for (bh = bhTab[i]; bh; bh = bh->next) {
+      if (bh->buf <= p && BYTE_PTR(p) < (BYTE_PTR(bh->buf) + bh->size))
+        return bh;
+    }
+  }
+  return 0;
+}
+
+/*
+ * fda_dump_hash - enumerate hash table link counts
+ */
+void fda_dump_hash(void (*enumfn)(int, int))
+{
+  int i = 0;
+  BlkHdr* bh;
+  for (i = 0; i < HTABLE_SIZE; ++i) {
+    int count = 0;
+    for (bh = bhTab[i]; bh; bh = bh->next)
+      ++count;
+    (*enumfn)(i, count);
+  }
+}
+/*
+ * find_blk - return the block struct associated with the
+ * pointer p.
+ */
+static BlkHdr* find_blk(const void* p)
+{
+  BlkHdr* bh = bhTab[hash_ptr(p)];
+  for ( ; bh; bh = bh->next) {
+    if (p == bh->buf)
+      return bh;
+  }
+  return find_blk_exhaustive(p);
+}
+
+/*
+ * make_blk - create a block header and add it to the hash table
+ */
+static int make_blk(unsigned char* p, size_t size, Location* loc)
+{
+  BlkHdr* bh;
+
+  assert(0 != p);
+  assert(0 < size);
+  assert(0 != loc);
+
+  if ((bh = (BlkHdr*) malloc(sizeof(BlkHdr))) != 0) {
+    unsigned long h = hash_ptr(p);
+    bh->ref       = 0;
+    bh->buf       = p;
+    bh->size      = size;
+    bh->location  = loc;
+    bh->timestamp = time(0);
+    bh->next      = bhTab[h];
+    bhTab[h]      = bh;
+    ++bh->location->count;
+    byteCount += size;
+    ++blockCount;
+  }
+  return (0 != bh);
+}
+
+/*
+ * free_blk - remove a block header and free it
+ */
+static void free_blk(const void* p)
+{
+  BlkHdr* bh_prev = 0;
+  BlkHdr* bh;
+  unsigned long h = hash_ptr(p);
+
+  for (bh = bhTab[h]; bh; bh = bh->next) {
+    if (p == bh->buf) {
+      if (0 == bh_prev)
+        bhTab[h] = bh->next;
+      else
+        bh_prev->next = bh->next;
+      break;
+    }
+    bh_prev = bh;
+  }
+  /* 
+   * if bh is NULL p was not allocated here 
+   */
+  assert(0 != bh);
+  assert(bh->location->count > 0);
+  if (--bh->location->count == 0)
+    freeLocation(bh->location);
+
+  byteCount -= bh->size;
+  --blockCount;
+
+  SHRED_MEM(bh, sizeof(BlkHdr));
+  free(bh);
+}
+
+/*
+ * update_blk - update block info, rehash if pointers are different,
+ * update location info if needed
+ */
+static void update_blk(void* p, void* np, size_t size, const char* file, int line)
+{
+  BlkHdr* bh;
+  if (p != np) {
+    BlkHdr* bh_prev = 0;
+    unsigned long h = hash_ptr(p);
+
+    /* 
+     * remove the old entry from the hash table 
+     */
+    for (bh = bhTab[h]; bh; bh = bh->next) {
+      if (p == bh->buf) {
+        if (0 == bh_prev)
+          bhTab[h] = bh->next;
+        else
+          bh_prev->next = bh->next;
+        /* 
+         * put it back in the hash table at hash(np) 
+         */
+        h = hash_ptr(np);
+        bh->next = bhTab[h];
+        bhTab[h] = bh;
+        break;
+      }
+      bh_prev = bh;
+    }
+  }
+  else
+    bh = find_blk(p);
+  /*
+   * invalid ptr? 
+   */
+  assert(0 != bh);
+  byteCount -= bh->size;
+  byteCount += size;
+  bh->buf = np;
+  bh->size = size;
+  /* 
+   * update location info 
+   */
+  if (bh->location->file != file || bh->location->line != line) {
+    if (--bh->location->count == 0)
+      freeLocation(bh->location);
+    if ((bh->location = findLocation(file, line)) == 0) {
+      if ((bh->location = addLocation(file, line)) == 0)
+        noMemFn();
+    }
+    assert(0 != bh->location);
+    ++bh->location->count;
+  }
+}
+
+/*
+ * fda_sizeof - returns the size of block of memory pointed to by p
+ */
+size_t fda_sizeof(const void* p)
+{
+  BlkHdr* bh = find_blk(p);
+  assert(0 != bh);
+  assert(p == bh->buf);
+  return bh->size;
+}
+
+void fda_set_byte_limit(size_t limit)
+{
+  byteLimit = limit;
+}
+
+/*
+ * fda_clear_refs - clear referenced markers on all blocks
+ */
+void fda_clear_refs(void)
+{
+  int i;
+  BlkHdr* bh;
+
+  for (i = 0; i < HTABLE_SIZE; ++i) {
+    for (bh = bhTab[i]; bh; bh = bh->next)
+      bh->ref = 0;
+  }
+}
+
+/*
+ * fda_set_ref - mark block as referenced
+ */
+void fda_set_ref(const void* p)
+{
+  BlkHdr* bh = find_blk(p);
+  assert(0 != bh);
+  bh->ref = 1;
+}
+
+/*
+ * fda_assert_refs - scan for all blocks and check for null
+ * ptrs and unreferenced (lost) blocks
+ */
+void fda_assert_refs(void)
+{
+  int i;
+  BlkHdr* bh;
+
+  for (i = 0; i < HTABLE_SIZE; ++i) {
+    for (bh = bhTab[i]; bh; bh = bh->next) {
+      assert(0 != bh->buf && 0 < bh->size);
+      assert(1 == bh->ref);
+    }
+  }
+}
+
+/*
+ * valid_ptr - returns true if p points to allocated memory and
+ * has at least size available
+ */
+int valid_ptr(const void* p, size_t size)
+{
+  BlkHdr* bh;
+  assert(0 != p);
+  assert(0 < size);
+
+  bh = find_blk(p);
+  /*
+   * check that there are at least size bytes available from p
+   */
+  assert((BYTE_PTR(p) + size) <= (BYTE_PTR(bh->buf) + bh->size));
+  return 1;
+}
+
+/*
+ * fda_enum_locations - calls enumfn to list file, line, and count
+ * info for allocations, returns the number of locations found
+ */
+int fda_enum_locations(void (*enumfn)(const char*, int, int))
+{
+  int count = 0;
+  Location* location;
+  assert(0 != enumfn);
+  for (location = locationList; location; location = location->next) {
+    (*enumfn)(location->file, location->line, location->count);
+    ++count;
+  }
+  return count;
+}
+
+/*
+ * fda_enum_leaks - scan hash table for leaks and call enumfn to
+ * report them.
+ */
+int fda_enum_leaks(void (*enumfn)(const char*, int, size_t, void*))
+{
+  int count = 0;
+  BlkHdr* bh;
+  int i;
+  for (i = 0; i < HTABLE_SIZE; ++i) {
+    for (bh = bhTab[i]; bh; bh = bh->next) {
+      if (0 == bh->ref) {
+        (*enumfn)(bh->location->file, bh->location->line, bh->size, bh->buf);
+        ++count;
+      }
+    }
+  }
+  return count;
+}
+
+/*
+ * fda_malloc - allocate size chunk of memory and create debug
+ * records for it.
+ */
+void* fda_malloc(size_t size, const char* file, int line)
+{
+  void* p;
+  size_t blk_size;
+  Location* location;
+
+  assert(0 < size);
+  assert(0 != file);
+  assert(sizeof(void*) == sizeof(size_t));
+
+  /*
+   * memory limiter do not allocate more than byteLimit
+   */
+  if ((size + byteCount) > byteLimit)
+    return 0;
+
+  /* 
+   * Make sure that there is enough room for prefix/postfix 
+   * and we get an aligned buffer 
+   */
+  blk_size = BASE_SIZE(size);
+
+  if ((p = malloc(blk_size)) == 0) {
+    lowMemFn();
+    if ((p = malloc(blk_size)) == 0)
+      noMemFn();
+  }
+  /* 
+   * don't allow malloc to fail 
+   */
+  assert(0 != p);
+  /* 
+   * shred the memory and set bounds markers 
+   */
+  SHRED_MEM(p, blk_size);
+  *((size_t*) p) = DEADBEEF;
+  *((size_t*) (BYTE_PTR(p) + blk_size - S_SIZE)) = DEADBEEF;
+
+  /* 
+   * find the location or create a new one 
+   */
+  if (0 == (location = findLocation(file, line))) {
+    if (0 == (location = addLocation(file, line))) {
+      free(p);
+      noMemFn();
+    }
+  }
+  /* 
+   * don't allow noMemFn to return 
+   */
+  assert(0 != location);
+  if (!make_blk(BYTE_PTR(p) + S_SIZE, size, location)) {
+    if (0 == location->count)
+      freeLocation(location);
+    free(p);
+    p = 0;
+    noMemFn();
+  }
+  /* 
+   * don't allow noMemFn to return 
+   */
+  assert(0 != p);
+  return (BYTE_PTR(p) + S_SIZE);
+}
+
+/*
+ * fda_free - check chunk of memory for overruns and free it
+ */
+void fda_free(void* p)
+{
+  if (p) {
+    size_t size;
+    BlkHdr* bh = find_blk(p);
+    void*   bp;
+
+    /* p already freed or not allocated? */
+    assert(0 != bh);
+    assert(p == bh->buf);
+
+    bp = BASE_PTR(p);
+    /* buffer underflow? */
+    assert(DEADBEEF == *((size_t*) bp));
+    /* 
+     * buffer overflow?
+     * Note: it's possible to have up to 3 bytes of unchecked space 
+     * between size and DEADBEEF
+     */
+    size = BASE_SIZE(bh->size);
+    assert(DEADBEEF == *((size_t*)(BYTE_PTR(bp) + size - S_SIZE)));
+    SHRED_MEM(bp, size);
+
+    free_blk(p);
+    free(bp);
+  }
+}
+
+/*
+ * fda_realloc - resize a buffer, force reallocation if new size is
+ * larger than old size
+ */
+void* fda_realloc(void* p, size_t size, const char* file, int line)
+{
+  void* np;
+  size_t old_size;
+  size_t blk_size;
+  /* 
+   * don't allow malloc or free through realloc 
+   */
+  assert(0 != p);
+  assert(0 < size);
+  old_size = fda_sizeof(p);
+  
+  if (size < old_size)
+    SHRED_MEM(BYTE_PTR(p) + size, old_size - size);
+  else if (size > old_size) {
+    void* t = fda_malloc(size, __FILE__, __LINE__);
+    memmove(t, p, old_size);
+    fda_free(p);
+    p = t;
+  }
+  blk_size = BASE_SIZE(size);
+
+  if ((np = realloc(BASE_PTR(p), blk_size)) == 0) {
+    lowMemFn();
+    if ((np = realloc(BASE_PTR(p), blk_size)) == 0)
+      noMemFn();
+  }
+  /* 
+   * don't allow noMemFn to return 
+   */
+  assert(0 != np);
+
+  *((size_t*)(BYTE_PTR(np) + blk_size - S_SIZE)) = DEADBEEF;
+
+  np = BYTE_PTR(np) + S_SIZE;
+  update_blk(p, np, size, file, line);
+  /* 
+   * shred tail 
+   */
+  if (size > old_size)
+    SHRED_MEM(BYTE_PTR(np) + old_size, size - old_size);
+
+  return np;
+}
+
+/*
+ * fda_calloc - allocate 0 initialized buffer nelems * size length
+ */
+void* fda_calloc(size_t nelems, size_t size, const char* file, int line)
+{
+  void* p;
+  assert(0 < nelems);
+  assert(0 < size);
+  assert(0 != file);
+  size *= nelems;
+  p = fda_malloc(size, file, line);
+  memset(p, 0, size);
+  return p;
+}
+
+/*
+ * fda_strdup - duplicates a string returns newly allocated string
+ */
+char* fda_strdup(const char* src, const char* file, int line)
+{
+  char* p;
+  assert(0 != src);
+  p = (char*) fda_malloc(strlen(src) + 1, file, line);
+  strcpy(p, src);
+  return p;
+}
+
+#endif /* !defined(NDEBUG) */
+
diff --git a/ircd/fda_t.c b/ircd/fda_t.c
new file mode 100644 (file)
index 0000000..416bf72
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * fdatest.c - Free Debug Allocator
+ * Copyright (C) 1997 Thomas Helvey <tomh@inxpress.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "fda.h"
+#include <stdio.h>
+#include <assert.h>
+
+#define ALLOC_SIZE 100000
+
+static int empty_slots   = 0;
+static int longest_chain = 0;
+
+void location_enumerator(const char* file, int line, int count)
+{
+  printf("%s line: %d count: %d\n", file, line, count);
+}
+
+void leak_enumerator(const char* file, int line, size_t size, void* ptr)
+{
+  printf("Memory leak: %s: %d - %d bytes (%p)\n", file, line, size, ptr);
+}
+
+void hash_enumerator(int slot, int links)
+{
+  /* printf("s: %d l: %d\n", slot, links); */
+  if (0 == links)
+    ++empty_slots;
+  else if (longest_chain < links)
+    longest_chain = links;
+}
+
+void test_hash(int count)
+{
+  int i = 0;
+  void** bufs = (void**) malloc(sizeof(void*) * count);
+  memset(bufs, 0, sizeof(void*) * count);
+
+  for (i = 0; i < count; ++i)
+    bufs[i] = malloc(i * 2 + 1);
+
+  empty_slots   = 0;
+  longest_chain = 0;
+  
+  fda_dump_hash(hash_enumerator);
+  printf("empty: %d longest: %d\n", empty_slots, longest_chain);
+  
+  for (i = 0; i < count; ++i)
+    bufs[i] = realloc(bufs[i], i * 3 + 1);
+
+  empty_slots   = 0;
+  longest_chain = 0;
+
+  fda_dump_hash(hash_enumerator);
+  printf("empty: %d longest: %d\n", empty_slots, longest_chain);
+  
+  for (i = 0; i < count; ++i) {
+    free(bufs[i]);
+    bufs[i] = malloc(i * 4 + 1);
+  }
+
+  empty_slots   = 0;
+  longest_chain = 0;
+
+  fda_dump_hash(hash_enumerator);
+  printf("empty: %d longest: %d\n", empty_slots, longest_chain);
+  
+  for (i = 0; i < count; ++i)
+    free(bufs[i]);
+  free((void*)bufs);
+}
+
+int main(void)
+{
+  static void* allocations[100];
+  char* str;
+  char* realloc_ptr;
+  int i;
+  
+  test_hash(100); 
+  test_hash(256); 
+  test_hash(800); 
+  for (i = 0; i < 100; ++i) {
+    allocations[i] = malloc(ALLOC_SIZE);
+    assert(valid_ptr(allocations[i], ALLOC_SIZE));
+    assert(fda_sizeof(allocations[i]) == ALLOC_SIZE);
+  }
+  
+  str = strdup("This is a string test");
+  realloc_ptr = malloc(100);
+  realloc_ptr = realloc(realloc_ptr, 1000);
+  printf("Allocations ok\n");
+  printf("str has %d bytes allocated\n", fda_sizeof(str));
+  test_hash(10); 
+  for (i = 0; i < 100; ++i)
+    fda_set_ref(allocations[i]);
+  fda_set_ref(str);
+  fda_set_ref(realloc_ptr);
+  test_hash(100); 
+  printf("Location listing\n");
+  i = fda_enum_locations(location_enumerator);
+  printf("Total locations: %d\n", i);
+  fda_assert_refs();
+  fda_clear_refs();
+  for (i = 0; i < 100; ++i)
+    free(allocations[i]);
+  realloc_ptr = realloc(realloc_ptr, 100);
+  fda_set_ref(str);
+  fda_set_ref(realloc_ptr);
+  assert(valid_ptr(realloc_ptr, 100));
+  fda_assert_refs();
+  free(str);
+  free(realloc_ptr);
+  fda_assert_refs();
+  str = strdup("Hello There");
+  realloc_ptr = str++;
+  str++;
+  printf("checking offset ptr\n");
+  assert(valid_ptr(str, 9));
+  free(realloc_ptr);
+  printf("Listing memory leaks\n");
+  i = fda_enum_leaks(leak_enumerator);
+  printf("Total Leaks: %d\n", i);
+  fda_assert_refs();
+  printf("fdatest completed with no errors\n");
+  return 0;
+}
+
index 44f509099a160ab2dc6dc0eae831bd5f60304338..410110d3bbe2c6a0273a5e89bbec7cd7827500a7 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include "fileio.h"
-#include "runmalloc.h"         /* RunMalloc, RunFree */
-#include <stdio.h>             /* BUFSIZ, EOF */
-#include <fcntl.h>             /* O_RDONLY, O_WRONLY, ... */
-#include <unistd.h>            /* read, write, open, close */
-#include <assert.h>            /* assert */
+#include "ircd_alloc.h"         /* MyMalloc, MyFree */
+
+#include <assert.h>             /* assert */
+#include <fcntl.h>              /* O_RDONLY, O_WRONLY, ... */
+#include <stdio.h>              /* BUFSIZ, EOF */
+#include <sys/stat.h>           /* struct stat */
+#include <unistd.h>             /* read, write, open, close */
 
 #define FB_EOF  0x01
 #define FB_FAIL 0x02
 
 struct FileBuf {
-  int fd;                      /* file descriptor */
-  char *endp;                  /* one past the end */
-  char *ptr;                   /* current read pos */
-  int flags;                   /* file state */
-  char buf[BUFSIZ];            /* buffer */
+  int fd;                       /* file descriptor */
+  char *endp;                   /* one past the end */
+  char *ptr;                    /* current read pos */
+  int flags;                    /* file state */
+  char buf[BUFSIZ];             /* buffer */
 };
 
-FBFILE *fbopen(const char *filename, const char *mode)
+FBFILEfbopen(const char *filename, const char *mode)
 {
   int openmode = 0;
   int pmode = 0;
@@ -45,27 +47,25 @@ FBFILE *fbopen(const char *filename, const char *mode)
   assert(filename);
   assert(mode);
 
-  while (*mode)
-  {
-    switch (*mode)
-    {
-      case 'r':
-       openmode = O_RDONLY;
-       break;
-      case 'w':
-       openmode = O_WRONLY | O_CREAT | O_TRUNC;
-       pmode = S_IREAD | S_IWRITE;
-       break;
-      case 'a':
-       openmode = O_WRONLY | O_CREAT | O_APPEND;
-       pmode = S_IREAD | S_IWRITE;
-       break;
-      case '+':
-       openmode &= ~(O_RDONLY | O_WRONLY);
-       openmode |= O_RDWR;
-       break;
-      default:
-       break;
+  while (*mode) {
+    switch (*mode) {
+    case 'r':
+      openmode = O_RDONLY;
+      break;
+    case 'w':
+      openmode = O_WRONLY | O_CREAT | O_TRUNC;
+      pmode = S_IREAD | S_IWRITE;
+      break;
+    case 'a':
+      openmode = O_WRONLY | O_CREAT | O_APPEND;
+      pmode = S_IREAD | S_IWRITE;
+      break;
+    case '+':
+      openmode &= ~(O_RDONLY | O_WRONLY);
+      openmode |= O_RDWR;
+      break;
+    default:
+      break;
     }
     ++mode;
   }
@@ -74,8 +74,7 @@ FBFILE *fbopen(const char *filename, const char *mode)
    * 3 seconds. -avalon (curtesy of wumpus)
    */
   alarm(3);
-  if ((fd = open(filename, openmode, pmode)) == -1)
-  {
+  if ((fd = open(filename, openmode, pmode)) == -1) {
     alarm(0);
     return fb;
   }
@@ -86,27 +85,26 @@ FBFILE *fbopen(const char *filename, const char *mode)
   return fb;
 }
 
-FBFILE *fdbopen(int fd, const char *mode)
+FBFILEfdbopen(int fd, const char *mode)
 {
   /*
    * ignore mode, if file descriptor hasn't been opened with the
    * correct mode, the first use will fail
    */
-  FBFILE *fb = (FBFILE *) RunMalloc(sizeof(FBFILE));
-  if (NULL != fb)
-  {
-    fb->ptr = fb->endp = fb->buf;
-    fb->fd = fd;
-    fb->flags = 0;
-  }
+  FBFILE *fb = (FBFILE *) MyMalloc(sizeof(FBFILE));
+  assert(0 != fb);
+  fb->ptr   = fb->endp = fb->buf;
+  fb->fd    = fd;
+  fb->flags = 0;
+
   return fb;
 }
 
-void fbclose(FBFILE * fb)
+void fbclose(FBFILE* fb)
 {
   assert(fb);
   close(fb->fd);
-  RunFree(fb);
+  MyFree(fb);
 }
 
 static int fbfill(FBFILE * fb)
@@ -146,8 +144,7 @@ char *fbgets(char *buf, size_t len, FBFILE * fb)
   if (fb->ptr == fb->endp && fbfill(fb) < 1)
     return 0;
   --len;
-  while (len--)
-  {
+  while (len--) {
     *p = *fb->ptr++;
     if ('\n' == *p)
     {
@@ -157,12 +154,10 @@ char *fbgets(char *buf, size_t len, FBFILE * fb)
     /*
      * deal with CR's
      */
-    else if ('\r' == *p)
-    {
-      if (fb->ptr < fb->endp || fbfill(fb) > 0)
-      {
-       if ('\n' == *fb->ptr)
-         ++fb->ptr;
+    else if ('\r' == *p) {
+      if (fb->ptr < fb->endp || fbfill(fb) > 0) {
+        if ('\n' == *fb->ptr)
+          ++fb->ptr;
       }
       *p++ = '\n';
       break;
@@ -181,8 +176,7 @@ int fbputs(const char *str, FBFILE * fb)
   assert(str);
   assert(fb);
 
-  if (0 == fb->flags)
-  {
+  if (0 == fb->flags) {
     n = write(fb->fd, str, strlen(str));
     if (-1 == n)
       fb->flags |= FB_FAIL;
@@ -196,3 +190,4 @@ int fbstat(struct stat *sb, FBFILE * fb)
   assert(fb);
   return fstat(fb->fd, sb);
 }
+
diff --git a/ircd/gline.c b/ircd/gline.c
new file mode 100644 (file)
index 0000000..12881b4
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * IRC - Internet Relay Chat, ircd/gline.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Finland
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "gline.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"    /* FALSE bleah */
+
+#include <assert.h>
+
+struct Gline* GlobalGlineList  = 0;
+struct Gline* BadChanGlineList = 0;
+
+
+struct Gline *make_gline(int is_ipmask, char *host, char *reason,
+                         char *name, time_t expire)
+{
+  struct Gline *agline;
+
+#ifdef BADCHAN
+  int gtype = 0;
+  if ('#' == *host || '&' == *host || '+' == *host)
+    gtype = 1; /* BAD CHANNEL GLINE */
+#endif
+
+  agline = (struct Gline*) MyMalloc(sizeof(struct Gline)); /* alloc memory */
+  assert(0 != agline);
+  DupString(agline->host, host);        /* copy vital information */
+  DupString(agline->reason, reason);
+  DupString(agline->name, name);
+  agline->expire = expire;
+  agline->gflags = GLINE_ACTIVE;        /* gline is active */
+  if (is_ipmask)
+    SetGlineIsIpMask(agline);
+#ifdef BADCHAN
+  if (gtype)
+  { 
+    agline->next = BadChanGlineList;    /* link it into the list */
+    return (BadChanGlineList = agline);
+  }
+#endif
+  agline->next = GlobalGlineList;       /* link it into the list */
+  return (GlobalGlineList = agline);
+}
+
+struct Gline *find_gline(struct Client *cptr, struct Gline **pgline)
+{
+  struct Gline* gline = GlobalGlineList;
+  struct Gline* prev = 0;
+
+  while (gline) {
+    /*
+     * look through all glines
+     */
+    if (gline->expire <= TStime()) {
+      /*
+       * handle expired glines
+       */
+      free_gline(gline, prev);
+      gline = prev ? prev->next : GlobalGlineList;
+      if (!gline)
+        break;                  /* gline == NULL means gline == NULL */
+      continue;
+    }
+
+    /* Does gline match? */
+    /* Added a check against the user's IP address as well -Kev */
+    if ((GlineIsIpMask(gline) ?
+        match(gline->host, ircd_ntoa((const char*) &cptr->ip)) :
+        match(gline->host, cptr->sockhost)) == 0 &&
+        match(gline->name, cptr->user->username) == 0) {
+      if (pgline)
+        *pgline = prev; /* If they need it, give them the previous gline
+                                   entry (probably for free_gline, below) */
+      return gline;
+    }
+
+    prev = gline;
+    gline = gline->next;
+  }
+
+  return 0;                  /* found no glines */
+}
+
+void free_gline(struct Gline* gline, struct Gline* prev)
+{
+  assert(0 != gline);
+  if (prev)
+    prev->next = gline->next;   /* squeeze agline out */
+  else { 
+#ifdef BADCHAN
+    assert(0 != gline->host);
+    if ('#' == *gline->host ||
+        '&' == *gline->host ||
+        '+' == *gline->host) {
+      BadChanGlineList = gline->next;
+    }
+    else
+#endif
+      GlobalGlineList = gline->next;
+  }
+
+  MyFree(gline->host);  /* and free up the memory */
+  MyFree(gline->reason);
+  MyFree(gline->name);
+  MyFree(gline);
+}
+
+void gline_remove_expired(time_t now)
+{
+  struct Gline* gline;
+  struct Gline* prev = 0;
+  
+  for (gline = GlobalGlineList; gline; gline = gline->next) {
+    if (gline->expire < now) {
+      free_gline(gline, prev);
+      gline = (prev) ? prev : GlobalGlineList;
+      if (!gline)
+        break;
+      continue;
+    }
+    prev = gline;
+  }
+}
+
+#ifdef BADCHAN
+int bad_channel(const char* name)
+{ 
+  struct Gline* agline = BadChanGlineList;
+
+  while (agline)
+  { 
+    if ((agline->gflags & GLINE_ACTIVE) && (agline->expire > TStime()) && 
+         !mmatch(agline->host, name)) { 
+      return 1;
+    }
+    agline = agline->next;
+  }
+  return 0;
+}
+
+void bad_channel_remove_expired(time_t now)
+{
+  struct Gline* gline;
+  struct Gline* prev = 0;
+  
+  for (gline = BadChanGlineList; gline; gline = gline->next) {
+    if (gline->expire < now) {
+      free_gline(gline, prev);
+      gline = (prev) ? prev : BadChanGlineList;
+      if (!gline)
+        break;
+      continue;
+    }
+    prev = gline;
+  }
+}
+
+#endif
+
+
+void add_gline(struct Client *sptr, int ip_mask, char *host, char *comment,
+               char *user, time_t expire, int local)
+{
+  struct Client *acptr;
+  struct Gline *agline;
+  int fd;
+  int gtype = 0;
+  assert(0 != host);
+
+#ifdef BADCHAN
+  if ('#' == *host || '&' == *host || '+' == *host)
+    gtype = 1;   /* BAD CHANNEL */
+#endif
+
+  /* Inform ops */
+  sendto_op_mask(SNO_GLINE,
+      "%s adding %s%s for %s@%s, expiring at " TIME_T_FMT ": %s", sptr->name,
+      local ? "local " : "",
+      gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
+
+#ifdef GPATH
+  write_log(GPATH,
+      "# " TIME_T_FMT " %s adding %s %s for %s@%s, expiring at " TIME_T_FMT
+      ": %s\n", TStime(), sptr->name, local ? "local" : "global",
+      gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
+
+  /* this can be inserted into the conf */
+  if (!gtype)
+    write_log(GPATH, "%c:%s:%s:%s\n", ip_mask ? 'k' : 'K', host, comment, 
+      user);
+#endif /* GPATH */
+
+  agline = make_gline(ip_mask, host, comment, user, expire);
+  if (local)
+    SetGlineIsLocal(agline);
+
+#ifdef BADCHAN
+  if (gtype)
+    return;
+#endif
+
+  for (fd = HighestFd; fd >= 0; --fd) { 
+    /*
+     * get the users!
+     */ 
+    if ((acptr = LocalClientArray[fd])) {
+      if (!acptr->user)
+        continue;
+#if 0
+      /*
+       * whee!! :)
+       */
+      if (!acptr->user || strlen(acptr->sockhost) > (size_t)HOSTLEN ||
+          (acptr->user->username ? strlen(acptr->user->username) : 0) >
+          (size_t)HOSTLEN)
+        continue;               /* these tests right out of
+                                   find_kill for safety's sake */
+#endif
+
+      if ((GlineIsIpMask(agline) ?  match(agline->host, acptr->sock_ip) :
+          match(agline->host, acptr->sockhost)) == 0 &&
+          (!acptr->user->username ||
+          match(agline->name, acptr->user->username) == 0))
+      {
+
+        /* ok, he was the one that got G-lined */
+        sendto_one(acptr, ":%s %d %s :*** %s.", me.name,
+            ERR_YOUREBANNEDCREEP, acptr->name, agline->reason);
+
+        /* let the ops know about my first kill */
+        sendto_op_mask(SNO_GLINE, "G-line active for %s",
+            get_client_name(acptr, FALSE));
+
+        /* and get rid of him */
+        if (sptr != acptr)
+          exit_client(sptr->from, acptr, &me, "G-lined");
+      }
+    }
+  }
+}
+
index 375ebea455dd6374b29c4cc27978041a42794850..1e25937d38ddde55457d901d622d8c4b78b4812b 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdlib.h>
-#include <limits.h>
-#include "h.h"
-#include "struct.h"
-#include "common.h"
 #include "hash.h"
+#include "client.h"
 #include "channel.h"
-#include "send.h"
-#include "s_serv.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
 #include "ircd.h"
+#include "send.h"
+#include "struct.h"
 #include "support.h"
+#include "sys.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
 
-RCSTAG_CC("$Id$");
 
 /************************* Nemesi's hash alghoritm ***********************/
 
@@ -166,27 +169,29 @@ static HASHMEMS hash_weight_table[CHAR_MAX - CHAR_MIN + 1];
    size tables could be supported but the rehash routine should also
    rebuild the transformation maps, I kept the tables of equal size 
    so that I can use one hash function and one transformation map */
-static aClient *clientTable[HASHSIZE];
-static aChannel *channelTable[HASHSIZE];
+static struct Client *clientTable[HASHSIZE];
+static struct Channel *channelTable[HASHSIZE];
 
 /* This is what the hash function will consider "equal" chars, this function 
    MUST be transitive, if HASHEQ(y,x)&&HASHEQ(y,z) then HASHEQ(y,z), and MUST
    be symmetric, if HASHEQ(a,b) then HASHEQ(b,a), obvious ok but... :) */
-#define HASHEQ(x,y) (((char) toLower((char) x)) == ((char) toLower((char) y)))
+#define HASHEQ(x,y) ((ToLower(x)) == (ToLower(y)))
 
 /* hash_init
  * Initialize the maps used by hash functions and clear the tables */
 void hash_init(void)
 {
-  int i, j;
-  unsigned long l, m;
+  int           i;
+  int           j;
+  unsigned long l;
+  unsigned long m;
 
   /* Clear the hash tables first */
   for (l = 0; l < HASHSIZE; l++)
   {
-    channelTable[l] = (aChannel *)NULL;
-    clientTable[l] = (aClient *)NULL;
-  };
+    channelTable[l] = 0;
+    clientTable[l]  = 0;
+  }
 
   /* Here is to what we "map" a char before working on it */
   for (i = CHAR_MIN; i <= CHAR_MAX; i++)
@@ -197,10 +202,12 @@ void hash_init(void)
      possible to change the HASHEQ macro and not touch here. 
      I don't actually care about the 32768 loops since it happens 
      only once at startup */
-  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
-    for (j = CHAR_MIN; j < i; j++)
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++) {
+    for (j = CHAR_MIN; j < i; j++) {
       if (HASHEQ(i, j))
-       hash_weight(i) = hash_weight(j);
+        hash_weight(i) = hash_weight(j);
+    }
+  }
 
   /* And this is our hash-loop "transformation" function, 
      basically it will be hash_map[x] == ((x*HASHSHIFT)%HASHSIZE)
@@ -211,7 +218,7 @@ void hash_init(void)
     l *= (unsigned long)HASHSHIFT;
     l %= (unsigned long)HASHSIZE;
     hash_map[m] = (HASHMEMS) l;
-  };
+  }
 }
 
 /* These are the actual hash functions, since they are static
@@ -224,9 +231,9 @@ void hash_init(void)
    strhash("") _will_ coredump, it's responsibility
    the caller to eventually check BadPtr(nick). */
 
-static HASHREGS strhash(register char *n)
+static HASHREGS strhash(const char *n)
 {
-  register HASHREGS hash = hash_weight(*n++);
+  HASHREGS hash = hash_weight(*n++);
   while (*n)
     hash = hash_map[hash] + hash_weight(*n++);
   return hash_map[hash];
@@ -243,8 +250,8 @@ static HASHREGS strhash(register char *n)
    on 16000 real channel names, 1000 loops. I left the code here
    as a bookmark if a strnhash is evetually needed in the future.
 
-   static HASHREGS strnhash(register char *n, register int i) {
-   register HASHREGS hash = hash_weight(*n++);
+   static HASHREGS strnhash(const char *n, int i) {
+   HASHREGS hash = hash_weight(*n++);
    i--;
    while(*n && i--)
    hash = hash_map[hash] + hash_weight(*n++);
@@ -271,9 +278,9 @@ static HASHREGS strhash(register char *n)
  * cptr must have a non-null name or expect a coredump, the name is
  * infact taken from cptr->name
  */
-int hAddClient(aClient *cptr)
+int hAddClient(struct Client *cptr)
 {
-  register HASHREGS hashv = strhash(cptr->name);
+  HASHREGS hashv = strhash(cptr->name);
 
   cptr->hnext = clientTable[hashv];
   clientTable[hashv] = cptr;
@@ -288,11 +295,11 @@ int hAddClient(aClient *cptr)
  * As before the name is taken from chptr->name, we do hash its entire
  * lenght since this proved to be statistically faster
  */
-int hAddChannel(aChannel *chptr)
+int hAddChannel(struct Channel *chptr)
 {
-  register HASHREGS hashv = strhash(chptr->chname);
+  HASHREGS hashv = strhash(chptr->chname);
 
-  chptr->hnextch = channelTable[hashv];
+  chptr->hnext = channelTable[hashv];
   channelTable[hashv] = chptr;
 
   return 0;
@@ -302,21 +309,21 @@ int hAddChannel(aChannel *chptr)
  * hRemClient
  * Removes a Client's name from the hash linked list
  */
-int hRemClient(aClient *cptr)
+int hRemClient(struct Client *cptr)
 {
-  register HASHREGS hashv = strhash(cptr->name);
-  register aClient *tmp = clientTable[hashv];
+  HASHREGS hashv = strhash(cptr->name);
+  struct Client *tmp = clientTable[hashv];
 
-  if (tmp == cptr)
-  {
+  if (tmp == cptr) {
     clientTable[hashv] = cptr->hnext;
+    cptr->hnext = cptr;
     return 0;
   }
-  while (tmp)
-  {
-    if (tmp->hnext == cptr)
-    {
+
+  while (tmp) {
+    if (tmp->hnext == cptr) {
       tmp->hnext = tmp->hnext->hnext;
+      cptr->hnext = cptr;
       return 0;
     }
     tmp = tmp->hnext;
@@ -340,10 +347,11 @@ int hRemClient(aClient *cptr)
  * There isn't an equivalent function for channels since they
  * don't change name.
  */
-int hChangeClient(aClient *cptr, char *newname)
+int hChangeClient(struct Client *cptr, const char *newname)
 {
-  register HASHREGS newhash = strhash(newname);
+  HASHREGS newhash = strhash(newname);
 
+  assert(0 != cptr);
   hRemClient(cptr);
 
   cptr->hnext = clientTable[newhash];
@@ -355,26 +363,25 @@ int hChangeClient(aClient *cptr, char *newname)
  * hRemChannel
  * Removes the channel's name from the corresponding hash linked list
  */
-int hRemChannel(aChannel *chptr)
+int hRemChannel(struct Channel *chptr)
 {
-  register HASHREGS hashv = strhash(chptr->chname);
-  register aChannel *tmp = channelTable[hashv];
+  HASHREGS hashv = strhash(chptr->chname);
+  struct Channel *tmp = channelTable[hashv];
 
-  if (tmp == chptr)
-  {
-    channelTable[hashv] = chptr->hnextch;
+  if (tmp == chptr) {
+    channelTable[hashv] = chptr->hnext;
+    chptr->hnext = chptr;
     return 0;
-  };
+  }
 
-  while (tmp)
-  {
-    if (tmp->hnextch == chptr)
-    {
-      tmp->hnextch = tmp->hnextch->hnextch;
+  while (tmp) {
+    if (tmp->hnext == chptr) {
+      tmp->hnext = tmp->hnext->hnext;
+      chptr->hnext = chptr;
       return 0;
-    };
-    tmp = tmp->hnextch;
-  };
+    }
+    tmp = tmp->hnext;
+  }
 
   return -1;
 }
@@ -386,25 +393,25 @@ int hRemChannel(aChannel *chptr)
  * returns NULL. If it finds one moves it to the top of the list
  * and returns it.
  */
-aClient *hSeekClient(char *name, int TMask)
+struct Client* hSeekClient(const char *name, int TMask)
 {
-  register HASHREGS hashv = strhash(name);
-  register aClient *cptr = clientTable[hashv];
-  register aClient *prv;
-
-  if (cptr)
-    if ((!IsStatMask(cptr, TMask)) || strCasediff(name, cptr->name))
-      while (prv = cptr, cptr = cptr->hnext)
-       if (IsStatMask(cptr, TMask) && (!strCasediff(name, cptr->name)))
-       {
-         prv->hnext = cptr->hnext;
-         cptr->hnext = clientTable[hashv];
-         clientTable[hashv] = cptr;
-         break;
-       };
-
+  HASHREGS hashv      = strhash(name);
+  struct Client *cptr = clientTable[hashv];
+
+  if (cptr) {
+    if (0 == (cptr->status & TMask) || 0 != ircd_strcmp(name, cptr->name)) {
+      struct Client* prev;
+      while (prev = cptr, cptr = cptr->hnext) {
+        if ((cptr->status & TMask) && (0 == ircd_strcmp(name, cptr->name))) {
+          prev->hnext = cptr->hnext;
+          cptr->hnext = clientTable[hashv];
+          clientTable[hashv] = cptr;
+          break;
+        }
+      }
+    }
+  }
   return cptr;
-
 }
 
 /*
@@ -413,23 +420,24 @@ aClient *hSeekClient(char *name, int TMask)
  * if can't find one returns NULL, if can find it moves
  * it to the top of the list and returns it.
  */
-aChannel *hSeekChannel(char *name)
+struct Channel* hSeekChannel(const char *name)
 {
-  register HASHREGS hashv = strhash(name);
-  register aChannel *chptr = channelTable[hashv];
-  register aChannel *prv;
-
-  if (chptr)
-    if (strCasediff(name, chptr->chname))
-      while (prv = chptr, chptr = chptr->hnextch)
-       if (!strCasediff(name, chptr->chname))
-       {
-         prv->hnextch = chptr->hnextch;
-         chptr->hnextch = channelTable[hashv];
-         channelTable[hashv] = chptr;
-         break;
-       };
-
+  HASHREGS hashv = strhash(name);
+  struct Channel *chptr = channelTable[hashv];
+
+  if (chptr) {
+    if (0 != ircd_strcmp(name, chptr->chname)) {
+      struct Channel* prev;
+      while (prev = chptr, chptr = chptr->hnext) {
+        if (0 == ircd_strcmp(name, chptr->chname)) {
+          prev->hnext = chptr->hnext;
+          chptr->hnext = channelTable[hashv];
+          channelTable[hashv] = chptr;
+          break;
+        }
+      }
+    }
+  }
   return chptr;
 
 }
@@ -439,13 +447,50 @@ aChannel *hSeekChannel(char *name)
    coders are able to SIGCORE the server and look into what goes
    on themselves :-) */
 
-int m_hash(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
+int m_hash(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
 {
-  sendto_one(sptr, "NOTICE %s :SUSER SSERV", parv[0]);
-  sendto_one(sptr, "NOTICE %s :SBSDC IRCDC", parv[0]);
-  sendto_one(sptr, "NOTICE %s :CHANC SMISC", parv[0]);
-  sendto_one(sptr, "NOTICE %s :HASHC VERSH", parv[0]);
-  sendto_one(sptr, "NOTICE %s :MAKEF HOSTID", parv[0]);
+  int max_chain = 0;
+  int buckets   = 0;
+  int count     = 0;
+  struct Client*  cl;
+  struct Channel* ch;
+  int i;
+  
+  sendto_one(sptr, "NOTICE %s :Hash Table Statistics", parv[0]);
+
+  for (i = 0; i < HASHSIZE; ++i) {
+    if ((cl = clientTable[i])) {
+      int len = 0;
+      ++buckets;
+      for ( ; cl; cl = cl->hnext)
+        ++len; 
+      if (len > max_chain)
+        max_chain = len;
+      count += len;
+    }
+  } 
+
+  sendto_one(sptr, "NOTICE %s :Client: entries: %d buckets: %d max chain: %d",
+             parv[0], count, buckets, max_chain);
+
+  buckets = 0;
+  count   = 0;
+  max_chain = 0;
+
+  for (i = 0; i < HASHSIZE; ++i) {
+    if ((ch = channelTable[i])) {
+      int len = 0;
+      ++buckets;
+      for ( ; ch; ch = ch->hnext)
+        ++len; 
+      if (len > max_chain)
+        max_chain = len;
+      count += len;
+    }
+  } 
+
+  sendto_one(sptr, "NOTICE %s :Channel: entries: %d buckets: %d max chain: %d",
+             parv[0], count, buckets, max_chain);
   return 0;
 }
 
@@ -454,62 +499,65 @@ int m_hash(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
    lowest 12 bits of the hash value are used, deletion is not supported,
    only addition, test for existence and cleanup of the table are.. */
 
-#define JUPEHASHBITS 12                /* 4096 entries, 64 nick jupes allowed */
+#define JUPEHASHBITS 12         /* 4096 entries, 64 nick jupes allowed */
 #define JUPEHASHSIZE (1<<JUPEHASHBITS)
 #define JUPEHASHMASK (JUPEHASHSIZE-1)
 #define JUPEMAX      (1<<(JUPEHASHBITS-6))
 
-static char jupeTable[JUPEHASHSIZE][NICKLEN + 1];      /* About 40k */
+static char jupeTable[JUPEHASHSIZE][NICKLEN + 1];       /* About 40k */
 static int jupesCount;
 
 /*
  * isNickJuped()
  * Tells if a nick is juped (nonzero returned) or not (zero) 
  */
-int isNickJuped(char *nick)
+int isNickJuped(const char *nick)
 {
-  register int pos;
+  int pos;
 
-  if (nick && *nick)
-    for (pos = strhash(nick); (pos &= JUPEHASHMASK), jupeTable[pos][0]; pos++)
-      if (!strCasediff(nick, jupeTable[pos]))
-       return 1;
-  return 0;                    /* A bogus pointer is NOT a juped nick, right ? :) */
+  if (nick && *nick) {
+    for (pos = strhash(nick); (pos &= JUPEHASHMASK), jupeTable[pos][0]; pos++) {
+      if (0 == ircd_strcmp(nick, jupeTable[pos]))
+        return 1;
+    }
+  }
+  return 0;                     /* A bogus pointer is NOT a juped nick, right ? :) */
 }
 
 /*
  * addNickJupes()
  * Adds a (comma separated list of) nick jupes to the table 
  */
-int addNickJupes(char *nicks)
+int addNickJupes(const char *nicks)
 {
-  static char temp[512];
-  char *one, *p;
-  register int pos;
+  static char temp[BUFSIZE + 1];
+  char* one;
+  char* p;
+  int   pos;
 
   if (nicks && *nicks)
   {
-    strncpy(temp, nicks, 512);
-    temp[512] = '\000';
+    ircd_strncpy(temp, nicks, BUFSIZE);
+    temp[BUFSIZE] = '\0';
     p = NULL;
-    for (one = strtoken(&p, temp, ","); one; one = strtoken(&p, NULL, ","))
+    for (one = ircd_strtok(&p, temp, ","); one; one = ircd_strtok(&p, NULL, ","))
     {
       if (!*one)
-       continue;
+        continue;
       pos = strhash(one);
-    loop:
+loop:
       pos &= JUPEHASHMASK;
       if (!jupeTable[pos][0])
       {
-       if (jupesCount == JUPEMAX)
-         return 1;             /* Error: Jupe table is full ! */
-       jupesCount++;
-       strncpy(jupeTable[pos], one, NICKLEN);
-       jupeTable[pos][NICKLEN] = '\000';       /* Better safe than sorry :) */
-       continue;
+        if (jupesCount == JUPEMAX)
+          return 1;             /* Error: Jupe table is full ! */
+        jupesCount++;
+        ircd_strncpy(jupeTable[pos], one, NICKLEN);
+        jupeTable[pos][NICKLEN] = '\000';       /* Better safe than sorry :) */
+        continue;
       }
-      if (!strCasediff(one, jupeTable[pos]))
-       continue;
+      if (0 == ircd_strcmp(one, jupeTable[pos]))
+        continue;
       ++pos;
       goto loop;
     }
@@ -523,7 +571,7 @@ int addNickJupes(char *nicks)
  */
 void clearNickJupes(void)
 {
-  register int i;
+  int i;
   jupesCount = 0;
   for (i = 0; i < JUPEHASHSIZE; i++)
     jupeTable[i][0] = '\000';
index 3f8ddadd0cfad7cb0515e4cbeb352c265d787a51..aaf74f2ca550e4d35aecb3675ef9907743f310dc 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#if HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-#include <sys/stat.h>
-#include <pwd.h>
-#include <signal.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HPUX
-#define _KERNEL
-#endif
-#include <sys/resource.h>
-#ifdef HPUX
-#undef _KERNEL
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdlib.h>
-#include <stdio.h>
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#ifdef CHROOTDIR
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#endif
-#ifdef VIRTUAL_HOST
-#include <sys/socket.h>                /* Needed for AF_INET on some OS */
-#endif
-#include "h.h"
-#include "res.h"
-#include "struct.h"
-#include "s_serv.h"
-#include "send.h"
 #include "ircd.h"
-#include "s_conf.h"
 #include "class.h"
-#include "s_misc.h"
-#include "parse.h"
+#include "client.h"
+#include "crule.h"
+#include "hash.h"
+#include "ircd_alloc.h" /* set_nomem_handler */
+#include "ircd_log.h"
+#include "ircd_signal.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
 #include "match.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "parse.h"
+#include "res.h"
+#include "s_auth.h"
 #include "s_bsd.h"
-#include "crule.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
 #include "userload.h"
-#include "numeric.h"
-#include "hash.h"
-#include "bsd.h"
 #include "version.h"
 #include "whowas.h"
-#include "numnicks.h"
+#include "msg.h"
 
-RCSTAG_CC("$Id$");
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <netdb.h>
 
 extern void init_counters(void);
 
-aClient me;                    /* That's me */
-aClient *client = &me;         /* Pointer to beginning of Client list */
-time_t TSoffset = 0;           /* Global variable; Offset of timestamps to
-                                  system clock */
+struct Client  me;                      /* That's me */
+struct Client* GlobalClientList = &me;  /* Pointer to beginning of Client list */
+time_t         TSoffset = 0;      /* Offset of timestamps to system clock */
+int            GlobalRehashFlag = 0;    /* do a rehash if set */
+int            GlobalRestartFlag = 0;   /* do a restart if set */
+time_t         CurrentTime;       /* Updated every time we leave select() */
 
 char **myargv;
-unsigned short int portnum = 0;        /* Server port number, listening this */
-char *configfile = CPATH;      /* Server configuration file */
-int debuglevel = -1;           /* Server debug level */
-unsigned int bootopt = 0;      /* Server boot option flags */
-char *debugmode = "";          /*  -"-    -"-   -"-  */
-int dorehash = 0;
-int restartFlag = 0;
+char *configfile = CPATH;       /* Server configuration file */
+int debuglevel = -1;            /* Server debug level */
+unsigned int bootopt = 0;       /* Server boot option flags */
+char *debugmode = "";           /*  -"-    -"-   -"-  */
 static char *dpath = DPATH;
 
-time_t nextconnect = 1;                /* time for next try_connections call */
-time_t nextping = 1;           /* same as above for check_pings() */
-time_t nextdnscheck = 0;       /* next time to poll dns to force timeouts */
-time_t nextexpire = 1;         /* next expire run on the dns cache */
-
-time_t now;                    /* Updated every time we leave select(),
-                                  and used everywhere else */
+time_t nextconnect = 1;         /* time for next try_connections call */
+time_t nextping = 1;            /* same as above for check_pings() */
+time_t nextdnscheck = 0;        /* next time to poll dns to force timeouts */
+time_t nextexpire = 1;          /* next expire run on the dns cache */
 
 #ifdef PROFIL
 extern etext(void);
-
-RETSIGTYPE s_monitor(HANDLER_ARG(int UNUSED(sig)))
-{
-  static int mon = 0;
-#ifdef POSIX_SIGNALS
-  struct sigaction act;
-#endif
-
-  moncontrol(mon);
-  mon = 1 - mon;
-#ifdef POSIX_SIGNALS
-  act.sa_handler = s_rehash;
-  act.sa_flags = 0;
-  sigemptyset(&act.sa_mask);
-  sigaddset(&act.sa_mask, SIGUSR1);
-  sigaction(SIGUSR1, &act, NULL);
-#else
-  signal(SIGUSR1, s_monitor);
-#endif
-}
-
-#endif
-
-RETSIGTYPE s_die(HANDLER_ARG(int UNUSED(sig)))
-{
-#ifdef USE_SYSLOG
-  syslog(LOG_CRIT, "Server Killed By SIGTERM");
-#endif
-  flush_connections(me.fd);
-  exit(-1);
-}
-
-static RETSIGTYPE s_rehash(HANDLER_ARG(int UNUSED(sig)))
-{
-#ifdef POSIX_SIGNALS
-  struct sigaction act;
-#endif
-  dorehash = 1;
-#ifdef POSIX_SIGNALS
-  act.sa_handler = s_rehash;
-  act.sa_flags = 0;
-  sigemptyset(&act.sa_mask);
-  sigaddset(&act.sa_mask, SIGHUP);
-  sigaction(SIGHUP, &act, NULL);
-#else
-  signal(SIGHUP, s_rehash);    /* sysV -argv */
-#endif
-}
-
-#ifdef USE_SYSLOG
-void restart(char *mesg)
-#else
-void restart(char *UNUSED(mesg))
 #endif
-{
-#ifdef USE_SYSLOG
-  syslog(LOG_WARNING, "Restarting Server because: %s", mesg);
-#endif
-  server_reboot();
-}
 
-RETSIGTYPE s_restart(HANDLER_ARG(int UNUSED(sig)))
+static void server_reboot(const char* message)
 {
-  restartFlag = 1;
-}
-
-void server_reboot(void)
-{
-  Reg1 int i;
+  int i;
 
-  sendto_ops("Aieeeee!!!  Restarting server...");
+  sendto_ops("Restarting server: %s", message);
   Debug((DEBUG_NOTICE, "Restarting server..."));
-  flush_connections(me.fd);
+  flush_connections(0);
   /*
    * fd 0 must be 'preserved' if either the -d or -i options have
    * been passed to us before restarting.
    */
-#ifdef USE_SYSLOG
-  closelog();
-#endif
+  close_log();
+
   for (i = 3; i < MAXCONNECTIONS; i++)
     close(i);
   if (!(bootopt & (BOOT_TTY | BOOT_DEBUG)))
     close(2);
   close(1);
-  if ((bootopt & BOOT_CONSOLE) || isatty(0))
-    close(0);
-  if (!(bootopt & BOOT_INETD))
-    execv(SPATH, myargv);
-#ifdef USE_SYSLOG
+  close(0);
+
+  execv(SPATH, myargv);
+
   /* Have to reopen since it has been closed above */
+  open_log(myargv[0]);
+  ircd_log(L_CRIT, "execv(%s,%s) failed: %m\n", SPATH, myargv[0]);
 
-  openlog(myargv[0], LOG_PID | LOG_NDELAY, LOG_FACILITY);
-  syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", SPATH, myargv[0]);
-  closelog();
-#endif
   Debug((DEBUG_FATAL, "Couldn't restart server \"%s\": %s",
-      SPATH, strerror(errno)));
+         SPATH, strerror(errno)));
   exit(-1);
 }
 
+void server_die(const char* message)
+{
+  ircd_log(L_CRIT, "Server terminating: %s", message);
+  sendto_ops("Server terminating: %s", message);
+  flush_connections(0);
+  exit(-1);
+}
+
+void server_restart(const char* message)
+{
+  static int restarting = 0;
+
+  ircd_log(L_WARNING, "Restarting Server: %s", message);
+  if (restarting == 0) {
+    restarting = 1;
+    server_reboot(message);
+  }
+}
+
+static void outofmemory(void)
+{
+  Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
+  server_restart("Out of Memory");
+} 
+
+static void write_pidfile(void)
+{
+#ifdef PPATH
+  int fd;
+  char buff[20];
+  if ((fd = open(PPATH, O_CREAT | O_WRONLY, 0600)) >= 0) {
+    memset(buff, 0, sizeof(buff));
+    sprintf(buff, "%5d\n", (int)getpid());
+    if (write(fd, buff, strlen(buff)) == -1)
+      Debug((DEBUG_NOTICE, "Error writing to pid file %s", PPATH));
+    close(fd);
+    return;
+  }
+  Debug((DEBUG_NOTICE, "Error opening pid file \"%s\": %s",
+        PPATH, strerror(errno)));
+#endif
+}
+
 /*
  * try_connections
  *
@@ -213,21 +170,21 @@ void server_reboot(void)
  */
 static time_t try_connections(void)
 {
-  Reg1 aConfItem *aconf;
-  Reg2 aClient *cptr;
-  aConfItem **pconf;
+  struct ConfItem *aconf;
+  struct Client *cptr;
+  struct ConfItem **pconf;
   int connecting, confrq;
   time_t next = 0;
-  aConfClass *cltmp;
-  aConfItem *cconf, *con_conf = NULL;
+  struct ConfClass *cltmp;
+  struct ConfItem *cconf, *con_conf = NULL;
   unsigned int con_class = 0;
 
   connecting = FALSE;
-  Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(now)));
-  for (aconf = conf; aconf; aconf = aconf->next)
+  Debug((DEBUG_NOTICE, "Connection check at   : %s", myctime(CurrentTime)));
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next)
   {
     /* Also when already connecting! (update holdtimes) --SRB */
-    if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port == 0)
+    if (!(aconf->status & CONF_SERVER) || aconf->port == 0)
       continue;
     cltmp = aconf->confClass;
     /*
@@ -238,15 +195,15 @@ static time_t try_connections(void)
      * a bit fuzzy... -- msa >;) ]
      */
 
-    if ((aconf->hold > now))
+    if ((aconf->hold > CurrentTime))
     {
       if ((next > aconf->hold) || (next == 0))
-       next = aconf->hold;
+        next = aconf->hold;
       continue;
     }
 
     confrq = get_con_freq(cltmp);
-    aconf->hold = now + confrq;
+    aconf->hold = CurrentTime + confrq;
     /*
      * Found a CONNECT config with port specified, scan clients
      * and see if this server is already connected?
@@ -254,20 +211,20 @@ static time_t try_connections(void)
     cptr = FindServer(aconf->name);
 
     if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
-       (!connecting || (ConClass(cltmp) > con_class)))
+        (!connecting || (ConClass(cltmp) > con_class)))
     {
       /* Check connect rules to see if we're allowed to try */
-      for (cconf = conf; cconf; cconf = cconf->next)
-       if ((cconf->status & CONF_CRULE) &&
-           (match(cconf->host, aconf->name) == 0))
-         if (crule_eval(cconf->passwd))
-           break;
+      for (cconf = GlobalConfList; cconf; cconf = cconf->next)
+        if ((cconf->status & CONF_CRULE) &&
+            (match(cconf->host, aconf->name) == 0))
+          if (crule_eval(cconf->passwd))
+            break;
       if (!cconf)
       {
-       con_class = ConClass(cltmp);
-       con_conf = aconf;
-       /* We connect only one at time... */
-       connecting = TRUE;
+        con_class = ConClass(cltmp);
+        con_conf = aconf;
+        /* We connect only one at time... */
+        connecting = TRUE;
       }
     }
     if ((next > aconf->hold) || (next == 0))
@@ -275,15 +232,15 @@ static time_t try_connections(void)
   }
   if (connecting)
   {
-    if (con_conf->next)                /* are we already last? */
+    if (con_conf->next)         /* are we already last? */
     {
       /* Put the current one at the end and make sure we try all connections */
-      for (pconf = &conf; (aconf = *pconf); pconf = &(aconf->next))
-       if (aconf == con_conf)
-         *pconf = aconf->next;
+      for (pconf = &GlobalConfList; (aconf = *pconf); pconf = &(aconf->next))
+        if (aconf == con_conf)
+          *pconf = aconf->next;
       (*pconf = con_conf)->next = 0;
     }
-    if (connect_server(con_conf, (aClient *)NULL, (struct hostent *)NULL) == 0)
+    if (connect_server(con_conf, 0, 0))
       sendto_ops("Connection to %s activated.", con_conf->name);
   }
   Debug((DEBUG_NOTICE, "Next connection check : %s", myctime(next)));
@@ -292,130 +249,96 @@ static time_t try_connections(void)
 
 static time_t check_pings(void)
 {
-  Reg1 aClient *cptr;
-  int ping = 0, i, rflag = 0;
-  time_t oldest = 0, timeout;
-
-  for (i = 0; i <= highest_fd; i++)
-  {
-    if (!(cptr = loc_clients[i]) || IsMe(cptr) || IsLog(cptr) || IsPing(cptr))
+  struct Client *cptr;
+  int ping = 0;
+  int i;
+  time_t oldest = CurrentTime + PINGFREQUENCY;
+  time_t timeout;
+
+  for (i = 0; i <= HighestFd; i++) {
+    if (!(cptr = LocalClientArray[i]))
       continue;
-
+    /*
+     * me is never in the local client array
+     */
+    assert(cptr != &me);
     /*
      * Note: No need to notify opers here.
      * It's already done when "FLAGS_DEADSOCKET" is set.
      */
-    if (IsDead(cptr))
-    {
+    if (IsDead(cptr)) {
       exit_client(cptr, cptr, &me, LastDeadComment(cptr));
       continue;
     }
 
-#if defined(R_LINES) && defined(R_LINES_OFTEN)
-    rflag = IsUser(cptr) ? find_restrict(cptr) : 0;
-#endif
     ping = IsRegistered(cptr) ? get_client_ping(cptr) : CONNECTTIMEOUT;
-    Debug((DEBUG_DEBUG, "c(%s)=%d p %d r %d a %d",
-       cptr->name, cptr->status, ping, rflag, (int)(now - cptr->lasttime)));
+    Debug((DEBUG_DEBUG, "c(%s)=%d p %d a %d",
+          cptr->name, cptr->status, ping, 
+          (int)(CurrentTime - cptr->lasttime)));
     /*
      * Ok, so goto's are ugly and can be avoided here but this code
      * is already indented enough so I think its justified. -avalon
      */
-    if (!rflag && IsRegistered(cptr) && (ping >= now - cptr->lasttime))
+    if (IsRegistered(cptr) && (ping >= CurrentTime - cptr->lasttime))
       goto ping_timeout;
     /*
-     * If the server hasnt talked to us in 2*ping seconds
+     * If the server hasnt talked to us in 2 * ping seconds
      * and it has a ping time, then close its connection.
      * If the client is a user and a KILL line was found
      * to be active, close this connection too.
      */
-    if (rflag ||
-       ((now - cptr->lasttime) >= (2 * ping) &&
-       (cptr->flags & FLAGS_PINGSENT)) ||
-       (!IsRegistered(cptr) && !IsHandshake(cptr) &&
-       (now - cptr->firsttime) >= ping))
+    if (((CurrentTime - cptr->lasttime) >= (2 * ping) && (cptr->flags & FLAGS_PINGSENT)) ||
+        (!IsRegistered(cptr) && !IsHandshake(cptr) && (CurrentTime - cptr->firsttime) >= ping))
     {
-      if (!IsRegistered(cptr) && (DoingDNS(cptr) || DoingAuth(cptr)))
-      {
-       Debug((DEBUG_NOTICE, "%s/%s timeout %s", DoingDNS(cptr) ? "DNS" : "",
-           DoingAuth(cptr) ? "AUTH" : "", get_client_name(cptr, FALSE)));
-       if (cptr->authfd >= 0)
-       {
-         close(cptr->authfd);
-         cptr->authfd = -1;
-         cptr->count = 0;
-         *cptr->buffer = '\0';
-       }
-       del_queries((char *)cptr);
-       ClearAuth(cptr);
-       ClearDNS(cptr);
-       SetAccess(cptr);
-       cptr->firsttime = now;
-       cptr->lasttime = now;
-       continue;
-      }
       if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
       {
-       sendto_ops("No response from %s, closing link", cptr->name);
-       exit_client(cptr, cptr, &me, "Ping timeout");
-       continue;
-      }
-      /*
-       * This is used for KILL lines with time restrictions
-       * on them - send a messgae to the user being killed first.
-       */
-#if defined(R_LINES) && defined(R_LINES_OFTEN)
-      else if (IsUser(cptr) && rflag)
-      {
-       sendto_ops("Restricting %s, closing link.",
-           get_client_name(cptr, FALSE));
-       exit_client(cptr, cptr, &me, "R-lined");
+        sendto_ops("No response from %s, closing link", cptr->name);
+        exit_client(cptr, cptr, &me, "Ping timeout");
+        continue;
       }
-#endif
-      else
-      {
-       if (!IsRegistered(cptr) && *cptr->name && *cptr->user->username)
-       {
-         sendto_one(cptr,
-             ":%s %d %s :Your client may not be compatible with this server.",
-             me.name, ERR_BADPING, cptr->name);
-         sendto_one(cptr,
-             ":%s %d %s :Compatible clients are available at "
-             "ftp://ftp.undernet.org/pub/irc/clients",
-             me.name, ERR_BADPING, cptr->name);
-       }
-       exit_client_msg(cptr, cptr, &me, "Ping timeout for %s",
-           IsServer(cptr) ? cptr->name : get_client_name(cptr, FALSE));
+      else {
+        if (!IsRegistered(cptr) && *cptr->name && *cptr->user->username) {
+          sendto_one(cptr,
+              ":%s %d %s :Your client may not be compatible with this server.",
+              me.name, ERR_BADPING, cptr->name);
+          sendto_one(cptr,
+              ":%s %d %s :Compatible clients are available at "
+              "ftp://ftp.undernet.org/pub/irc/clients",
+              me.name, ERR_BADPING, cptr->name);
+        }
+        exit_client_msg(cptr, cptr, &me, "Ping timeout for %s",
+                        get_client_name(cptr, HIDE_IP));
       }
       continue;
     }
-    else if (IsRegistered(cptr) && (cptr->flags & FLAGS_PINGSENT) == 0)
-    {
+    else if (IsRegistered(cptr) && 0 == (cptr->flags & FLAGS_PINGSENT)) {
       /*
        * If we havent PINGed the connection and we havent
        * heard from it in a while, PING it to make sure
        * it is still alive.
        */
       cptr->flags |= FLAGS_PINGSENT;
-      /* not nice but does the job */
-      cptr->lasttime = now - ping;
+      /*
+       * not nice but does the job
+       */
+      cptr->lasttime = CurrentTime - ping;
       if (IsUser(cptr))
-       sendto_one(cptr, "PING :%s", me.name);
+        sendto_one(cptr, "PING :%s", me.name);
       else
-       sendto_one(cptr, ":%s PING :%s", me.name, me.name);
+        sendto_one(cptr, "%s " TOK_PING " :%s", NumServ(&me), me.name);
     }
-  ping_timeout:
+ping_timeout:
     timeout = cptr->lasttime + ping;
-    while (timeout <= now)
+    while (timeout <= CurrentTime)
       timeout += ping;
-    if (timeout < oldest || !oldest)
+    if (timeout < oldest)
       oldest = timeout;
   }
-  if (!oldest || oldest < now)
-    oldest = now + PINGFREQUENCY;
+  if (oldest < CurrentTime)
+    oldest = CurrentTime + PINGFREQUENCY;
   Debug((DEBUG_NOTICE,
-      "Next check_ping() call at: %s, %d " TIME_T_FMT " " TIME_T_FMT,
-      myctime(oldest), ping, oldest, now));
+        "Next check_ping() call at: %s, %d " TIME_T_FMT " " TIME_T_FMT,
+        myctime(oldest), ping, oldest, CurrentTime));
 
   return (oldest);
 }
@@ -428,7 +351,7 @@ static time_t check_pings(void)
  */
 static int bad_command(void)
 {
-  printf("Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-t]\n",
+  printf("Usage: ircd %s[-h servername] [-x loglevel] [-t]\n",
 #ifdef CMDLINE_CONFIG
       "[-f config] "
 #else
@@ -439,121 +362,8 @@ static int bad_command(void)
   return (-1);
 }
 
-static void setup_signals(void)
-{
-#ifdef POSIX_SIGNALS
-  struct sigaction act;
-
-  act.sa_handler = SIG_IGN;
-  act.sa_flags = 0;
-  sigemptyset(&act.sa_mask);
-  sigaddset(&act.sa_mask, SIGPIPE);
-  sigaddset(&act.sa_mask, SIGALRM);
-#ifdef SIGWINCH
-  sigaddset(&act.sa_mask, SIGWINCH);
-  sigaction(SIGWINCH, &act, NULL);
-#endif
-  sigaction(SIGPIPE, &act, NULL);
-  act.sa_handler = dummy;
-  sigaction(SIGALRM, &act, NULL);
-  act.sa_handler = s_rehash;
-  sigemptyset(&act.sa_mask);
-  sigaddset(&act.sa_mask, SIGHUP);
-  sigaction(SIGHUP, &act, NULL);
-  act.sa_handler = s_restart;
-  sigaddset(&act.sa_mask, SIGINT);
-  sigaction(SIGINT, &act, NULL);
-  act.sa_handler = s_die;
-  sigaddset(&act.sa_mask, SIGTERM);
-  sigaction(SIGTERM, &act, NULL);
-
-#else
-#ifndef HAVE_RELIABLE_SIGNALS
-  signal(SIGPIPE, dummy);
-#ifdef SIGWINCH
-  signal(SIGWINCH, dummy);
-#endif
-#else
-#ifdef SIGWINCH
-  signal(SIGWINCH, SIG_IGN);
-#endif
-  signal(SIGPIPE, SIG_IGN);
-#endif
-  signal(SIGALRM, dummy);
-  signal(SIGHUP, s_rehash);
-  signal(SIGTERM, s_die);
-  signal(SIGINT, s_restart);
-#endif
-
-#ifdef HAVE_RESTARTABLE_SYSCALLS
-  /*
-   * At least on Apollo sr10.1 it seems continuing system calls
-   * after signal is the default. The following 'siginterrupt'
-   * should change that default to interrupting calls.
-   */
-  siginterrupt(SIGALRM, 1);
-#endif
-}
-
-/*
- * open_debugfile
- *
- * If the -t option is not given on the command line when the server is
- * started, all debugging output is sent to the file set by LPATH in config.h
- * Here we just open that file and make sure it is opened to fd 2 so that
- * any fprintf's to stderr also goto the logfile.  If the debuglevel is not
- * set from the command line by -x, use /dev/null as the dummy logfile as long
- * as DEBUGMODE has been defined, else dont waste the fd.
- */
-static void open_debugfile(void)
-{
-#ifdef DEBUGMODE
-  int fd;
-  aClient *cptr;
-
-  if (debuglevel >= 0)
-  {
-    cptr = make_client(NULL, STAT_LOG);
-    cptr->fd = 2;
-    cptr->port = debuglevel;
-    cptr->flags = 0;
-    cptr->acpt = cptr;
-    loc_clients[2] = cptr;
-    strcpy(cptr->sockhost, me.name);
-
-    printf("isatty = %d ttyname = %#x\n", isatty(2), (unsigned int)ttyname(2));
-    if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
-    {
-      if ((fd = creat(LOGFILE, 0600)) < 0)
-       if ((fd = open("/dev/null", O_WRONLY)) < 0)
-         exit(-1);
-      if (fd != 2)
-      {
-       dup2(fd, 2);
-       close(fd);
-      }
-      strncpy(cptr->name, LOGFILE, sizeof(cptr->name));
-      cptr->name[sizeof(cptr->name) - 1] = 0;
-    }
-    else if (isatty(2) && ttyname(2))
-    {
-      strncpy(cptr->name, ttyname(2), sizeof(cptr->name));
-      cptr->name[sizeof(cptr->name) - 1] = 0;
-    }
-    else
-      strcpy(cptr->name, "FD2-Pipe");
-    Debug((DEBUG_FATAL, "Debug: File <%s> Level: %u at %s",
-       cptr->name, cptr->port, myctime(now)));
-  }
-  else
-    loc_clients[2] = NULL;
-#endif
-  return;
-}
-
 int main(int argc, char *argv[])
 {
-  unsigned short int portarg = 0;
   uid_t uid;
   uid_t euid;
   time_t delay = 0;
@@ -561,9 +371,18 @@ int main(int argc, char *argv[])
   struct rlimit corelim;
 #endif
 
+  CurrentTime = time(NULL);
+
+  /*
+   * sanity check
+   */
+  if (MAXCONNECTIONS < 64 || MAXCONNECTIONS > 256000) {
+    fprintf(stderr, "%s: MAXCONNECTIONS insane: %d\n", *argv, MAXCONNECTIONS);
+    return 2;
+  }
+    
   uid = getuid();
   euid = geteuid();
-  now = time(NULL);
 #ifdef PROFIL
   monstartup(0, etext);
   moncontrol(1);
@@ -574,9 +393,8 @@ int main(int argc, char *argv[])
   if (chdir(DPATH))
   {
     fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", DPATH, strerror(errno));
-    exit(-1);
+    exit(2);
   }
-  res_init();
   if (chroot(DPATH))
   {
     fprintf(stderr, "Fail: Cannot chroot(%s): %s\n", DPATH, strerror(errno));
@@ -586,10 +404,14 @@ int main(int argc, char *argv[])
 #endif /*CHROOTDIR */
 
   myargv = argv;
-  umask(077);                  /* better safe than sorry --SRB */
+  umask(077);                   /* better safe than sorry --SRB */
   memset(&me, 0, sizeof(me));
+  me.fd = -1;
+
+#if 0
 #ifdef VIRTUAL_HOST
   memset(&vserv, 0, sizeof(vserv));
+#endif
 #endif
 
   setup_signals();
@@ -599,7 +421,7 @@ int main(int argc, char *argv[])
   if (getrlimit(RLIMIT_CORE, &corelim))
   {
     fprintf(stderr, "Read of rlimit core size failed: %s\n", strerror(errno));
-    corelim.rlim_max = RLIM_INFINITY;  /* Try to recover */
+    corelim.rlim_max = RLIM_INFINITY;   /* Try to recover */
   }
   corelim.rlim_cur = corelim.rlim_max;
   if (setrlimit(RLIMIT_CORE, &corelim))
@@ -621,144 +443,129 @@ int main(int argc, char *argv[])
     {
       if (argc > 1 && argv[1][0] != '-')
       {
-       p = *++argv;
-       argc -= 1;
+        p = *++argv;
+        argc -= 1;
       }
       else
-       p = "";
+        p = "";
     }
 
     switch (flag)
     {
-      case 'a':
-       bootopt |= BOOT_AUTODIE;
-       break;
-      case 'c':
-       bootopt |= BOOT_CONSOLE;
-       break;
       case 'q':
-       bootopt |= BOOT_QUICK;
-       break;
+        bootopt |= BOOT_QUICK;
+        break;
       case 'd':
-       if (euid != uid)
-         setuid((uid_t) uid);
-       dpath = p;
-       break;
+        if (euid != uid)
+          setuid((uid_t) uid);
+        dpath = p;
+        break;
 #ifdef CMDLINE_CONFIG
       case 'f':
-       if (euid != uid)
-         setuid((uid_t) uid);
-       configfile = p;
-       break;
+        if (euid != uid)
+          setuid((uid_t) uid);
+        configfile = p;
+        break;
 #endif
       case 'h':
-       strncpy(me.name, p, sizeof(me.name));
-       me.name[sizeof(me.name) - 1] = 0;
-       break;
-      case 'i':
-       bootopt |= BOOT_INETD | BOOT_AUTODIE;
-       break;
-      case 'p':
-       if ((portarg = atoi(p)) > 0)
-         portnum = portarg;
-       break;
+        ircd_strncpy(me.name, p, HOSTLEN);
+        break;
       case 't':
-       if (euid != uid)
-         setuid((uid_t) uid);
-       bootopt |= BOOT_TTY;
-       break;
+        if (euid != uid)
+          setuid((uid_t) uid);
+        bootopt |= BOOT_TTY;
+        break;
       case 'v':
-       printf("ircd %s\n", version);
-       exit(0);
+        printf("ircd %s\n", version);
+        exit(0);
+#if 0
 #ifdef VIRTUAL_HOST
       case 'w':
       {
-       struct hostent *hep;
-       if (!(hep = gethostbyname(p)))
-       {
-         fprintf(stderr, "%s: Error creating virtual host \"%s\": %d",
-             argv[0], p, h_errno);
-         return -1;
-       }
-       if (hep->h_addrtype == AF_INET && hep->h_addr_list[0] &&
-           !hep->h_addr_list[1])
-       {
-         memcpy(&vserv.sin_addr, hep->h_addr_list[0], sizeof(struct in_addr));
-         vserv.sin_family = AF_INET;
-       }
-       else
-       {
-         fprintf(stderr, "%s: Error creating virtual host \"%s\": "
-             "Use -w <IP-number of interface>\n", argv[0], p);
-         return -1;
-       }
-       break;
+        struct hostent *hep;
+        if (!(hep = gethostbyname(p)))
+        {
+          fprintf(stderr, "%s: Error creating virtual host \"%s\": %d",
+              argv[0], p, h_errno);
+          return 2;
+        }
+        if (hep->h_addrtype == AF_INET && hep->h_addr_list[0] &&
+            !hep->h_addr_list[1])
+        {
+          memcpy(&vserv.sin_addr, hep->h_addr_list[0], sizeof(struct in_addr));
+          vserv.sin_family = AF_INET;
+        }
+        else
+        {
+          fprintf(stderr, "%s: Error creating virtual host \"%s\": "
+              "Use -w <IP-number of interface>\n", argv[0], p);
+          return 2;
+        }
+        break;
       }
+#endif
 #endif
       case 'x':
-#ifdef DEBUGMODE
-       if (euid != uid)
-         setuid((uid_t) uid);
-       debuglevel = atoi(p);
-       debugmode = *p ? p : "0";
-       bootopt |= BOOT_DEBUG;
-       break;
+#ifdef  DEBUGMODE
+        if (euid != uid)
+          setuid((uid_t) uid);
+        debuglevel = atoi(p);
+        debugmode = *p ? p : "0";
+        bootopt |= BOOT_DEBUG;
+        break;
 #else
-       fprintf(stderr, "%s: DEBUGMODE must be defined for -x y\n", myargv[0]);
-       exit(0);
+        fprintf(stderr, "%s: DEBUGMODE must be defined for -x y\n", myargv[0]);
+        exit(0);
 #endif
       default:
-       bad_command();
-       break;
+        bad_command();
+        break;
     }
   }
 
   if (chdir(dpath))
   {
     fprintf(stderr, "Fail: Cannot chdir(%s): %s\n", dpath, strerror(errno));
-    exit(-1);
+    exit(2);
   }
 
 #ifndef IRC_UID
   if ((uid != euid) && !euid)
   {
     fprintf(stderr,
-       "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
-    exit(-1);
+        "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
+    exit(2);
   }
 #endif
 
 #if !defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))
-#ifndef _AIX
   if (euid != uid)
   {
-    setuid((uid_t) uid);
-    setuid((uid_t) euid);
+    setuid(uid);
+    setuid(euid);
   }
-#endif
 
-  if ((int)getuid() == 0)
+  if (0 == getuid())
   {
 #if defined(IRC_UID) && defined(IRC_GID)
 
     /* run as a specified user */
     fprintf(stderr, "WARNING: running ircd with uid = %d\n", IRC_UID);
-    fprintf(stderr, "        changing to gid %d.\n", IRC_GID);
+    fprintf(stderr, "         changing to gid %d.\n", IRC_GID);
     setuid(IRC_UID);
     setgid(IRC_GID);
 #else
     /* check for setuid root as usual */
     fprintf(stderr,
-       "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
-    exit(-1);
+        "ERROR: do not run ircd setuid root. Make it setuid a normal user.\n");
+    exit(2);
 #endif
   }
 #endif /*CHROOTDIR/UID/GID */
 
   if (argc > 0)
-    return bad_command();      /* This should exit out */
+    return bad_command();       /* This should exit out */
 
-#if HAVE_UNISTD_H
   /* Sanity checks */
   {
     char c;
@@ -766,20 +573,16 @@ int main(int argc, char *argv[])
 
     c = 'S';
     path = SPATH;
-    if (access(path, X_OK) == 0)
-    {
+    if (access(path, X_OK) == 0) {
       c = 'C';
       path = CPATH;
-      if (access(path, R_OK) == 0)
-      {
-       c = 'M';
-       path = MPATH;
-       if (access(path, R_OK) == 0)
-       {
-         c = 'R';
-         path = RPATH;
-         if (access(path, R_OK) == 0)
-         {
+      if (access(path, R_OK) == 0) {
+        c = 'M';
+        path = MPATH;
+        if (access(path, R_OK) == 0) {
+          c = 'R';
+          path = RPATH;
+          if (access(path, R_OK) == 0) {
 #ifndef DEBUG
             c = 0;
 #else
@@ -788,95 +591,66 @@ int main(int argc, char *argv[])
             if (access(path, W_OK) == 0)
               c = 0;
 #endif
-         }
-       }
+          }
+        }
       }
     }
     if (c)
     {
-      fprintf(stderr, "Check on %cPATH (%s) failed: %s\n",
-         c, path, strerror(errno));
+      fprintf(stderr, "Check on %cPATH (%s) failed: %s\n", 
+              c, path, strerror(errno));
       fprintf(stderr,
-         "Please create file and/or rerun `make config' and recompile to correct this.\n");
+          "Please create file and/or rerun `make config' and recompile to correct this.\n");
 #ifdef CHROOTDIR
       fprintf(stderr,
-         "Keep in mind that all paths are relative to CHROOTDIR.\n");
+          "Keep in mind that all paths are relative to CHROOTDIR.\n");
 #endif
-      exit(-1);
+      exit(2);
     }
   }
-#endif
 
+  init_list();
   hash_init();
-#ifdef DEBUGMODE
-  initlists();
-#endif
   initclass();
   initwhowas();
   initmsgtree();
   initstats();
   open_debugfile();
-  if (portnum == 0)
-    portnum = PORTNUM;
-  me.port = portnum;
   init_sys();
-  me.flags = FLAGS_LISTEN;
-  if ((bootopt & BOOT_INETD))
-  {
-    me.fd = 0;
-    loc_clients[0] = &me;
-    me.flags = FLAGS_LISTEN;
-  }
-  else
-    me.fd = -1;
+  set_nomem_handler(outofmemory);
 
-#ifdef USE_SYSLOG
-  openlog(myargv[0], LOG_PID | LOG_NDELAY, LOG_FACILITY);
-#endif
-  if (initconf(bootopt) == -1)
-  {
+  me.fd = -1;
+
+  open_log(myargv[0]);
+
+  if (initconf(bootopt) == -1) {
     Debug((DEBUG_FATAL, "Failed in reading configuration file %s", configfile));
     printf("Couldn't open configuration file %s\n", configfile);
-    exit(-1);
+    exit(2);
   }
-  get_my_name(&me);
-
-  if (!(bootopt & BOOT_INETD))
-  {
-    static char star[] = "*";
-    aConfItem *aconf;
-
-    if ((aconf = find_me()) && portarg == 0 && aconf->port != 0)
-      portnum = aconf->port;
-    Debug((DEBUG_ERROR, "Port = %u", portnum));
-    if (inetport(&me, star, portnum))
-      exit(1);
+  if (!init_server_identity()) {
+    Debug((DEBUG_FATAL, "Failed to initialize server identity"));
+    exit(2);
   }
-  else if (inetport(&me, "*", 0))
-    exit(1);
-
   read_tlines();
   rmotd = read_motd(RPATH);
   motd = read_motd(MPATH);
-  setup_ping();
-  now = time(NULL);
-  me.hopcount = 0;
-  me.authfd = -1;
-  me.confs = NULL;
-  me.next = NULL;
-  me.user = NULL;
+  CurrentTime = time(NULL);
   me.from = &me;
   SetMe(&me);
   make_server(&me);
-  /* Abuse own link timestamp as start timestamp: */
+  /*
+   * Abuse own link timestamp as start timestamp:
+   */
   me.serv->timestamp = TStime();
   me.serv->prot = atoi(MAJOR_PROTOCOL);
   me.serv->up = &me;
   me.serv->down = NULL;
+  me.handler = SERVER_HANDLER;
 
   SetYXXCapacity(&me, MAXCLIENTS);
 
-  me.lasttime = me.since = me.firsttime = now;
+  me.lasttime = me.since = me.firsttime = CurrentTime;
   hAddClient(&me);
 
   check_class();
@@ -885,9 +659,7 @@ int main(int argc, char *argv[])
   init_counters();
 
   Debug((DEBUG_NOTICE, "Server ready..."));
-#ifdef USE_SYSLOG
-  syslog(LOG_NOTICE, "Server Ready");
-#endif
+  ircd_log(L_NOTICE, "Server Ready");
 
   for (;;)
   {
@@ -897,27 +669,23 @@ int main(int argc, char *argv[])
      * active C lines, this call to Tryconnections is
      * made once only; it will return 0. - avalon
      */
-    if (nextconnect && now >= nextconnect)
+    if (nextconnect && CurrentTime >= nextconnect)
       nextconnect = try_connections();
     /*
      * DNS checks. One to timeout queries, one for cache expiries.
      */
-    if (now >= nextdnscheck)
-      nextdnscheck = timeout_query_list();
-    if (now >= nextexpire)
-      nextexpire = expire_cache();
+    nextdnscheck = timeout_resolver(CurrentTime);
     /*
      * Take the smaller of the two 'timed' event times as
      * the time of next event (stops us being late :) - avalon
      * WARNING - nextconnect can return 0!
      */
     if (nextconnect)
-      delay = MIN(nextping, nextconnect);
+      delay = IRCD_MIN(nextping, nextconnect);
     else
       delay = nextping;
-    delay = MIN(nextdnscheck, delay);
-    delay = MIN(nextexpire, delay);
-    delay -= now;
+    delay = IRCD_MIN(nextdnscheck, delay);
+    delay -= CurrentTime;
     /*
      * Adjust delay to something reasonable [ad hoc values]
      * (one might think something more clever here... --msa)
@@ -930,7 +698,7 @@ int main(int argc, char *argv[])
     if (delay < 1)
       delay = 1;
     else
-      delay = MIN(delay, TIMESEC);
+      delay = IRCD_MIN(delay, TIMESEC);
     read_message(delay);
 
     Debug((DEBUG_DEBUG, "Got message(s)"));
@@ -943,15 +711,19 @@ int main(int argc, char *argv[])
      * time might be too far away... (similarly with
      * ping times) --msa
      */
-    if (now >= nextping)
+    if (CurrentTime >= nextping)
       nextping = check_pings();
+    
+    /*
+     * timeout pending queries that haven't been responded to
+     */
+    timeout_auth_queries(CurrentTime);
 
-    if (dorehash)
-    {
+    if (GlobalRehashFlag) {
       rehash(&me, 1);
-      dorehash = 0;
+      GlobalRehashFlag = 0;
     }
-    if (restartFlag)
-      server_reboot();
+    if (GlobalRestartFlag)
+      server_restart("caught signal: SIGINT");
   }
 }
diff --git a/ircd/ircd_alloc.c b/ircd/ircd_alloc.c
new file mode 100644 (file)
index 0000000..903b9b1
--- /dev/null
@@ -0,0 +1,83 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/ircd_log.c
+ *   Copyright (C) 1999 Thomas Helvey (BleepSoft)
+ *                     
+ *   See file AUTHORS in IRC package for additional names of
+ *   the programmers. 
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+#include "ircd_alloc.h"
+#include "ircd_string.h"
+#include "s_debug.h"
+
+#include <assert.h>
+
+#if defined(NDEBUG)
+/*
+ * RELEASE: allocation functions
+ */
+
+static void nomem_handler(void)
+{
+  Debug((DEBUG_FATAL, "Out of memory, exiting"));
+  exit(2);
+}
+
+static OutOfMemoryHandler noMemHandler = nomem_handler;
+
+void set_nomem_handler(OutOfMemoryHandler handler)
+{
+  noMemHandler = handler;
+}
+
+void* MyMalloc(size_t size)
+{
+  void* p = malloc(size);
+  if (!p)
+    (*noMemHandler)();
+  return p;
+}
+
+void* MyRealloc(void* p, size_t size)
+{
+  void* x = realloc(p, size);
+  if (!x)
+    (*noMemHandler)();
+  return x;
+}
+
+void* MyCalloc(size_t nelem, size_t size)
+{
+  void* p = calloc(nelem, size);
+  if (!p)
+    (*noMemHandler)();
+  return p;
+}
+
+#else /* !defined(NDEBUG) */
+/*
+ * DEBUG: allocation functions
+ */
+void set_nomem_handler(OutOfMemoryHandler handler)
+{
+  assert(0 != handler);
+  fda_set_nomem_handler(handler);
+}
+
+#endif /* !defined(NDEBUG) */
+
diff --git a/ircd/ircd_log.c b/ircd/ircd_log.c
new file mode 100644 (file)
index 0000000..c0c2f9d
--- /dev/null
@@ -0,0 +1,131 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/ircd_log.c
+ *   Copyright (C) 1999 Thomas Helvey (BleepSoft)
+ *                     
+ *   See file AUTHORS in IRC package for additional names of
+ *   the programmers. 
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+#include "ircd_log.h"
+#include "client.h"
+#include "config.h"
+#include "ircd_string.h"
+#include "s_debug.h"
+#include "struct.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define LOG_BUFSIZE 2048 
+
+static int logLevel = L_INFO;
+
+#ifdef USE_SYSLOG
+static int sysLogLevel[] = {
+  LOG_CRIT,
+  LOG_ERR,
+  LOG_WARNING,
+  LOG_NOTICE,
+  LOG_INFO,
+  LOG_INFO,
+  LOG_INFO
+};
+#endif
+
+void ircd_log(int priority, const char* fmt, ...)
+{
+#if defined(USE_SYSLOG) || defined(DEBUGMODE)
+  char    buf[LOG_BUFSIZE];
+  va_list args;
+  assert(-1 < priority);
+  assert(priority < L_LAST_LEVEL);
+  assert(0 != fmt);
+
+  if (priority > logLevel)
+    return;
+
+  va_start(args, fmt);
+  vsprintf(buf, fmt, args);
+  va_end(args);
+#endif
+#ifdef USE_SYSLOG
+  syslog(sysLogLevel[priority], "%s", buf);
+#endif
+#ifdef DEBUGMODE
+  Debug((DEBUG_INFO, "LOG: %s", buf));
+#endif
+}
+
+void open_log(const char* process_name)
+{
+#ifdef USE_SYSLOG
+  if (EmptyString(process_name))
+    process_name = "ircd";
+  openlog(process_name, LOG_PID | LOG_NDELAY, LOG_USER);
+#endif
+}
+
+void close_log(void)
+{
+#ifdef USE_SYSLOG
+  closelog();
+#endif
+}
+
+void set_log_level(int level)
+{
+  if (L_ERROR < level && level < L_LAST_LEVEL)
+    logLevel = level;
+}
+
+int get_log_level(void)
+{
+  return(logLevel);
+}
+
+/*
+ * ircd_log_kill - log information about a kill
+ */
+void ircd_log_kill(const struct Client* victim, const struct Client* killer,
+                   const char* inpath, const char* path)
+{
+  if (MyUser(victim)) {
+    /*
+     * get more infos when your local clients are killed -- _dl
+     */
+    if (IsServer(killer))
+      ircd_log(L_TRACE,
+               "A local client %s!%s@%s KILLED from %s [%s] Path: %s!%s)",
+               victim->name, victim->user->username, victim->user->host,
+               killer->name, killer->name, inpath, path);
+    else
+      ircd_log(L_TRACE,
+               "A local client %s!%s@%s KILLED by %s [%s!%s@%s] (%s!%s)",
+               victim->name, victim->user->username, victim->user->host,
+               killer->name, killer->name, killer->user->username, killer->user->host,
+               inpath, path);
+  }
+  else
+    ircd_log(L_TRACE, "KILL From %s For %s Path %s!%s",
+             killer->name, victim->name, inpath, path);
+}
+
+
diff --git a/ircd/ircd_relay.c b/ircd/ircd_relay.c
new file mode 100644 (file)
index 0000000..d997b90
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_relay.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "ircd_relay.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file contains message relaying functions for client and server
+ * private messages and notices
+ * TODO: This file contains a lot of cut and paste code, and needs
+ * to be cleaned up a bit. The idea is to factor out the common checks
+ * but not introduce any IsOper/IsUser/MyUser/IsServer etc. stuff.
+ */
+void relay_channel_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Channel* chptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (chptr = FindChannel(name))) {
+    send_error_to_client(sptr, ERR_NOSUCHCHANNEL, name);
+    return;
+  }
+  /*
+   * This first: Almost never a server/service
+   */
+  if (!client_can_send_to_channel(sptr, chptr)) {
+    send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+    return;
+  }
+  if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+      check_target_limit(sptr, chptr, chptr->chname, 0))
+    return;
+
+  sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
+                           TOK_PRIVATE, chptr->chname, text);
+}
+
+void relay_channel_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Channel* chptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (chptr = FindChannel(name)))
+    return;
+  /*
+   * This first: Almost never a server/service
+   */
+  if (!client_can_send_to_channel(sptr, chptr))
+    return;
+
+  if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+      check_target_limit(sptr, chptr, chptr->chname, 0))
+    return;  
+
+  sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
+                           TOK_NOTICE, chptr->chname, text);
+}
+
+void server_relay_channel_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Channel* chptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (chptr = FindChannel(name))) {
+    /*
+     * XXX - do we need to send this back from a remote server?
+     */
+    send_error_to_client(sptr, ERR_NOSUCHCHANNEL, name);
+    return;
+  }
+  /*
+   * This first: Almost never a server/service
+   * Servers may have channel services, need to check for it here
+   */
+  if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr)) {
+    sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
+                             TOK_PRIVATE, chptr->chname, text);
+  }
+  else
+    send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, chptr->chname);
+}
+
+void server_relay_channel_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Channel* chptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (chptr = FindChannel(name)))
+    return;
+  /*
+   * This first: Almost never a server/service
+   * Servers may have channel services, need to check for it here
+   */
+  if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr)) {
+    sendmsgto_channel_butone(sptr->from, sptr, chptr, sptr->name,
+                             TOK_NOTICE, chptr->chname, text);
+  }
+}
+
+
+void relay_directed_message(struct Client* sptr, char* name, char* server, const char* text)
+{
+  struct Client* acptr;
+  char*          host;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  assert(0 != server);
+
+  if (0 == (acptr = FindServer(server + 1))) {
+    send_error_to_client(sptr, ERR_NOSUCHNICK, name);
+    return;
+  }
+  /*
+   * NICK[%host]@server addressed? See if <server> is me first
+   */
+  if (!IsMe(acptr)) {
+    sendto_one(acptr, ":%s %s %s :%s", sptr->name, MSG_PRIVATE, name, text);
+    return;
+  }
+  /*
+   * Look for an user whose NICK is equal to <name> and then
+   * check if it's hostname matches <host> and if it's a local
+   * user.
+   */
+  *server = '\0';
+  if ((host = strchr(name, '%')))
+    *host++ = '\0';
+
+  if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
+      (!EmptyString(host) && 0 != match(host, acptr->user->host))) {
+    send_error_to_client(sptr, ERR_NOSUCHNICK, name);
+    return;
+  }
+
+  *server = '@';
+  if (host)
+    *--host = '%';
+
+  if (!(is_silenced(sptr, acptr)))
+    sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                      sptr->name, MSG_PRIVATE, name, text);
+}
+
+void relay_directed_notice(struct Client* sptr, char* name, char* server, const char* text)
+{
+  struct Client* acptr;
+  char*          host;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  assert(0 != server);
+
+  if (0 == (acptr = FindServer(server + 1)))
+    return;
+  /*
+   * NICK[%host]@server addressed? See if <server> is me first
+   */
+  if (!IsMe(acptr)) {
+    sendto_one(acptr, ":%s %s %s :%s", sptr->name, MSG_NOTICE, name, text);
+    return;
+  }
+  /*
+   * Look for an user whose NICK is equal to <name> and then
+   * check if it's hostname matches <host> and if it's a local
+   * user.
+   */
+  *server = '\0';
+  if ((host = strchr(name, '%')))
+    *host++ = '\0';
+
+  if (!(acptr = FindUser(name)) || !MyUser(acptr) ||
+      (!EmptyString(host) && 0 != match(host, acptr->user->host)))
+    return;
+
+  *server = '@';
+  if (host)
+    *--host = '%';
+
+  if (!(is_silenced(sptr, acptr)))
+    sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                      sptr->name, MSG_NOTICE, name, text);
+}
+
+void relay_private_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (acptr = FindUser(name))) {
+    send_error_to_client(sptr, ERR_NOSUCHNICK, name);
+    return;
+  }
+  if (check_target_limit(sptr, acptr, acptr->name, 0) ||
+      is_silenced(sptr, acptr))
+    return;
+
+  /*
+   * send away message if user away
+   */
+  if (acptr->user && acptr->user->away)
+    sendto_one(sptr, rpl_str(RPL_AWAY),
+               me.name, sptr->name, acptr->name, acptr->user->away);
+  /*
+   * deliver the message
+   */
+  if (MyUser(acptr)) {
+    add_target(acptr, sptr);
+    sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                      sptr->name, MSG_PRIVATE, acptr->name, text);
+  }
+  else
+    sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr),
+               TOK_PRIVATE, NumNick(acptr), text);
+}
+
+void relay_private_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+
+  if (0 == (acptr = FindUser(name)))
+    return;
+  if (check_target_limit(sptr, acptr, acptr->name, 0) ||
+      is_silenced(sptr, acptr))
+    return;
+  /*
+   * deliver the message
+   */
+  if (MyUser(acptr)) {
+    add_target(acptr, sptr);
+    sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                      sptr->name, MSG_NOTICE, acptr->name, text);
+  }
+  else
+    sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr),
+               TOK_NOTICE, NumNick(acptr), text);
+}
+
+void server_relay_private_message(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  /*
+   * nickname addressed?
+   */
+  if (0 == (acptr = findNUser(name)) || !IsUser(acptr)) {
+    sendto_one(sptr,
+               ":%s %d %s * :Target left UnderNet. Failed to deliver: [%.20s]",
+               me.name, ERR_NOSUCHNICK, sptr->name, text);
+    return;
+  }
+  if (is_silenced(sptr, acptr))
+    return;
+
+  if (MyUser(acptr)) {
+    add_target(acptr, sptr);
+    sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                      sptr->name, MSG_PRIVATE, acptr->name, text);
+  }
+  else {
+    if (IsServer(sptr))
+      sendto_one(acptr, "%s %s %s%s :%s", NumServ(sptr),
+                 TOK_PRIVATE, NumNick(acptr), text);
+    else
+      sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr),
+                 TOK_PRIVATE, NumNick(acptr), text);
+  }        
+}
+
+
+void server_relay_private_notice(struct Client* sptr, const char* name, const char* text)
+{
+  struct Client* acptr;
+  assert(0 != sptr);
+  assert(0 != name);
+  assert(0 != text);
+  /*
+   * nickname addressed?
+   */
+  if (0 == (acptr = findNUser(name)) || !IsUser(acptr))
+    return;
+
+  if (is_silenced(sptr, acptr))
+    return;
+
+  if (MyUser(acptr)) {
+    add_target(acptr, sptr);
+    sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                      sptr->name, MSG_NOTICE, acptr->name, text);
+  }
+  else {
+    if (IsServer(sptr))
+      sendto_one(acptr, "%s %s %s%s :%s", NumServ(sptr), 
+                 TOK_NOTICE, NumNick(acptr), text);
+    else            
+      sendto_one(acptr, "%s%s %s %s%s :%s", NumNick(sptr), 
+                 TOK_NOTICE, NumNick(acptr), text);
+  }              
+}
+
+void relay_masked_message(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s;
+  int   host_mask = 0;
+
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+  /*
+   * look for the last '.' in mask and scan forward
+   */
+  if (0 == (s = strrchr(mask, '.'))) {
+    send_error_to_client(sptr, ERR_NOTOPLEVEL, mask);
+    return;
+  }
+  while (*++s) {
+    if (*s == '.' || *s == '*' || *s == '?')
+       break;
+  }
+  if (*s == '*' || *s == '?') {
+    send_error_to_client(sptr, ERR_WILDTOPLEVEL, mask);
+    return;
+  }
+  s = mask;
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+  sendto_match_butone(IsServer(sptr->from) ? sptr->from : 0,
+                      sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
+                      ":%s %s %s :%s", sptr->name, MSG_PRIVATE, mask, text);
+}
+
+void relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s;
+  int   host_mask = 0;
+
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+  /*
+   * look for the last '.' in mask and scan forward
+   */
+  if (0 == (s = strrchr(mask, '.'))) {
+    send_error_to_client(sptr, ERR_NOTOPLEVEL, mask);
+    return;
+  }
+  while (*++s) {
+    if (*s == '.' || *s == '*' || *s == '?')
+       break;
+  }
+  if (*s == '*' || *s == '?') {
+    send_error_to_client(sptr, ERR_WILDTOPLEVEL, mask);
+    return;
+  }
+  s = mask;
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+  sendto_match_butone(IsServer(sptr->from) ? sptr->from : 0,
+                      sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
+                      ":%s %s %s :%s", sptr->name, MSG_NOTICE, mask, text);
+}
+
+void server_relay_masked_message(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s = mask;
+  int         host_mask = 0;
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+  sendto_match_butone(sptr->from, sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
+                      ":%s %s %s :%s", sptr->name, MSG_PRIVATE, mask, text);
+}
+
+void server_relay_masked_notice(struct Client* sptr, const char* mask, const char* text)
+{
+  const char* s = mask;
+  int         host_mask = 0;
+  assert(0 != sptr);
+  assert(0 != mask);
+  assert(0 != text);
+
+  if ('@' == *++s) {
+    host_mask = 1;
+    ++s;
+  }
+  sendto_match_butone(sptr->from, sptr, s, host_mask ? MATCH_HOST : MATCH_SERVER,
+                      ":%s %s %s :%s", sptr->name, MSG_NOTICE, mask, text);
+}
+
diff --git a/ircd/ircd_reply.c b/ircd/ircd_reply.c
new file mode 100644 (file)
index 0000000..31b4650
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_proto.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "ircd_reply.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "send.h"
+
+#include <assert.h>
+
+int need_more_params(struct Client* cptr, const char* cmd)
+{
+  sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), 
+             me.name, (*cptr->name) ? cptr->name : "*", cmd);
+  return 0;
+}
+
+/*
+ * send_error_to_client - send an error message to a client
+ * I don't know if this function is any faster than the other version
+ * but it is a bit easier to use. It's reentrant until it hits vsendto_one
+ * at least :) --Bleep
+ */
+int send_error_to_client(struct Client* cptr, int error, ...)
+{
+  va_list               vl;
+  char                  buf[BUFSIZE];
+  char*                 dest = buf;
+  const char*           src  = me.name;
+  const struct Numeric* num  = get_error_numeric(error);
+
+  assert(0 != cptr);
+  assert(0 != num);
+  /*
+   * prefix
+   */
+  *dest++ = ':';
+  while ((*dest = *src++))
+    ++dest;
+  *dest++ = ' ';
+  /*
+   * numeric
+   */
+  src = num->str;
+  while ((*dest = *src++))
+    ++dest;
+  *dest++ = ' ';
+  /*
+   * client name (nick)
+   */
+  src = cptr->name;
+  while ((*dest = *src++))
+    ++dest;
+  *dest++ = ' ';
+  /*
+   * reply format
+   */
+  strcpy(dest, num->format);
+
+#if 0
+  Debug((DEBUG_INFO, "send_error_to_client: format: ->%s<-", buf));
+#endif
+
+  va_start(vl, error);
+  vsendto_one(cptr, buf, vl);
+  va_end(vl);
+  return 0;
+}
+
+int send_admin_info(struct Client* sptr, const struct ConfItem* admin)
+{
+  assert(0 != sptr);
+  if (admin) {
+    sendto_one(sptr, rpl_str(RPL_ADMINME),    me.name, sptr->name, me.name);
+    sendto_one(sptr, rpl_str(RPL_ADMINLOC1),  me.name, sptr->name, admin->host);
+    sendto_one(sptr, rpl_str(RPL_ADMINLOC2),  me.name, sptr->name, admin->passwd);
+    sendto_one(sptr, rpl_str(RPL_ADMINEMAIL), me.name, sptr->name, admin->name);
+  }
+  else
+    send_error_to_client(sptr, ERR_NOADMININFO, me.name);
+  return 0;
+}
+
+
diff --git a/ircd/ircd_signal.c b/ircd/ircd_signal.c
new file mode 100644 (file)
index 0000000..04e25cd
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_signal.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "ircd_signal.h"
+#include "ircd.h"
+
+#include <signal.h>
+
+static struct tag_SignalCounter {
+  unsigned int alrm;
+  unsigned int hup;
+} SignalCounter;
+
+#ifdef PROFIL
+void s_monitor(int sig)
+{
+  static int mon = 0;
+
+  moncontrol(mon);
+  mon = 1 - mon;
+}
+
+#endif
+
+void sigalrm_handler(int sig)
+{
+  ++SignalCounter.alrm;
+}
+
+void sigterm_handler(int sig)
+{
+  server_die("received signal SIGTERM");
+}
+
+static void sighup_handler(int sig)
+{
+  ++SignalCounter.hup;
+  GlobalRehashFlag = 1;
+}
+
+static void sigint_handler(int sig)
+{
+  GlobalRestartFlag = 1;
+}
+
+void setup_signals(void)
+{
+  struct sigaction act;
+
+  act.sa_handler = SIG_IGN;
+  act.sa_flags = 0;
+  sigemptyset(&act.sa_mask);
+  sigaddset(&act.sa_mask, SIGPIPE);
+  sigaddset(&act.sa_mask, SIGALRM);
+#ifdef  SIGWINCH
+  sigaddset(&act.sa_mask, SIGWINCH);
+  sigaction(SIGWINCH, &act, 0);
+#endif
+  sigaction(SIGPIPE, &act, 0);
+
+  act.sa_handler = sigalrm_handler;
+  sigaction(SIGALRM, &act, 0);
+
+  sigemptyset(&act.sa_mask);
+
+  act.sa_handler = sighup_handler;
+  sigaction(SIGHUP, &act, 0);
+
+  act.sa_handler = sigint_handler;
+  sigaction(SIGINT, &act, 0);
+
+  act.sa_handler = sigterm_handler;
+  sigaction(SIGTERM, &act, 0);
+
+#ifdef HAVE_RESTARTABLE_SYSCALLS
+  /*
+   * At least on Apollo sr10.1 it seems continuing system calls
+   * after signal is the default. The following 'siginterrupt'
+   * should change that default to interrupting calls.
+   */
+  siginterrupt(SIGALRM, 1);
+#endif
+}
+
diff --git a/ircd/ircd_string.c b/ircd/ircd_string.c
new file mode 100644 (file)
index 0000000..bb76933
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_string.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "ircd_string.h"
+#include "ircd_defs.h"
+#include "ircd_chattr.h"
+#include <assert.h>
+#include <string.h>
+/*
+ * include the character attribute tables here
+ */
+#include "chattr.tab.c"
+
+/*
+ * strtoken.c
+ *
+ * Walk through a string of tokens, using a set of separators.
+ * -argv 9/90
+ */
+char* ircd_strtok(char **save, char *str, char *fs)
+{
+  char *pos = *save;            /* keep last position across calls */
+  char *tmp;
+
+  if (str)
+    pos = str;                  /* new string scan */
+
+  while (pos && *pos && strchr(fs, *pos) != NULL)
+    pos++;                      /* skip leading separators */
+
+  if (!pos || !*pos)
+    return (pos = *save = NULL);        /* string contains only sep's */
+
+  tmp = pos;                    /* now, keep position of the token */
+
+  while (*pos && strchr(fs, *pos) == NULL)
+    pos++;                      /* skip content of the token */
+
+  if (*pos)
+    *pos++ = '\0';              /* remove first sep after the token */
+  else
+    pos = NULL;                 /* end of string */
+
+  *save = pos;
+  return (tmp);
+}
+
+/*
+ * canonize
+ *
+ * reduce a string of duplicate list entries to contain only the unique
+ * items.  Unavoidably O(n^2).
+ */
+char* canonize(char* buffer)
+{
+  static char cbuf[BUFSIZE];
+  char*       s;
+  char*       t;
+  char*       cp = cbuf;
+  int         l = 0;
+  char*       p = NULL;
+  char*       p2;
+
+  *cp = '\0';
+
+  for (s = ircd_strtok(&p, buffer, ","); s; s = ircd_strtok(&p, NULL, ","))
+  {
+    if (l)
+    {
+      p2 = NULL;
+      for (t = ircd_strtok(&p2, cbuf, ","); t; t = ircd_strtok(&p2, NULL, ","))
+        if (0 == ircd_strcmp(s, t))
+          break;
+        else if (p2)
+          p2[-1] = ',';
+    }
+    else
+      t = NULL;
+    if (!t)
+    {
+      if (l)
+        *(cp - 1) = ',';
+      else
+        l = 1;
+      strcpy(cp, s);
+      if (p)
+        cp += (p - s);
+    }
+    else if (p2)
+      p2[-1] = ',';
+  }
+  return cbuf;
+}
+
+/*
+ * ircd_strncpy - optimized strncpy
+ * This may not look like it would be the fastest possible way to do it,
+ * but it generally outperforms everything else on many platforms,
+ * including asm library versions and memcpy, if compiled with the
+ * optimizer on. (-O2 for gcc) --Bleep
+ */
+char* ircd_strncpy(char* s1, const char* s2, size_t n)
+{
+  char* endp = s1 + n;
+  char* s = s1;
+
+  assert(0 != s1);
+  assert(0 != s2);
+
+  while (s < endp && (*s++ = *s2++))
+    ;
+  return s1;
+}
+
+
+#ifndef FORCEINLINE
+NTL_HDR_strChattr { NTL_SRC_strChattr }
+NTL_HDR_strCasediff { NTL_SRC_strCasediff }
+#endif /* !FORCEINLINE */
+
+/*=============================================================================
+ * Other functions visible externally
+ */
+
+int strnChattr(const char *s, const size_t n)
+{
+  const char *rs = s;
+  unsigned int x = ~0;
+  int r = n;
+  while (*rs && r--)
+    x &= IRCD_CharAttrTab[*rs++ - CHAR_MIN];
+  return x;
+}
+
+/*
+ * ircd_strcmp - case insensitive comparison of 2 strings
+ * NOTE: see ircd_chattr.h for notes on case mapping.
+ */
+int ircd_strcmp(const char *a, const char *b)
+{
+  const char* ra = a;
+  const char* rb = b;
+  while (ToLower(*ra) == ToLower(*rb)) {
+    if (!*ra++)
+      return 0;
+    else
+      ++rb;
+  }
+  return (*ra - *rb);
+}
+
+/*
+ * ircd_strncmp - counted case insensitive comparison of 2 strings
+ * NOTE: see ircd_chattr.h for notes on case mapping.
+ */
+int ircd_strncmp(const char *a, const char *b, const size_t n)
+{
+  const char* ra = a;
+  const char* rb = b;
+  int left = n;
+  if (!left--)
+    return 0;
+  while (ToLower(*ra) == ToLower(*rb)) {
+    if (!*ra++ || !left--)
+      return 0;
+    else
+      ++rb;
+  }
+  return (*ra - *rb);
+}
+
+/*
+ * unique_name_vector - create a unique vector of names from
+ * a token separated list
+ * list   - [in]  a token delimited null terminated character array
+ * token  - [in]  the token to replace 
+ * vector - [out] vector of strings to be returned
+ * size   - [in]  maximum number of elements to place in vector
+ * Returns count of elements placed into the vector, if the list
+ * is an empty string { '\0' } 0 is returned.
+ * list, and vector must be non-null and size must be > 0 
+ * Empty strings <token><token> are not placed in the vector or counted.
+ * This function ignores all subsequent tokens when count == size
+ *
+ * NOTE: this function destroys it's input, do not use list after it
+ * is passed to this function
+ */
+int unique_name_vector(char* list, char token, char** vector, int size)
+{
+  int   i;
+  int   count = 0;
+  char* start = list;
+  char* end;
+
+  assert(0 != list);
+  assert(0 != vector);
+  assert(0 < size);
+  /*
+   * ignore spurious tokens
+   */
+  while (token == *start)
+    ++start;
+
+  for (end = strchr(start, token); end; end = strchr(start, token)) {
+    *end++ = '\0';
+    /*
+     * ignore spurious tokens
+     */
+    while (token == *end)
+      ++end;
+    for (i = 0; i < count; ++i) {
+      if (0 == ircd_strcmp(vector[i], start))
+        break;
+    }
+    if (i == count) {
+      vector[count++] = start;
+      if (count == size)
+        return count;
+    }
+    start = end;
+  }
+  if (*start)
+    vector[count++] = start;
+
+  return count;
+}
+
+/*
+ * token_vector - create a vector of tokens from
+ * a token separated list
+ * list   - [in]  a token delimited null terminated character array
+ * token  - [in]  the token to replace 
+ * vector - [out] vector of strings to be returned
+ * size   - [in]  maximum number of elements to place in vector
+ * returns count of elements placed into the vector, if the list
+ * is an empty string { '\0' } 0 is returned.
+ * list, and vector must be non-null and size must be > 1 
+ * Empty tokens are counted and placed in the list
+ *
+ * NOTE: this function destroys it's input, do not use list after it
+ * is passed to this function
+ */
+int token_vector(char* list, char token, char** vector, int size)
+{
+  int   count = 0;
+  char* start = list;
+  char* end;
+
+  assert(0 != list);
+  assert(0 != vector);
+  assert(1 < size);
+  vector[count++] = start;
+  for (end = strchr(start, token); end; end = strchr(start, token)) {
+    *end++ = '\0';
+    start = end;
+    if (*start) {
+      vector[count++] = start;
+      if (count < size)
+        continue;
+    }
+    break;
+  }
+  return count;
+} 
+
+/*
+ * host_from_uh - get the host.domain part of a user@host.domain string
+ * ripped from get_sockhost
+ */
+char* host_from_uh(char* host, const char* userhost, size_t n)
+{
+  const char* s;
+
+  assert(0 != host);
+  assert(0 != userhost);
+
+  if ((s = strchr(userhost, '@')))
+    ++s;
+  else
+    s = userhost;
+  ircd_strncpy(host, s, n);
+  host[n] = '\0';
+  return host;
+}
+
+/* 
+ * this new faster inet_ntoa was ripped from:
+ * From: Thomas Helvey <tomh@inxpress.net>
+ */
+static const char* IpQuadTab[] =
+{
+    "0",   "1",   "2",   "3",   "4",   "5",   "6",   "7",   "8",   "9",
+   "10",  "11",  "12",  "13",  "14",  "15",  "16",  "17",  "18",  "19",
+   "20",  "21",  "22",  "23",  "24",  "25",  "26",  "27",  "28",  "29",
+   "30",  "31",  "32",  "33",  "34",  "35",  "36",  "37",  "38",  "39",
+   "40",  "41",  "42",  "43",  "44",  "45",  "46",  "47",  "48",  "49",
+   "50",  "51",  "52",  "53",  "54",  "55",  "56",  "57",  "58",  "59",
+   "60",  "61",  "62",  "63",  "64",  "65",  "66",  "67",  "68",  "69",
+   "70",  "71",  "72",  "73",  "74",  "75",  "76",  "77",  "78",  "79",
+   "80",  "81",  "82",  "83",  "84",  "85",  "86",  "87",  "88",  "89",
+   "90",  "91",  "92",  "93",  "94",  "95",  "96",  "97",  "98",  "99",
+  "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
+  "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
+  "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
+  "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
+  "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
+  "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
+  "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
+  "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
+  "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
+  "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
+  "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
+  "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
+  "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
+  "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
+  "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
+  "250", "251", "252", "253", "254", "255"
+};
+
+/*
+ * ircd_ntoa - rewrote and renamed yet again :) --Bleep
+ * inetntoa - in_addr to string
+ *      changed name to remove collision possibility and
+ *      so behaviour is guaranteed to take a pointer arg.
+ *      -avalon 23/11/92
+ *  inet_ntoa --  returned the dotted notation of a given
+ *      internet number
+ *      argv 11/90).
+ *  inet_ntoa --  its broken on some Ultrix/Dynix too. -avalon
+ */
+const char* ircd_ntoa(const char* in)
+{
+  static char buf[20];
+  return ircd_ntoa_r(buf, in);
+}
+
+/*
+ * reentrant version of above
+ */
+const char* ircd_ntoa_r(char* buf, const char* in)
+{
+  char*                p = buf;
+  const unsigned char* a = (const unsigned char*)in;
+  const char*          n;
+
+  assert(0 != buf);
+  assert(0 != in);
+
+  n = IpQuadTab[*a++];
+  while ((*p = *n++))
+    ++p;
+  *p++ = '.';
+  n = IpQuadTab[*a++];
+  while ((*p = *n++))
+    ++p;
+  *p++ = '.';
+  n = IpQuadTab[*a++];
+  while ((*p = *n++))
+    ++p;
+  *p++ = '.';
+  n = IpQuadTab[*a];
+  while ((*p = *n++))
+    ++p;
+  return buf;
+}
+
+
diff --git a/ircd/ircd_xopen.c b/ircd/ircd_xopen.c
new file mode 100644 (file)
index 0000000..8eccda7
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * IRC - Internet Relay Chat, ircd/ircd_xopen.c
+ * Copyright (C) 1990, 1991 Armin Gruner
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#define _XOPEN_SOURCE
+#define _XOPEN_VERSION 4
+#include "ircd_xopen.h"
+
+#include <assert.h>
+#include <unistd.h>
+
+const char* ircd_crypt(const char* key, const char* salt)
+{
+  assert(0 != key);
+  assert(0 != salt);
+  return crypt(key, salt);
+}
+
index d39c39b99c10e211c0421f33765143a67f55278a..f798394052193c9aab0debce4faec78fecbb9895 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#include "list.h"
 
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_conf.h"
 #include "class.h"
-#include "match.h"
+#include "client.h"
 #include "ircd.h"
-#include "s_serv.h"
-#include "support.h"
-#include "s_misc.h"
-#include "s_bsd.h"
-#include "whowas.h"
+#include "ircd_alloc.h"
+#include "ircd_string.h"
+#include "listener.h"
+#include "match.h"
+#include "numeric.h"
 #include "res.h"
-#include "common.h"
-#include "list.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
 #include "s_user.h"
-#include "opercmds.h"
+#include "send.h"
+#include "struct.h"
+#include "support.h"
+#include "whowas.h"
 
-RCSTAG_CC("$Id$");
+#include <assert.h>
+#include <stddef.h>  /* offsetof */
+#include <unistd.h>  /* close */
+#include <string.h>
 
 #ifdef DEBUGMODE
 static struct liststats {
   int inuse;
-} cloc, crem, users, servs, links, classs, aconfs;
+} cloc, crem, users, servs, links, classs;
 #endif
 
-void outofmemory();
-
-#ifdef DEBUGMODE
-void initlists(void)
+void init_list(void)
 {
+#ifdef DEBUGMODE
   memset(&cloc, 0, sizeof(cloc));
   memset(&crem, 0, sizeof(crem));
   memset(&users, 0, sizeof(users));
   memset(&servs, 0, sizeof(servs));
   memset(&links, 0, sizeof(links));
   memset(&classs, 0, sizeof(classs));
-  memset(&aconfs, 0, sizeof(aconfs));
-}
 #endif
-
-void outofmemory(void)
-{
-  Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
-  restart("Out of Memory");
 }
 
 /*
- * Create a new aClient structure and set it to initial state.
+ * Create a new struct Client structure and set it to initial state.
  *
  *   from == NULL,   create local client (a client connected to a socket).
  *
@@ -76,10 +72,10 @@ void outofmemory(void)
  *                   the client defined by 'from').
  *                   ('from' is a local client!!).
  */
-aClient *make_client(aClient *from, int status)
+struct Client* make_client(struct Client *from, int status)
 {
-  Reg1 aClient *cptr = NULL;
-  Reg2 size_t size = CLIENT_REMOTE_SIZE;
+  struct Client *cptr = NULL;
+  size_t size = CLIENT_REMOTE_SIZE;
 
   /*
    * Check freelists first to see if we can grab a client without
@@ -88,11 +84,15 @@ aClient *make_client(aClient *from, int status)
   if (!from)
     size = CLIENT_LOCAL_SIZE;
 
-  if (!(cptr = (aClient *)RunMalloc(size)))
-    outofmemory();
-  memset(cptr, 0, size);       /* All variables are 0 by default */
+  cptr = (struct Client*) MyMalloc(size);
+  assert(0 != cptr);
+  /*
+   * NOTE: Do not remove this, a lot of code depends on the entire
+   * structure being zeroed out
+   */
+  memset(cptr, 0, size);        /* All variables are 0 by default */
 
-#ifdef DEBUGMODE
+#ifdef  DEBUGMODE
   if (size == CLIENT_LOCAL_SIZE)
     cloc.inuse++;
   else
@@ -100,145 +100,111 @@ aClient *make_client(aClient *from, int status)
 #endif
 
   /* Note: structure is zero (memset) */
-  cptr->from = from ? from : cptr;     /* 'from' of local client is self! */
-  cptr->fd = -1;
+  cptr->from = from ? from : cptr;      /* 'from' of local client is self! */
   cptr->status = status;
+  cptr->hnext = cptr;
   strcpy(cptr->username, "unknown");
-  if (size == CLIENT_LOCAL_SIZE)
-  {
-    cptr->since = cptr->lasttime = cptr->firsttime = now;
+
+  if (CLIENT_LOCAL_SIZE == size) {
+    cptr->fd = -1;
+    cptr->local = 1;
+    cptr->since = cptr->lasttime = cptr->firsttime = CurrentTime;
     cptr->lastnick = TStime();
-    cptr->nextnick = now - NICK_DELAY;
-    cptr->nexttarget = now - (TARGET_DELAY * (STARTTARGETS - 1));
-    cptr->authfd = -1;
+    cptr->nextnick = CurrentTime - NICK_DELAY;
+    cptr->nexttarget = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
+    cptr->handler = UNREGISTERED_HANDLER;
   }
-  return (cptr);
-}
-
-void free_client(aClient *cptr)
-{
-  RunFree(cptr);
+  return cptr;
 }
 
-/*
- * 'make_user' add's an User information block to a client
- * if it was not previously allocated.
- */
-anUser *make_user(aClient *cptr)
+void free_client(struct Client *cptr)
 {
-  Reg1 anUser *user;
+  if (cptr && cptr->local) {
+    /*
+     * make sure we have cleaned up local resources
+     */
+    if (cptr->dns_reply)
+      --cptr->dns_reply->ref_count;
+    if (-1 < cptr->fd)
+      close(cptr->fd);
+    DBufClear(&cptr->sendQ);
+    DBufClear(&cptr->recvQ);
+    if (cptr->listener)
+      release_listener(cptr->listener);
+  }    
+  /*
+   * forget to remove the client from the hash table?
+   */
+  assert(cptr->hnext == cptr);
 
-  user = cptr->user;
-  if (!user)
-  {
-    if (!(user = (anUser *)RunMalloc(sizeof(anUser))))
-      outofmemory();
-    memset(user, 0, sizeof(anUser));   /* All variables are 0 by default */
-#ifdef DEBUGMODE
-    users.inuse++;
-#endif
-    user->refcnt = 1;
-    *user->host = 0;
-    cptr->user = user;
-  }
-  return user;
+  MyFree(cptr);
 }
 
-aServer *make_server(aClient *cptr)
+struct Server *make_server(struct Client *cptr)
 {
-  Reg1 aServer *serv = cptr->serv;
+  struct Server *serv = cptr->serv;
 
   if (!serv)
   {
-    if (!(serv = (aServer *)RunMalloc(sizeof(aServer))))
-      outofmemory();
-    memset(serv, 0, sizeof(aServer));  /* All variables are 0 by default */
-#ifdef DEBUGMODE
+    serv = (struct Server*) MyMalloc(sizeof(struct Server));
+    assert(0 != serv);
+    memset(serv, 0, sizeof(struct Server)); /* All variables are 0 by default */
+#ifdef  DEBUGMODE
     servs.inuse++;
 #endif
     cptr->serv = serv;
     *serv->by = '\0';
-    DupString(serv->last_error_msg, "<>");     /* String must be non-empty */
+    DupString(serv->last_error_msg, "<>");      /* String must be non-empty */
   }
   return cptr->serv;
 }
 
-/*
- * free_user
- *
- * Decrease user reference count by one and realease block, if count reaches 0.
- */
-void free_user(anUser *user, aClient *cptr)
-{
-  if (--user->refcnt == 0)
-  {
-    if (user->away)
-      RunFree(user->away);
-    /*
-     * sanity check
-     */
-    if (user->joined || user->invited || user->channel)
-#ifdef DEBUGMODE
-      dumpcore("%p user (%s!%s@%s) %p %p %p %d %d",
-         cptr, cptr ? cptr->name : "<noname>",
-         user->username, user->host, user,
-         user->invited, user->channel, user->joined, user->refcnt);
-#else
-      sendto_ops("* %p user (%s!%s@%s) %p %p %p %d %d *",
-         cptr, cptr ? cptr->name : "<noname>",
-         user->username, user->host, user,
-         user->invited, user->channel, user->joined, user->refcnt);
-#endif
-    RunFree(user);
-#ifdef DEBUGMODE
-    users.inuse--;
-#endif
-  }
-}
-
 /*
  * Taken the code from ExitOneClient() for this and placed it here.
  * - avalon
  */
-void remove_client_from_list(aClient *cptr)
+void remove_client_from_list(struct Client *cptr)
 {
-  checklist();
   if (cptr->prev)
     cptr->prev->next = cptr->next;
-  else
-  {
-    client = cptr->next;
-    client->prev = NULL;
+  else {
+    GlobalClientList = cptr->next;
+    GlobalClientList->prev = 0;
   }
   if (cptr->next)
     cptr->next->prev = cptr->prev;
-  if (IsUser(cptr) && cptr->user)
-  {
+
+  cptr->next = cptr->prev = 0;
+
+  if (IsUser(cptr) && cptr->user) {
     add_history(cptr, 0);
     off_history(cptr);
   }
-  if (cptr->user)
-    free_user(cptr->user, cptr);
-  if (cptr->serv)
-  {
-    if (cptr->serv->user)
-      free_user(cptr->serv->user, cptr);
+  if (cptr->user) {
+    free_user(cptr->user);
+    cptr->user = 0;
+  }
+
+  if (cptr->serv) {
+    if (cptr->serv->user) {
+      free_user(cptr->serv->user);
+      cptr->serv->user = 0;
+    }
     if (cptr->serv->client_list)
-      RunFree(cptr->serv->client_list);
-    RunFree(cptr->serv->last_error_msg);
-    RunFree(cptr->serv);
-#ifdef DEBUGMODE
-    servs.inuse--;
+      MyFree(cptr->serv->client_list);
+    MyFree(cptr->serv->last_error_msg);
+    MyFree(cptr->serv);
+#ifdef  DEBUGMODE
+    --servs.inuse;
 #endif
   }
-#ifdef DEBUGMODE
-  if (cptr->fd == -2)
-    cloc.inuse--;
+#ifdef  DEBUGMODE
+  if (cptr->local)
+    --cloc.inuse;
   else
-    crem.inuse--;
+    --crem.inuse;
 #endif
   free_client(cptr);
-  return;
 }
 
 /*
@@ -247,249 +213,103 @@ void remove_client_from_list(aClient *cptr)
  * in this file, shouldnt they ?  after all, this is list.c, isn't it ?
  * -avalon
  */
-void add_client_to_list(aClient *cptr)
+void add_client_to_list(struct Client *cptr)
 {
   /*
    * Since we always insert new clients to the top of the list,
    * this should mean the "me" is the bottom most item in the list.
+   * XXX - don't always count on the above, things change
    */
-  cptr->next = client;
-  client = cptr;
+  cptr->prev = 0;
+  cptr->next = GlobalClientList;
+  GlobalClientList = cptr;
   if (cptr->next)
     cptr->next->prev = cptr;
-  return;
 }
 
 /*
  * Look for ptr in the linked listed pointed to by link.
  */
-Link *find_user_link(Link *lp, aClient *ptr)
+struct SLink *find_user_link(struct SLink *lp, struct Client *ptr)
 {
   if (ptr)
     while (lp)
     {
       if (lp->value.cptr == ptr)
-       return (lp);
+        return (lp);
       lp = lp->next;
     }
   return NULL;
 }
 
-Link *make_link(void)
+struct SLink *make_link(void)
 {
-  Reg1 Link *lp;
+  struct SLink *lp;
 
-  lp = (Link *)RunMalloc(sizeof(Link));
-#ifdef DEBUGMODE
+  lp = (struct SLink*) MyMalloc(sizeof(struct SLink));
+  assert(0 != lp);
+#ifdef  DEBUGMODE
   links.inuse++;
 #endif
   return lp;
 }
 
-void free_link(Link *lp)
+void free_link(struct SLink *lp)
 {
-  RunFree(lp);
-#ifdef DEBUGMODE
+  MyFree(lp);
+#ifdef  DEBUGMODE
   links.inuse--;
 #endif
 }
 
-Dlink *add_dlink(Dlink **lpp, aClient *cp)
+struct DLink *add_dlink(struct DLink **lpp, struct Client *cp)
 {
-  register Dlink *lp;
-  lp = (Dlink *)RunMalloc(sizeof(Dlink));
+  struct DLink* lp = (struct DLink*) MyMalloc(sizeof(struct DLink));
+  assert(0 != lp);
   lp->value.cptr = cp;
-  lp->prev = NULL;
+  lp->prev = 0;
   if ((lp->next = *lpp))
     lp->next->prev = lp;
   *lpp = lp;
   return lp;
 }
 
-void remove_dlink(Dlink **lpp, Dlink *lp)
+void remove_dlink(struct DLink **lpp, struct DLink *lp)
 {
-  if (lp->prev)
-  {
+  assert(0 != lpp);
+  assert(0 != lp);
+
+  if (lp->prev) {
     if ((lp->prev->next = lp->next))
       lp->next->prev = lp->prev;
   }
   else if ((*lpp = lp->next))
     lp->next->prev = NULL;
-  RunFree(lp);
+  MyFree(lp);
 }
 
-aConfClass *make_class(void)
+struct ConfClass *make_class(void)
 {
-  Reg1 aConfClass *tmp;
+  struct ConfClass *tmp;
 
-  tmp = (aConfClass *) RunMalloc(sizeof(aConfClass));
-#ifdef DEBUGMODE
+  tmp = (struct ConfClass*) MyMalloc(sizeof(struct ConfClass));
+  assert(0 != tmp);
+#ifdef  DEBUGMODE
   classs.inuse++;
 #endif
   return tmp;
 }
 
-void free_class(aConfClass * tmp)
+void free_class(struct ConfClass * tmp)
 {
-  RunFree(tmp);
-#ifdef DEBUGMODE
+  MyFree(tmp);
+#ifdef  DEBUGMODE
   classs.inuse--;
 #endif
 }
 
-aConfItem *make_conf(void)
-{
-  Reg1 aConfItem *aconf;
-
-  aconf = (struct ConfItem *)RunMalloc(sizeof(aConfItem));
-#ifdef DEBUGMODE
-  aconfs.inuse++;
-#endif
-  memset(&aconf->ipnum, 0, sizeof(struct in_addr));
-  aconf->next = NULL;
-  aconf->host = aconf->passwd = aconf->name = NULL;
-  aconf->status = CONF_ILLEGAL;
-  aconf->clients = 0;
-  aconf->port = 0;
-  aconf->hold = 0;
-  aconf->confClass = NULL;
-  return (aconf);
-}
-
-void delist_conf(aConfItem *aconf)
-{
-  if (aconf == conf)
-    conf = conf->next;
-  else
-  {
-    aConfItem *bconf;
-
-    for (bconf = conf; aconf != bconf->next; bconf = bconf->next);
-    bconf->next = aconf->next;
-  }
-  aconf->next = NULL;
-}
-
-void free_conf(aConfItem *aconf)
-{
-  del_queries((char *)aconf);
-  RunFree(aconf->host);
-  if (aconf->passwd)
-    memset(aconf->passwd, 0, strlen(aconf->passwd));
-  RunFree(aconf->passwd);
-  RunFree(aconf->name);
-  RunFree(aconf);
-#ifdef DEBUGMODE
-  aconfs.inuse--;
-#endif
-  return;
-}
-
-aGline *make_gline(int is_ipmask, char *host, char *reason,
-    char *name, time_t expire)
-{
-  Reg4 aGline *agline;
-#ifdef BADCHAN
-  int gtype=0;
-  if(*host == '#' || *host == '&' || *host == '+') 
-    gtype=1; /* BAD CHANNEL GLINE */
-#endif
-
-  agline = (struct Gline *)RunMalloc(sizeof(aGline));  /* alloc memory */
-  DupString(agline->host, host);       /* copy vital information */
-  DupString(agline->reason, reason);
-  DupString(agline->name, name);
-  agline->expire = expire;
-  agline->gflags = GLINE_ACTIVE;       /* gline is active */
-  if (is_ipmask)
-    SetGlineIsIpMask(agline);
-
-#ifdef BADCHAN
-  if(gtype)
-  { agline->next = badchan;            /* link it into the list */
-    return (badchan = agline);
-  }
-#endif
-  agline->next = gline;                /* link it into the list */
-  return (gline = agline);
-}
-
-aGline *find_gline(aClient *cptr, aGline **pgline)
-{
-  Reg3 aGline *agline = gline, *a2gline = NULL;
-
-  while (agline)
-  {                            /* look through all glines */
-    if (agline->expire <= TStime())
-    {                          /* handle expired glines */
-      free_gline(agline, a2gline);
-      agline = a2gline ? a2gline->next : gline;
-      if (!agline)
-       break;                  /* agline == NULL means gline == NULL */
-      continue;
-    }
-
-    /* Does gline match? */
-    /* Added a check against the user's IP address as well -Kev */
-    if ((GlineIsIpMask(agline) ?
-       match(agline->host, inetntoa(cptr->ip)) :
-       match(agline->host, cptr->sockhost)) == 0 &&
-       match(agline->name, cptr->user->username) == 0)
-    {
-      if (pgline)
-       *pgline = a2gline;      /* If they need it, give them the previous gline
-                                  entry (probably for free_gline, below) */
-      return agline;
-    }
-
-    a2gline = agline;
-    agline = agline->next;
-  }
-
-  return NULL;                 /* found no glines */
-}
-
-void free_gline(aGline *agline, aGline *pgline)
-{
-  if (pgline)
-    pgline->next = agline->next;       /* squeeze agline out */
-  else
-  { 
-#ifdef BADCHAN
-    if(*agline->host =='#' || *agline->host == '&' || *agline->host == '+')
-    {
-      badchan = agline->next;
-    }
-    else
-#endif
-      gline = agline->next;
-  }
-
-  RunFree(agline->host);       /* and free up the memory */
-  RunFree(agline->reason);
-  RunFree(agline->name);
-  RunFree(agline);
-}
-
-#ifdef BADCHAN
-int bad_channel(char *name)
-{ aGline *agline;
-
-  agline=badchan;
-  while(agline)
-  { 
-    if ((agline->gflags&GLINE_ACTIVE) && (agline->expire >TStime()) && 
-         !mmatch(agline->host,name))
-    { return 1;
-    }
-    agline=agline->next;
-  }
-  return 0;
-}
-#endif
-
-#ifdef DEBUGMODE
-void send_listinfo(aClient *cptr, char *name)
+#ifdef  DEBUGMODE
+void send_listinfo(struct Client *cptr, char *name)
 {
   int inuse = 0, mem = 0, tmp = 0;
 
@@ -504,29 +324,29 @@ void send_listinfo(aClient *cptr, char *name)
   inuse += crem.inuse;
   sendto_one(cptr, ":%s %d %s :Users: inuse: %d(%d)",
       me.name, RPL_STATSDEBUG, name, users.inuse,
-      tmp = users.inuse * sizeof(anUser));
+      tmp = users.inuse * sizeof(struct User));
   mem += tmp;
   inuse += users.inuse,
       sendto_one(cptr, ":%s %d %s :Servs: inuse: %d(%d)",
       me.name, RPL_STATSDEBUG, name, servs.inuse,
-      tmp = servs.inuse * sizeof(aServer));
+      tmp = servs.inuse * sizeof(struct Server));
   mem += tmp;
   inuse += servs.inuse,
       sendto_one(cptr, ":%s %d %s :Links: inuse: %d(%d)",
       me.name, RPL_STATSDEBUG, name, links.inuse,
-      tmp = links.inuse * sizeof(Link));
+      tmp = links.inuse * sizeof(struct SLink));
   mem += tmp;
   inuse += links.inuse,
       sendto_one(cptr, ":%s %d %s :Classes: inuse: %d(%d)",
       me.name, RPL_STATSDEBUG, name, classs.inuse,
-      tmp = classs.inuse * sizeof(aConfClass));
+      tmp = classs.inuse * sizeof(struct ConfClass));
   mem += tmp;
   inuse += classs.inuse,
       sendto_one(cptr, ":%s %d %s :Confs: inuse: %d(%d)",
-      me.name, RPL_STATSDEBUG, name, aconfs.inuse,
-      tmp = aconfs.inuse * sizeof(aConfItem));
+      me.name, RPL_STATSDEBUG, name, GlobalConfCount,
+      tmp = GlobalConfCount * sizeof(struct ConfItem));
   mem += tmp;
-  inuse += aconfs.inuse,
+  inuse += GlobalConfCount,
       sendto_one(cptr, ":%s %d %s :Totals: inuse %d %d",
       me.name, RPL_STATSDEBUG, name, inuse, mem);
 }
diff --git a/ircd/listener.c b/ircd/listener.c
new file mode 100644 (file)
index 0000000..b496265
--- /dev/null
@@ -0,0 +1,462 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/listener.c
+ *   Copyright (C) 1999 Thomas Helvey <tomh@inxpress.net>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  $Id$
+ */
+#include "listener.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_osdep.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "send.h"
+#include "sprintf_irc.h"
+#include "sys.h"         /* MAXCLIENTS */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
+
+struct Listener* ListenerPollList = 0;
+
+static struct Listener* make_listener(int port, struct in_addr addr)
+{
+  struct Listener* listener = 
+    (struct Listener*) MyMalloc(sizeof(struct Listener));
+  assert(0 != listener);
+
+  memset(listener, 0, sizeof(struct Listener));
+
+  listener->fd          = -1;
+  listener->port        = port;
+  listener->addr.s_addr = addr.s_addr;
+
+#ifdef NULL_POINTER_NOT_ZERO
+  listener->next = NULL;
+  listener->conf = NULL;
+#endif
+  return listener;
+}
+
+static void free_listener(struct Listener* listener)
+{
+  assert(0 != listener);
+  MyFree(listener);
+}
+
+#define PORTNAMELEN 10  /* ":31337" */
+
+/*
+ * get_listener_name - return displayable listener name and port
+ * returns "host.foo.org:6667" for a given listener
+ */
+const char* get_listener_name(const struct Listener* listener)
+{
+  static char buf[HOSTLEN + PORTNAMELEN + 4];
+  assert(0 != listener);
+  sprintf_irc(buf, "%s:%u", me.name, listener->port);
+  return buf;
+}
+
+/*
+ * count_listener_memory - count memory and listeners
+ */
+void count_listener_memory(int* count_out, size_t* size_out)
+{
+  struct Listener* l;
+  int              count = 0;
+  assert(0 != count_out);
+  assert(0 != size_out);
+  for (l = ListenerPollList; l; l = l->next)
+    ++count;
+  *count_out = count;
+  *size_out  = count * sizeof(struct Listener);
+}
+  
+/*
+ * show_ports - send port listing to a client
+ * inputs       - pointer to client to show ports to
+ * output       - none
+ * side effects - show ports
+ * author       - Dianora
+ */
+void show_ports(struct Client* sptr, int show_hidden, int port, int count)
+{
+  struct Listener* listener = 0;
+  char             flags[8];
+  assert(0 != sptr);
+
+  for (listener = ListenerPollList; listener; listener = listener->next) {
+    if (port && port != listener->port)
+      continue;
+    flags[0] = (listener->server) ? 'S' : 'C';
+    if (listener->hidden) {
+      if (!show_hidden)
+        continue;
+      flags[1] = 'H';
+      flags[2] = '\0';
+    }
+    else
+      flags[1] = '\0';
+        
+    sendto_one(sptr, rpl_str(RPL_STATSPLINE),
+               me.name, sptr->name, listener->port,
+               listener->ref_count, flags, 
+               (listener->active) ? "active" : "disabled");
+    if (--count == 0)
+      break;
+  }
+}
+
+/*
+ * inetport - create a listener socket in the AF_INET domain, 
+ * bind it to the port given in 'port' and listen to it  
+ * returns true (1) if successful false (0) on error.
+ *
+ * If the operating system has a define for SOMAXCONN, use it, otherwise
+ * use HYBRID_SOMAXCONN -Dianora
+ * NOTE: Do this in os_xxxx.c files
+ */
+#ifdef SOMAXCONN
+#define HYBRID_SOMAXCONN SOMAXCONN
+#else
+#define HYBRID_SOMAXCONN 64
+#endif
+
+static int inetport(struct Listener* listener)
+{
+  struct sockaddr_in sin;
+  int                fd;
+
+  /*
+   * At first, open a new socket
+   */
+  if (-1 == (fd = socket(AF_INET, SOCK_STREAM, 0))) {
+    report_error(SOCKET_ERROR_MSG, get_listener_name(listener), errno);
+    return 0;
+  }
+  else if (fd > MAXCLIENTS - 1) {
+    report_error(CONNLIMIT_ERROR_MSG, get_listener_name(listener), 0);
+    close(fd);
+    return 0;
+  }
+
+  if (!os_set_reuseaddr(fd)) {
+    report_error(REUSEADDR_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return 0;
+  }
+  /*
+   * Bind a port to listen for new connections if port is non-null,
+   * else assume it is already open and try get something from it.
+   */
+  memset(&sin, 0, sizeof(sin));
+  sin.sin_family = AF_INET;
+  sin.sin_addr   = listener->addr;
+  sin.sin_port   = htons(listener->port);
+
+  if (bind(fd, (struct sockaddr*) &sin, sizeof(sin))) {
+    report_error(BIND_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return 0;
+  }
+  /*
+   * Set the buffer sizes for the listener. Accepted connections
+   * inherit the accepting sockets settings for SO_RCVBUF S_SNDBUF
+   * The window size is set during the SYN ACK so setting it anywhere
+   * else has no effect whatsoever on the connection.
+   * NOTE: this must be set before listen is called
+   */
+  if (!os_set_sockbufs(fd, (listener->server) ? SERVER_TCP_WINDOW : CLIENT_TCP_WINDOW)) {
+    report_error(SETBUFS_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return 0;
+  }
+  if (!os_set_listen(fd, HYBRID_SOMAXCONN)) {
+    report_error(LISTEN_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return 0;
+  }
+  /*
+   * XXX - this should always work, performance will suck if it doesn't
+   */
+  if (!os_set_nonblocking(fd)) {
+    report_error(NONB_ERROR_MSG, get_listener_name(listener), errno);
+    close(fd);
+    return 0;
+  }
+  listener->fd = fd;
+
+  return 1;
+}
+
+/*
+ * find_listener - find a listener in the list
+ *
+ * XXX - this function does N comparisons so if the list is huge
+ * we may want to do something else for this. (rehash and init use this)
+ */
+static struct Listener* find_listener(int port, struct in_addr addr)
+{
+  struct Listener* listener;
+  for (listener = ListenerPollList; listener; listener = listener->next) {
+    if (port == listener->port && addr.s_addr == listener->addr.s_addr)
+      return listener;
+  }
+  return 0;
+}
+
+/*
+ * set_listener_mask - set the connection mask for this listener
+ */
+static void set_listener_mask(struct Listener* listener, const char* mask)
+{
+  int  ad[4];
+  char ipname[20];
+
+  assert(0 != listener);
+
+  if (EmptyString(mask) && strcmp(mask,"*")!=0) {
+    listener->mask.s_addr = 0;
+    return;
+  }
+  ad[0] = ad[1] = ad[2] = ad[3] = 0;
+  /*
+   * do it this way because building ip# from separate values for each
+   * byte requires endian knowledge or some nasty messing. Also means
+   * easy conversion of "*" 0.0.0.0 or 134.* to 134.0.0.0 :-)
+   */
+  sscanf(mask, "%d.%d.%d.%d", &ad[0], &ad[1], &ad[2], &ad[3]);
+  sprintf_irc(ipname, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
+  listener->mask.s_addr = inet_addr(ipname);
+}
+
+/*
+ * connection_allowed - spin through mask and addr passed to see if connect 
+ * allowed on a listener, uses mask generated by set_listener_mask
+ */
+static int connection_allowed(const char* addr, const char* mask)
+{
+  int i = 4;
+  for ( ; i > 0; --i) {
+    if (*mask && *addr != *mask)
+      break;
+    ++addr;
+    ++mask;
+  }
+  return (0 == i);
+}
+
+
+/*
+ * add_listener- create a new listener 
+ * port - the port number to listen on
+ * vhost_ip - if non-null must contain a valid IP address string in
+ * the format "255.255.255.255"
+ */
+void add_listener(int port, const char* vhost_ip, const char* mask,
+                  int is_server, int is_hidden) 
+{
+  struct Listener* listener;
+  struct in_addr   vaddr;
+
+  /*
+   * if no port in conf line, don't bother
+   */
+  if (0 == port)
+    return;
+
+  vaddr.s_addr = INADDR_ANY;
+
+  if (!EmptyString(vhost_ip) && strcmp(vhost_ip,"*") != 0) {
+    vaddr.s_addr = inet_addr(vhost_ip);
+    if (INADDR_NONE == vaddr.s_addr)
+      return;
+  }
+
+  if ((listener = find_listener(port, vaddr))) {
+    /*
+     * set active flag and change connect mask here, it's the only thing 
+     * that can change on a rehash
+     */
+    listener->active = 1;
+    set_listener_mask(listener, mask);
+    listener->hidden = is_hidden;
+    listener->server = is_server;
+    return;
+  }
+
+  listener = make_listener(port, vaddr);
+
+  if (inetport(listener)) {
+    listener->active = 1;
+    set_listener_mask(listener, mask);
+    listener->hidden = is_hidden;
+    listener->server = is_server;
+    listener->next   = ListenerPollList;
+    ListenerPollList = listener; 
+  }
+  else
+    free_listener(listener);
+}
+
+/*
+ * mark_listeners_closing - iterate through listeners and mark them as
+ * inactive
+ */
+void mark_listeners_closing(void)
+{
+  struct Listener* listener;
+  for (listener = ListenerPollList; listener; listener = listener->next)
+    listener->active = 0;
+}
+
+/*
+ * close_listener - close a single listener
+ */
+void close_listener(struct Listener* listener)
+{
+  assert(0 != listener);
+  /*
+   * remove from listener list
+   */
+  if (listener == ListenerPollList)
+    ListenerPollList = listener->next;
+  else {
+    struct Listener* prev = ListenerPollList;
+    for ( ; prev; prev = prev->next) {
+      if (listener == prev->next) {
+        prev->next = listener->next;
+        break; 
+      }
+    }
+  }
+  if (-1 < listener->fd)
+    close(listener->fd);
+  free_listener(listener);
+}
+/*
+ * close_listeners - close and free all listeners that are not being used
+ */
+void close_listeners()
+{
+  struct Listener* listener;
+  struct Listener* listener_next = 0;
+  /*
+   * close all 'extra' listening ports we have
+   */
+  for (listener = ListenerPollList; listener; listener = listener_next) {
+    listener_next = listener->next;
+    if (0 == listener->active && 0 == listener->ref_count)
+      close_listener(listener);
+  }
+}
+
+void release_listener(struct Listener* listener)
+{
+  assert(0 != listener);
+  assert(0 < listener->ref_count);
+  if (0 == --listener->ref_count && !listener->active)
+    close_listener(listener);
+}
+
+/*
+ * accept_connection - accept a connection on a listener
+ */
+void accept_connection(struct Listener* listener)
+{
+  struct sockaddr_in addr;
+  size_t             addrlen = sizeof(struct sockaddr_in);
+  int                fd;
+
+  assert(0 != listener);
+
+  listener->last_accept = CurrentTime;
+  /*
+   * There may be many reasons for error return, but
+   * in otherwise correctly working environment the
+   * probable cause is running out of file descriptors
+   * (EMFILE, ENFILE or others?). The man pages for
+   * accept don't seem to list these as possible,
+   * although it's obvious that it may happen here.
+   * Thus no specific errors are tested at this
+   * point, just assume that connections cannot
+   * be accepted until some old is closed first.
+   */
+  if (-1 == (fd = accept(listener->fd, (struct sockaddr*) &addr, &addrlen)))
+    return;
+  /*
+   * check for connection limit
+   */
+  if (fd > MAXCLIENTS - 1) {
+    ++ServerStats->is_ref;
+    send(fd, "ERROR :All connections in use\r\n", 32, 0);
+    close(fd);
+    return;
+  }
+  /*
+   * check to see if listener is shutting down
+   */
+  if (!listener->active) {
+    ++ServerStats->is_ref;
+    send(fd, "ERROR :Use another port\r\n", 25, 0);
+    close(fd);
+    return;
+  }
+  /*
+   * check to see if connection is allowed for this address mask
+   */
+  if (!connection_allowed((const char*) &addr, (const char*) &listener->mask)) {
+    ++ServerStats->is_ref;
+    send(fd, "ERROR :Use another port\r\n", 25, 0);
+    close(fd);
+    return;
+  }
+#if 0
+  /*
+   * check conf for ip address access
+   */
+  if (!conf_connect_allowed(addr.sin_addr)) {
+    ++ServerStats->is_ref;
+    send(fd, "ERROR :Not authorized\r\n", 23, 0);
+    close(fd);
+    return;
+  }
+#endif
+  ++ServerStats->is_ac;
+  nextping = CurrentTime;
+
+  add_connection(listener, fd);
+}
+
+
diff --git a/ircd/m_admin.c b/ircd/m_admin.c
new file mode 100644 (file)
index 0000000..2591259
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_admin.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_reply.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_user.h"
+
+#include <assert.h>
+
+/*
+ * m_admin - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc > 1) {
+    struct Client *acptr;
+    if (!(acptr = find_match_server(parv[1])))
+      return send_error_to_client(sptr, ERR_NOSUCHSERVER, parv[1]);
+
+    parv[1] = acptr->name;
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_ADMIN " :%s", 1, parc, parv) != HUNTED_ISME)
+      return 0;
+  }
+  return send_admin_info(sptr, find_admin());
+}
+
+/*
+ * ms_admin - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int ms_admin(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (parc < 2)
+    return 0;
+
+  if (hunt_server(0, cptr, sptr, "%s%s " TOK_ADMIN " :%s", 1, parc, parv) != HUNTED_ISME)
+    return 0;
+
+  return send_admin_info(sptr, find_admin());
+}
+
diff --git a/ircd/m_away.c b/ircd/m_away.c
new file mode 100644 (file)
index 0000000..2ccd5f9
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_away.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_away - generic message handler template
+ * - Added 14 Dec 1988 by jto.
+ *
+ * parv[0] = sender prefix
+ * parv[1] = away message
+ */
+int m_away(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* away_message = parv[1];
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (user_set_away(sptr->user, away_message)) {
+    sendto_serv_butone(cptr, "%s%s " TOK_AWAY " :%s", NumNick(sptr), away_message);
+    sendto_one(sptr, rpl_str(RPL_NOWAWAY), me.name, parv[0]);
+  }
+  else {
+    sendto_serv_butone(cptr, "%s%s " TOK_AWAY, NumNick(sptr));
+    sendto_one(sptr, rpl_str(RPL_UNAWAY), me.name, parv[0]);
+  }
+  return 0;
+}
+
+/*
+ * ms_away - server message handler template
+ * - Added 14 Dec 1988 by jto.
+ *
+ * parv[0] = sender prefix
+ * parv[1] = away message
+ */
+int ms_away(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* away_message = parv[1];
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  /*
+   * servers can't set away
+   */
+  if (IsServer(sptr))
+    return 0;
+
+  if (user_set_away(sptr->user, away_message))
+    sendto_serv_butone(cptr, "%s%s " TOK_AWAY " :%s", NumNick(sptr), away_message);
+  else
+    sendto_serv_butone(cptr, "%s%s " TOK_AWAY, NumNick(sptr));
+  return 0;
+}
+
+
diff --git a/ircd/m_burst.c b/ircd/m_burst.c
new file mode 100644 (file)
index 0000000..7e063e2
--- /dev/null
@@ -0,0 +1,1542 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_burst.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ms_burst - server message handler
+ *
+ * --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel name
+ * parv[2] = channel timestamp
+ * The meaning of the following parv[]'s depend on their first character:
+ * If parv[n] starts with a '+':
+ * Net burst, additive modes
+ *   parv[n] = <mode>
+ *   parv[n+1] = <param> (optional)
+ *   parv[n+2] = <param> (optional)
+ * If parv[n] starts with a '%', then n will be parc-1:
+ *   parv[n] = %<ban> <ban> <ban> ...
+ * If parv[n] starts with another character:
+ *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
+ *   where <mode> is the channel mode (ov) of nick and all following nicks.
+ *
+ * Example:
+ * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
+ *
+ * Anti net.ride code.
+ *
+ * When the channel already exist, and its TS is larger then
+ * the TS in the BURST message, then we cancel all existing modes.
+ * If its is smaller then the received BURST message is ignored.
+ * If it's equal, then the received modes are just added.
+ */
+int ms_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel* chptr;
+  time_t          timestamp;
+  int             netride = 0;
+  int             wipeout = 0;
+  int             n;
+  int             send_it = 0;
+  int             add_banid_not_called = 1;
+  struct Mode*    current_mode;
+  size_t          sblen;
+  size_t          mblen = 0;
+  int             mblen2;
+  int             pblen2;
+  int             cnt;
+  int             prev_mode;
+  char            prev_key[KEYLEN + 1];
+  struct Membership* member;
+  struct SLink*   lp;
+  char modebuf[MODEBUFLEN];
+  char parabuf[MODEBUFLEN];
+  char bmodebuf[MODEBUFLEN];
+  char bparambuf[MODEBUFLEN];
+
+  /* BURST is only for servers and has at least 4 parameters */
+  if (!IsServer(cptr) || parc < 4)
+    return 0;
+
+  if (!IsBurst(sptr))
+  {
+    int i;
+    char *p;
+    if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
+    {
+      p =
+          sprintf_irc(sendbuf,
+          ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
+          sptr->name, parv[1], parv[2]);
+      for (i = 3; i < parc - 1; ++i)
+        p = sprintf_irc(p, " %s", parv[i]);
+      sprintf_irc(p, " :%s", parv[parc - 1]);
+      sendbufto_op_mask(SNO_HACK4);
+    }
+    else
+    {
+#if 1                           /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
+      SetBurst(sptr);
+      if (MyConnect(sptr))
+#endif
+        return exit_client_msg(cptr, cptr, &me,
+            "HACK: BURST message outside net.burst from %s", sptr->name);
+    }
+  }
+
+  /* Find the channel, or create it - note that the creation time
+   * will be 0 if it has to be created */
+  chptr = get_channel(sptr, parv[1], CGT_CREATE);
+  current_mode = &chptr->mode;
+  prev_mode = chptr->mode.mode;
+  if (*chptr->mode.key)
+  {
+    prev_mode |= MODE_KEY;
+    strcpy(prev_key, chptr->mode.key);
+  }
+  if (chptr->mode.limit)
+    prev_mode |= MODE_LIMIT;
+
+  timestamp = atoi(parv[2]);
+
+  /* Copy the new TS when the received creationtime appears to be older */
+  if (!chptr->creationtime || chptr->creationtime > timestamp)
+  {
+    /* Set the new timestamp */
+    chptr->creationtime = timestamp;
+    send_it = 1;                /* Make sure we pass on the different timestamp ! */
+    /* Mark all bans as needed to be wiped out */
+    for (lp = chptr->banlist; lp; lp = lp->next)
+      lp->flags |= CHFL_BURST_BAN_WIPEOUT;
+    /*
+     * Only the first BURST for this channel can have creationtime > timestamp,
+     * so at this moment ALL members are on OUR side, and thus all net.riders:
+     */
+    wipeout = 1;
+  }
+  for (member = chptr->members; member; member = member->next_member)
+    member->status &= ~CHFL_BURST_JOINED;    /* Set later for nicks in the BURST msg */
+  /* If `wipeout' is set then these will be deopped later. */
+
+  /* If the entering creationtime is younger, ignore the modes */
+  if (chptr->creationtime < timestamp)
+    netride = 1;                /* Only pass on the nicks (so they JOIN) */
+
+  /* Prepare buffers to pass the message */
+  *bparambuf = *bmodebuf = *parabuf = '\0';
+  pblen2 = 0;
+  *modebuf = '+';
+  mblen2 = 1;
+  cnt = 0;
+  sblen = sprintf_irc(sendbuf, "%s B %s " TIME_T_FMT,
+      NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
+
+  /* Run over all remaining parameters */
+  for (n = 3; n < parc; n++)
+    switch (*parv[n])           /* What type is it ? mode, nicks or bans ? */
+    {
+      case '+':         /* modes */
+      {
+        char *p = parv[n];
+        while (*(++p))          /* Run over all mode characters */
+        {
+          switch (*p)           /* which mode ? */
+          {
+              /*
+               * The following cases all do the following:
+               * - In case wipeout needed, reset 'prev_mode' to indicate this
+               *   mode should not be cancelled.
+               * - If wipeout or (not netride and the new mode is a change),
+               *   add it to bmodebuf and bparabuf for propagation.
+               * - Else ignore it.
+               * - Add it to modebuf and parabuf for propagation to the
+               *   clients when not netride and the new mode is a change.
+               * Special cases:
+               * - If a +s is received, cancel a +p and sent a -p to the
+               *   clients too (if +p was set).
+               * - If a +p is received and +s is set, ignore the +p.
+               */
+            case 'i':
+            {
+              int tmp;
+              prev_mode &= ~MODE_INVITEONLY;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_INVITEONLY)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'i';
+                current_mode->mode |= MODE_INVITEONLY;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'i';
+              break;
+            }
+            case 'k':
+            {
+              int tmp;
+              char *param = parv[++n];
+              prev_mode &= ~MODE_KEY;
+              if (!(tmp = netride || (*current_mode->key &&
+                  (!strcmp(current_mode->key, param) ||
+                  (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
+                  wipeout)
+              {
+                bmodebuf[mblen++] = 'k';
+                strcat(bparambuf, " ");
+                strcat(bparambuf, param);
+                ircd_strncpy(current_mode->key, param, KEYLEN);
+              }
+              if (!tmp && !wipeout)
+              {
+                modebuf[mblen2++] = 'k';
+                parabuf[pblen2++] = ' ';
+                strcpy(parabuf + pblen2, param);
+                pblen2 += strlen(param);
+                cnt++;
+              }
+              break;
+            }
+            case 'l':
+            {
+              int tmp;
+              unsigned int param = atoi(parv[++n]);
+              prev_mode &= ~MODE_LIMIT;
+              if (!(tmp = netride || (current_mode->limit &&
+                  (current_mode->limit == param ||
+                  (!wipeout && current_mode->limit < param)))) || wipeout)
+              {
+                bmodebuf[mblen++] = 'l';
+                sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
+                current_mode->limit = param;
+              }
+              if (!tmp)
+              {
+                modebuf[mblen2++] = 'l';
+                pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
+                cnt++;
+              }
+              break;
+            }
+            case 'm':
+            {
+              int tmp;
+              prev_mode &= ~MODE_MODERATED;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_MODERATED)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'm';
+                current_mode->mode |= MODE_MODERATED;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'm';
+              break;
+            }
+            case 'n':
+            {
+              int tmp;
+              prev_mode &= ~MODE_NOPRIVMSGS;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'n';
+                current_mode->mode |= MODE_NOPRIVMSGS;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'n';
+              break;
+            }
+            case 'p':
+            {
+              int tmp;
+
+              /* Special case: */
+              if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
+                break;
+
+              prev_mode &= ~MODE_PRIVATE;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_PRIVATE)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'p';
+                current_mode->mode |= MODE_PRIVATE;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'p';
+              break;
+            }
+            case 's':
+            {
+              int tmp;
+              prev_mode &= ~MODE_SECRET;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_SECRET)) || wipeout)
+              {
+                bmodebuf[mblen++] = 's';
+                current_mode->mode |= MODE_SECRET;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 's';
+
+              /* Special case: */
+              if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
+              {
+                int i;
+                for (i = mblen2 - 1; i >= 0; --i)
+                  modebuf[i + 2] = modebuf[i];
+                modebuf[0] = '-';
+                modebuf[1] = 'p';
+                mblen2 += 2;
+                current_mode->mode &= ~MODE_PRIVATE;
+              }
+
+              break;
+            }
+            case 't':
+            {
+              int tmp;
+              prev_mode &= ~MODE_TOPICLIMIT;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
+              {
+                bmodebuf[mblen++] = 't';
+                current_mode->mode |= MODE_TOPICLIMIT;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 't';
+              break;
+            }
+          }
+        }                       /* <-- while over all modes */
+
+        bmodebuf[mblen] = '\0';
+        sendbuf[sblen] = '\0';
+        if (mblen)              /* Anything to send at all ? */
+        {
+          send_it = 1;
+          strcpy(sendbuf + sblen, " +");
+          sblen += 2;
+          strcpy(sendbuf + sblen, bmodebuf);
+          sblen += mblen;
+          strcpy(sendbuf + sblen, bparambuf);
+          sblen += strlen(bparambuf);
+        }
+        break;                  /* Done mode part */
+      }
+      case '%':         /* bans */
+      {
+        char *pv, *p = 0, *ban;
+        int first = 1;
+        if (netride)
+          break;                /* Ignore bans */
+        /* Run over all bans */
+        for (pv = parv[n] + 1; (ban = ircd_strtok(&p, pv, " ")); pv = 0)
+        {
+          int ret;
+          /*
+           * The following part should do the following:
+           * - If the new (un)ban is not a _change_ it is ignored.
+           * - Else, add it to sendbuf for later use.
+           * - If sendbuf is full, send it, and prepare a new
+           *   message in sendbuf.
+           */
+          ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
+          if (ret == 0)
+          {
+            add_banid_not_called = 0;
+            /* Mark this new ban so we can send it to the clients later */
+            chptr->banlist->flags |= CHFL_BURST_BAN;
+          }
+          if (ret != -1)
+            /* A new ban was added or an existing one needs to be passed on.
+             * Also add it to sendbuf: */
+            add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
+        }
+        break;                  /* Done bans part */
+      }
+      default:                  /* nicks */
+      {
+        char *pv, *p = 0, *nick, *ptr;
+        int first = 1;
+        /* Default mode: */
+        int default_mode = CHFL_DEOPPED;
+        /* Run over all nicks */
+        for (pv = parv[n]; (nick = ircd_strtok(&p, pv, ",")); pv = 0)
+        {
+          struct Client *acptr;
+          if ((ptr = strchr(nick, ':')))        /* New default mode ? */
+          {
+            *ptr = '\0';        /* Fix 'nick' */
+            acptr = findNUser(nick);
+            if (!netride)
+            {
+              /* Calculate new mode change: */
+              default_mode = CHFL_DEOPPED;
+              while (*(++ptr))
+                if (*ptr == 'o')
+                {
+                  default_mode |= CHFL_CHANOP;
+                  default_mode &= ~CHFL_DEOPPED;
+                }
+                else if (*ptr == 'v')
+                  default_mode |= CHFL_VOICE;
+                else
+                  break;
+            }
+          }
+          else
+            acptr = findNUser(nick);
+          /*
+           * Note that at this point we already received a 'NICK' for any
+           * <nick> numeric that is joining (and possibly opped) here.
+           * Therefore we consider the following situations:
+           * - The <nick> numeric exists and is from the direction of cptr: ok
+           * - The <nick> numeric does not exist:
+           *   Apparently this previous <nick> numeric was killed (upstream)
+           *   or it collided with an existing <nick> name.
+           * - The <nick> numeric exists but is from another direction:
+           *   Apparently this previous <nick> numeric was killed,
+           *   and due to a reroute it signed on via another link (probably
+           *   a nick [numeric] collision).
+           * Note that it can't be a QUIT or SQUIT, because a QUIT would
+           * come from the same direction as the BURST (cptr) while an
+           * upstream SQUIT removes the source (server) and we would thus
+           * have this BURST ignored already.
+           * This means that if we find the nick and it is from the correct
+           * direction, it joins. If it doesn't exist or is from another
+           * direction, we have to ignore it. If all nicks are ignored, we
+           * remove the channel again when it is empty and don't propagate
+           * the BURST message.
+           */
+          if (acptr && acptr->from == cptr)
+          {
+            /*
+             * The following should do the following:
+             * - Add it to sendbuf for later use.
+             * - If sendbuf is full, send it, and prepare a new
+             *   message in sendbuf.
+             */
+            add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
+                default_mode);
+            /* Let is take effect: (Note that in the case of a netride
+             * 'default_mode' is always CHFL_DEOPPED here). */
+            add_user_to_channel(chptr, acptr, default_mode | CHFL_BURST_JOINED);
+          }
+        }                       /* <-- Next nick */
+        if (!chptr->members)    /* All nicks collided and channel is empty ? */
+        {
+          sub1_from_channel(chptr);
+          return 0;             /* Forget about the (rest of the) message... */
+        }
+        break;                  /* Done nicks part */
+      }
+    }                           /* <-- Next parameter if any */
+  if (!chptr->members)          /* This message only contained bans (then the previous
+                                   message only contained collided nicks, see above) */
+  {
+    sub1_from_channel(chptr);
+    if (!add_banid_not_called)
+      while (next_removed_overlapped_ban());
+    return 0;                   /* Forget about the (rest of the) message... */
+  }
+
+  /* The last (possibly only) message is always send here */
+  if (send_it)                  /* Anything (left) to send ? */
+  {
+    struct DLink *lp;
+    struct Membership* member;
+
+    /* send 'sendbuf' to all downlinks */
+    for (lp = me.serv->down; lp; lp = lp->next)
+    {
+      if (lp->value.cptr == cptr)
+        continue;
+      if (Protocol(lp->value.cptr) > 9)
+        sendbufto_one(lp->value.cptr);
+    }
+
+    /*
+     * Now we finally can screw sendbuf again...
+     * Send all changes to the local clients:
+     *
+     * First send all joins and op them, because 2.9 servers
+     * would protest with a HACK if we first de-opped people.
+     * However, we don't send the +b bans yes, because we
+     * DO first want to -b the old bans (otherwise it's confusing).
+     */
+
+    /* Send all joins: */
+    for (member = chptr->members; member; member = member->next_member)
+      if (IsBurstJoined(member))
+      {
+        sendto_channel_butserv(chptr, member->user, ":%s JOIN :%s",
+                               member->user->name, chptr->chname);
+      }
+
+    if (!netride)
+    {
+      /* Send all +o and +v modes: */
+      for (member = chptr->members; member; member = member->next_member)
+      {
+        if (IsBurstJoined(member))
+        {
+          int mode = CHFL_CHANOP;
+          for (;;)
+          {
+            if ((member->status & mode))
+            {
+              modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
+              parabuf[pblen2++] = ' ';
+              strcpy(parabuf + pblen2, member->user->name);
+              pblen2 += strlen(member->user->name);
+              if (6 == ++cnt)
+              {
+                modebuf[mblen2] = 0;
+                sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+                    parv[0], chptr->chname, modebuf, parabuf);
+                *parabuf = 0;
+                pblen2 = 0;
+                mblen2 = 1;
+                cnt = 0;
+              }
+            }
+            if (mode == CHFL_CHANOP)
+              mode = CHFL_VOICE;
+            else
+              break;
+          }
+        }
+      }
+      /* Flush MODEs: */
+      if (cnt > 0 || mblen2 > 1)
+      {
+        modebuf[mblen2] = 0;
+        sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+            parv[0], chptr->chname, modebuf, parabuf);
+      }
+    }
+  }
+
+  if (wipeout)
+  {
+    struct Membership* member;
+    struct SLink**     ban;
+    int                mode;
+    char               m;
+    int                count = -1;
+
+    /* Now cancel all previous simple modes */
+    if ((prev_mode & MODE_SECRET))
+      cancel_mode(sptr, chptr, 's', 0, &count);
+    if ((prev_mode & MODE_PRIVATE))
+      cancel_mode(sptr, chptr, 'p', 0, &count);
+    if ((prev_mode & MODE_MODERATED))
+      cancel_mode(sptr, chptr, 'm', 0, &count);
+    if ((prev_mode & MODE_TOPICLIMIT))
+      cancel_mode(sptr, chptr, 't', 0, &count);
+    if ((prev_mode & MODE_INVITEONLY))
+      cancel_mode(sptr, chptr, 'i', 0, &count);
+    if ((prev_mode & MODE_NOPRIVMSGS))
+      cancel_mode(sptr, chptr, 'n', 0, &count);
+    if ((prev_mode & MODE_LIMIT))
+    {
+      current_mode->limit = 0;
+      cancel_mode(sptr, chptr, 'l', 0, &count);
+    }
+    if ((prev_mode & MODE_KEY))
+    {
+      *current_mode->key = 0;
+      cancel_mode(sptr, chptr, 'k', prev_key, &count);
+    }
+    current_mode->mode &= ~prev_mode;
+
+    /* And deop and devoice all net.riders on my side */
+    mode = CHFL_CHANOP;
+    m = 'o';
+    for (;;)
+    {
+      struct Membership* member_next = 0;
+
+      for (member = chptr->members; member; member = member_next)
+      {
+        member_next = member->next_member;
+        if (IsBurstJoined(member))
+          continue;             /* This is not a net.rider from
+                                   this side of the net.junction */
+#if defined(NO_INVITE_NETRIDE)
+        /*
+         * Kick net riding users from invite only channels.
+         *  - Isomer 25-11-1999
+         */
+        if (chptr->mode.mode & MODE_INVITEONLY) {
+          /* kick is magical - lotsa zombies and other undead.
+           * I'm hoping this is the right idea, comments anyone?
+           * Set everyone to a zombie, remove ops, and then send kicks
+           * everywhere...
+           */
+           if (IsZombie(member)) { /* don't kick ppl twice */
+                member->status = member->status & ~mode;
+                continue;
+           }
+
+           sendto_highprot_butone(0, 10, "%s " TOK_KICK " %s %s%s :Net Rider",
+            NumServ(&me), chptr->chname, NumNick(member->user));
+           sendto_channel_butserv(chptr, sptr,
+            ":%s KICK %s %s :Net Rider", me.name, chptr->chname,
+            member->user->name);
+
+           if (MyUser(member->user)) {
+             sendto_lowprot_butone(0, 9, ":%s PART %s",
+               member->user->name, chptr->chname, member->user->name);
+             sendto_highprot_butone(0, 10, "%s%s PART %s",
+               NumNick(member->user), chptr->chname);
+             remove_user_from_channel(member->user, chptr);
+           }
+           else {
+             member->status = (member->status & ~mode) | CHFL_ZOMBIE;
+           }
+           continue;
+        }
+#endif /* defined(NO_INVITE_NETRIDE) */
+        if ((member->status & mode))
+        {
+          member->status &= ~mode;
+          if (mode == CHFL_CHANOP)
+            SetDeopped(member);
+          cancel_mode(sptr, chptr, m, member->user->name, &count);
+        }
+      }
+      if (mode == CHFL_VOICE)
+        break;
+      mode = CHFL_VOICE;
+      m = 'v';
+    }
+
+    /* And finally wipeout all bans that are left */
+    for (ban = &chptr->banlist; *ban; ) {
+      struct SLink* tmp = *ban;
+      if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT)) {
+        struct Membership* member_z;
+
+        *ban = tmp->next;
+        cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
+
+        /* Copied from del_banid(): */
+        MyFree(tmp->value.ban.banstr);
+        MyFree(tmp->value.ban.who);
+        free_link(tmp);
+
+        /* Erase ban-valid-bit, for channel members that are banned */
+        for (member_z = chptr->members; member_z; member_z = member_z->next_member)
+          if ((member_z->status & CHFL_BANVALIDMASK) == CHFL_BANVALIDMASK)
+            ClearBanValid(member_z);
+      }
+      else
+        ban = &tmp->next;
+    }
+    /* Also wipeout overlapped bans */
+    if (!add_banid_not_called)
+    {
+      struct SLink *ban;
+      while ((ban = next_removed_overlapped_ban()))
+        cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
+    }
+    cancel_mode(sptr, chptr, 0, 0, &count);  /* flush */
+  }
+
+  if (send_it && !netride)
+  {
+    struct SLink *bl;
+    int deban;
+
+    if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
+    {
+      deban = 0;
+      bl = chptr->banlist;
+      *modebuf = '+';
+    }
+    else
+    {
+      deban = 1;
+      *modebuf = '-';
+    }
+
+    mblen2 = 1;
+    pblen2 = 0;
+    cnt = 0;
+    for (;;)
+    {
+      size_t nblen = 0;
+      if (bl)
+        nblen = strlen(bl->value.ban.banstr);
+      if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN) /* The last check is to make sure
+                                                                           that the receiving 2.9 will
+                                                                           still process this */
+      {
+        /* Time to send buffer */
+        modebuf[mblen2] = 0;
+        sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+            parv[0], chptr->chname, modebuf, parabuf);
+        *modebuf = deban ? '-' : '+';
+        mblen2 = 1;
+        pblen2 = 0;
+        cnt = 0;
+      }
+      if (!bl)                  /* Done ? */
+        break;
+      if (deban || (bl->flags & CHFL_BURST_BAN))
+      {
+        /* Add ban to buffers and remove it */
+        modebuf[mblen2++] = 'b';
+        parabuf[pblen2++] = ' ';
+        strcpy(parabuf + pblen2, bl->value.ban.banstr);
+        pblen2 += nblen;
+        cnt++;
+        bl->flags &= ~CHFL_BURST_BAN;
+      }
+      if (deban)
+      {
+        if (!(bl = next_removed_overlapped_ban()))
+        {
+          deban = 0;
+          modebuf[mblen2++] = '+';
+          bl = chptr->banlist;
+        }
+      }
+      else
+        bl = bl->next;
+    }
+    /* Flush MODE [-b]+b ...: */
+    if (cnt > 0 || mblen2 > 1)
+    {
+      modebuf[mblen2] = 0;
+      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+          parv[0], chptr->chname, modebuf, parabuf);
+    }
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_burst  --  by Run carlo@runaway.xs4all.nl  december 1995 till march 1997
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel name
+ * parv[2] = channel timestamp
+ * The meaning of the following parv[]'s depend on their first character:
+ * If parv[n] starts with a '+':
+ * Net burst, additive modes
+ *   parv[n] = <mode>
+ *   parv[n+1] = <param> (optional)
+ *   parv[n+2] = <param> (optional)
+ * If parv[n] starts with a '%', then n will be parc-1:
+ *   parv[n] = %<ban> <ban> <ban> ...
+ * If parv[n] starts with another character:
+ *   parv[n] = <nick>[:<mode>],<nick>[:<mode>],...
+ *   where <mode> is the channel mode (ov) of nick and all following nicks.
+ *
+ * Example:
+ * "S BURST #channel 87654321 +ntkl key 123 AAA,AAB:o,BAA,BAB:ov :%ban1 ban2"
+ *
+ * Anti net.ride code.
+ *
+ * When the channel already exist, and its TS is larger then
+ * the TS in the BURST message, then we cancel all existing modes.
+ * If its is smaller then the received BURST message is ignored.
+ * If it's equal, then the received modes are just added.
+ */
+int m_burst(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel* chptr;
+  time_t          timestamp;
+  int             netride = 0;
+  int             wipeout = 0;
+  int             n;
+  int             send_it = 0;
+  int             add_banid_not_called = 1;
+  struct Mode*    current_mode;
+  size_t          sblen;
+  size_t          mblen = 0;
+  int             mblen2;
+  int             pblen2;
+  int             cnt;
+  int             prev_mode;
+  char            prev_key[KEYLEN + 1];
+  struct Membership* member;
+  struct SLink*   lp;
+  char modebuf[MODEBUFLEN];
+  char parabuf[MODEBUFLEN];
+  char bmodebuf[MODEBUFLEN];
+  char bparambuf[MODEBUFLEN];
+
+  /* BURST is only for servers and has at least 4 parameters */
+  if (!IsServer(cptr) || parc < 4)
+    return 0;
+
+  if (!IsBurst(sptr))
+  {
+    int i;
+    char *p;
+    if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
+    {
+      p =
+          sprintf_irc(sendbuf,
+          ":%s NOTICE * :*** Notice -- HACK(4): %s BURST %s %s", me.name,
+          sptr->name, parv[1], parv[2]);
+      for (i = 3; i < parc - 1; ++i)
+        p = sprintf_irc(p, " %s", parv[i]);
+      sprintf_irc(p, " :%s", parv[parc - 1]);
+      sendbufto_op_mask(SNO_HACK4);
+    }
+    else
+    {
+#if 1                           /* FIXME: This should be removed after all HUBs upgraded to ircu2.10.05 */
+      SetBurst(sptr);
+      if (MyConnect(sptr))
+#endif
+        return exit_client_msg(cptr, cptr, &me,
+            "HACK: BURST message outside net.burst from %s", sptr->name);
+    }
+  }
+
+  /* Find the channel, or create it - note that the creation time
+   * will be 0 if it has to be created */
+  chptr = get_channel(sptr, parv[1], CGT_CREATE);
+  current_mode = &chptr->mode;
+  prev_mode = chptr->mode.mode;
+  if (*chptr->mode.key)
+  {
+    prev_mode |= MODE_KEY;
+    strcpy(prev_key, chptr->mode.key);
+  }
+  if (chptr->mode.limit)
+    prev_mode |= MODE_LIMIT;
+
+  timestamp = atoi(parv[2]);
+
+  /* Copy the new TS when the received creationtime appears to be older */
+  if (!chptr->creationtime || chptr->creationtime > timestamp)
+  {
+    /* Set the new timestamp */
+    chptr->creationtime = timestamp;
+    send_it = 1;                /* Make sure we pass on the different timestamp ! */
+    /* Mark all bans as needed to be wiped out */
+    for (lp = chptr->banlist; lp; lp = lp->next)
+      lp->flags |= CHFL_BURST_BAN_WIPEOUT;
+    /*
+     * Only the first BURST for this channel can have creationtime > timestamp,
+     * so at this moment ALL members are on OUR side, and thus all net.riders:
+     */
+    wipeout = 1;
+  }
+  for (member = chptr->members; member; member = member->next_member)
+    member->status &= ~CHFL_BURST_JOINED;    /* Set later for nicks in the BURST msg */
+  /* If `wipeout' is set then these will be deopped later. */
+
+  /* If the entering creationtime is younger, ignore the modes */
+  if (chptr->creationtime < timestamp)
+    netride = 1;                /* Only pass on the nicks (so they JOIN) */
+
+  /* Prepare buffers to pass the message */
+  *bparambuf = *bmodebuf = *parabuf = '\0';
+  pblen2 = 0;
+  *modebuf = '+';
+  mblen2 = 1;
+  cnt = 0;
+  sblen = sprintf_irc(sendbuf, "%s B %s " TIME_T_FMT,
+      NumServ(sptr), chptr->chname, chptr->creationtime) - sendbuf;
+
+  /* Run over all remaining parameters */
+  for (n = 3; n < parc; n++)
+    switch (*parv[n])           /* What type is it ? mode, nicks or bans ? */
+    {
+      case '+':         /* modes */
+      {
+        char *p = parv[n];
+        while (*(++p))          /* Run over all mode characters */
+        {
+          switch (*p)           /* which mode ? */
+          {
+              /*
+               * The following cases all do the following:
+               * - In case wipeout needed, reset 'prev_mode' to indicate this
+               *   mode should not be cancelled.
+               * - If wipeout or (not netride and the new mode is a change),
+               *   add it to bmodebuf and bparabuf for propagation.
+               * - Else ignore it.
+               * - Add it to modebuf and parabuf for propagation to the
+               *   clients when not netride and the new mode is a change.
+               * Special cases:
+               * - If a +s is received, cancel a +p and sent a -p to the
+               *   clients too (if +p was set).
+               * - If a +p is received and +s is set, ignore the +p.
+               */
+            case 'i':
+            {
+              int tmp;
+              prev_mode &= ~MODE_INVITEONLY;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_INVITEONLY)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'i';
+                current_mode->mode |= MODE_INVITEONLY;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'i';
+              break;
+            }
+            case 'k':
+            {
+              int tmp;
+              char *param = parv[++n];
+              prev_mode &= ~MODE_KEY;
+              if (!(tmp = netride || (*current_mode->key &&
+                  (!strcmp(current_mode->key, param) ||
+                  (!wipeout && strcmp(current_mode->key, param) < 0)))) ||
+                  wipeout)
+              {
+                bmodebuf[mblen++] = 'k';
+                strcat(bparambuf, " ");
+                strcat(bparambuf, param);
+                ircd_strncpy(current_mode->key, param, KEYLEN);
+              }
+              if (!tmp && !wipeout)
+              {
+                modebuf[mblen2++] = 'k';
+                parabuf[pblen2++] = ' ';
+                strcpy(parabuf + pblen2, param);
+                pblen2 += strlen(param);
+                cnt++;
+              }
+              break;
+            }
+            case 'l':
+            {
+              int tmp;
+              unsigned int param = atoi(parv[++n]);
+              prev_mode &= ~MODE_LIMIT;
+              if (!(tmp = netride || (current_mode->limit &&
+                  (current_mode->limit == param ||
+                  (!wipeout && current_mode->limit < param)))) || wipeout)
+              {
+                bmodebuf[mblen++] = 'l';
+                sprintf_irc(bparambuf + strlen(bparambuf), " %d", param);
+                current_mode->limit = param;
+              }
+              if (!tmp)
+              {
+                modebuf[mblen2++] = 'l';
+                pblen2 = sprintf_irc(parabuf + pblen2, " %d", param) - parabuf;
+                cnt++;
+              }
+              break;
+            }
+            case 'm':
+            {
+              int tmp;
+              prev_mode &= ~MODE_MODERATED;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_MODERATED)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'm';
+                current_mode->mode |= MODE_MODERATED;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'm';
+              break;
+            }
+            case 'n':
+            {
+              int tmp;
+              prev_mode &= ~MODE_NOPRIVMSGS;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_NOPRIVMSGS)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'n';
+                current_mode->mode |= MODE_NOPRIVMSGS;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'n';
+              break;
+            }
+            case 'p':
+            {
+              int tmp;
+
+              /* Special case: */
+              if (!netride && !wipeout && (current_mode->mode & MODE_SECRET))
+                break;
+
+              prev_mode &= ~MODE_PRIVATE;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_PRIVATE)) || wipeout)
+              {
+                bmodebuf[mblen++] = 'p';
+                current_mode->mode |= MODE_PRIVATE;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 'p';
+              break;
+            }
+            case 's':
+            {
+              int tmp;
+              prev_mode &= ~MODE_SECRET;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_SECRET)) || wipeout)
+              {
+                bmodebuf[mblen++] = 's';
+                current_mode->mode |= MODE_SECRET;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 's';
+
+              /* Special case: */
+              if (!netride && !wipeout && (current_mode->mode & MODE_PRIVATE))
+              {
+                int i;
+                for (i = mblen2 - 1; i >= 0; --i)
+                  modebuf[i + 2] = modebuf[i];
+                modebuf[0] = '-';
+                modebuf[1] = 'p';
+                mblen2 += 2;
+                current_mode->mode &= ~MODE_PRIVATE;
+              }
+
+              break;
+            }
+            case 't':
+            {
+              int tmp;
+              prev_mode &= ~MODE_TOPICLIMIT;
+              if (!(tmp = netride ||
+                  (current_mode->mode & MODE_TOPICLIMIT)) || wipeout)
+              {
+                bmodebuf[mblen++] = 't';
+                current_mode->mode |= MODE_TOPICLIMIT;
+              }
+              if (!tmp)
+                modebuf[mblen2++] = 't';
+              break;
+            }
+          }
+        }                       /* <-- while over all modes */
+
+        bmodebuf[mblen] = '\0';
+        sendbuf[sblen] = '\0';
+        if (mblen)              /* Anything to send at all ? */
+        {
+          send_it = 1;
+          strcpy(sendbuf + sblen, " +");
+          sblen += 2;
+          strcpy(sendbuf + sblen, bmodebuf);
+          sblen += mblen;
+          strcpy(sendbuf + sblen, bparambuf);
+          sblen += strlen(bparambuf);
+        }
+        break;                  /* Done mode part */
+      }
+      case '%':         /* bans */
+      {
+        char *pv, *p = 0, *ban;
+        int first = 1;
+        if (netride)
+          break;                /* Ignore bans */
+        /* Run over all bans */
+        for (pv = parv[n] + 1; (ban = ircd_strtok(&p, pv, " ")); pv = 0)
+        {
+          int ret;
+          /*
+           * The following part should do the following:
+           * - If the new (un)ban is not a _change_ it is ignored.
+           * - Else, add it to sendbuf for later use.
+           * - If sendbuf is full, send it, and prepare a new
+           *   message in sendbuf.
+           */
+          ret = add_banid(sptr, chptr, ban, 1, add_banid_not_called);
+          if (ret == 0)
+          {
+            add_banid_not_called = 0;
+            /* Mark this new ban so we can send it to the clients later */
+            chptr->banlist->flags |= CHFL_BURST_BAN;
+          }
+          if (ret != -1)
+            /* A new ban was added or an existing one needs to be passed on.
+             * Also add it to sendbuf: */
+            add_token_to_sendbuf(ban, &sblen, &first, &send_it, '%', 0);
+        }
+        break;                  /* Done bans part */
+      }
+      default:                  /* nicks */
+      {
+        char *pv, *p = 0, *nick, *ptr;
+        int first = 1;
+        /* Default mode: */
+        int default_mode = CHFL_DEOPPED;
+        /* Run over all nicks */
+        for (pv = parv[n]; (nick = ircd_strtok(&p, pv, ",")); pv = 0)
+        {
+          struct Client *acptr;
+          if ((ptr = strchr(nick, ':')))        /* New default mode ? */
+          {
+            *ptr = '\0';        /* Fix 'nick' */
+            acptr = findNUser(nick);
+            if (!netride)
+            {
+              /* Calculate new mode change: */
+              default_mode = CHFL_DEOPPED;
+              while (*(++ptr))
+                if (*ptr == 'o')
+                {
+                  default_mode |= CHFL_CHANOP;
+                  default_mode &= ~CHFL_DEOPPED;
+                }
+                else if (*ptr == 'v')
+                  default_mode |= CHFL_VOICE;
+                else
+                  break;
+            }
+          }
+          else
+            acptr = findNUser(nick);
+          /*
+           * Note that at this point we already received a 'NICK' for any
+           * <nick> numeric that is joining (and possibly opped) here.
+           * Therefore we consider the following situations:
+           * - The <nick> numeric exists and is from the direction of cptr: ok
+           * - The <nick> numeric does not exist:
+           *   Apparently this previous <nick> numeric was killed (upstream)
+           *   or it collided with an existing <nick> name.
+           * - The <nick> numeric exists but is from another direction:
+           *   Apparently this previous <nick> numeric was killed,
+           *   and due to a reroute it signed on via another link (probably
+           *   a nick [numeric] collision).
+           * Note that it can't be a QUIT or SQUIT, because a QUIT would
+           * come from the same direction as the BURST (cptr) while an
+           * upstream SQUIT removes the source (server) and we would thus
+           * have this BURST ignored already.
+           * This means that if we find the nick and it is from the correct
+           * direction, it joins. If it doesn't exist or is from another
+           * direction, we have to ignore it. If all nicks are ignored, we
+           * remove the channel again when it is empty and don't propagate
+           * the BURST message.
+           */
+          if (acptr && acptr->from == cptr)
+          {
+            /*
+             * The following should do the following:
+             * - Add it to sendbuf for later use.
+             * - If sendbuf is full, send it, and prepare a new
+             *   message in sendbuf.
+             */
+            add_token_to_sendbuf(nick, &sblen, &first, &send_it, 0,
+                default_mode);
+            /* Let is take effect: (Note that in the case of a netride
+             * 'default_mode' is always CHFL_DEOPPED here). */
+            add_user_to_channel(chptr, acptr, default_mode | CHFL_BURST_JOINED);
+          }
+        }                       /* <-- Next nick */
+        if (!chptr->members)    /* All nicks collided and channel is empty ? */
+        {
+          sub1_from_channel(chptr);
+          return 0;             /* Forget about the (rest of the) message... */
+        }
+        break;                  /* Done nicks part */
+      }
+    }                           /* <-- Next parameter if any */
+  if (!chptr->members)          /* This message only contained bans (then the previous
+                                   message only contained collided nicks, see above) */
+  {
+    sub1_from_channel(chptr);
+    if (!add_banid_not_called)
+      while (next_removed_overlapped_ban());
+    return 0;                   /* Forget about the (rest of the) message... */
+  }
+
+  /* The last (possibly only) message is always send here */
+  if (send_it)                  /* Anything (left) to send ? */
+  {
+    struct DLink *lp;
+    struct Membership* member;
+
+    /* send 'sendbuf' to all downlinks */
+    for (lp = me.serv->down; lp; lp = lp->next)
+    {
+      if (lp->value.cptr == cptr)
+        continue;
+      if (Protocol(lp->value.cptr) > 9)
+        sendbufto_one(lp->value.cptr);
+    }
+
+    /*
+     * Now we finally can screw sendbuf again...
+     * Send all changes to the local clients:
+     *
+     * First send all joins and op them, because 2.9 servers
+     * would protest with a HACK if we first de-opped people.
+     * However, we don't send the +b bans yes, because we
+     * DO first want to -b the old bans (otherwise it's confusing).
+     */
+
+    /* Send all joins: */
+    for (member = chptr->members; member; member = member->next_member)
+      if (IsBurstJoined(member))
+      {
+        sendto_channel_butserv(chptr, member->user, ":%s JOIN :%s",
+                               member->user->name, chptr->chname);
+      }
+
+    if (!netride)
+    {
+      /* Send all +o and +v modes: */
+      for (member = chptr->members; member; member = member->next_member)
+      {
+        if (IsBurstJoined(member))
+        {
+          int mode = CHFL_CHANOP;
+          for (;;)
+          {
+            if ((member->status & mode))
+            {
+              modebuf[mblen2++] = (mode == CHFL_CHANOP) ? 'o' : 'v';
+              parabuf[pblen2++] = ' ';
+              strcpy(parabuf + pblen2, member->user->name);
+              pblen2 += strlen(member->user->name);
+              if (6 == ++cnt)
+              {
+                modebuf[mblen2] = 0;
+                sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+                    parv[0], chptr->chname, modebuf, parabuf);
+                *parabuf = 0;
+                pblen2 = 0;
+                mblen2 = 1;
+                cnt = 0;
+              }
+            }
+            if (mode == CHFL_CHANOP)
+              mode = CHFL_VOICE;
+            else
+              break;
+          }
+        }
+      }
+      /* Flush MODEs: */
+      if (cnt > 0 || mblen2 > 1)
+      {
+        modebuf[mblen2] = 0;
+        sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+            parv[0], chptr->chname, modebuf, parabuf);
+      }
+    }
+  }
+
+  if (wipeout)
+  {
+    struct Membership* member;
+    struct SLink**     ban;
+    int                mode;
+    char               m;
+    int                count = -1;
+
+    /* Now cancel all previous simple modes */
+    if ((prev_mode & MODE_SECRET))
+      cancel_mode(sptr, chptr, 's', 0, &count);
+    if ((prev_mode & MODE_PRIVATE))
+      cancel_mode(sptr, chptr, 'p', 0, &count);
+    if ((prev_mode & MODE_MODERATED))
+      cancel_mode(sptr, chptr, 'm', 0, &count);
+    if ((prev_mode & MODE_TOPICLIMIT))
+      cancel_mode(sptr, chptr, 't', 0, &count);
+    if ((prev_mode & MODE_INVITEONLY))
+      cancel_mode(sptr, chptr, 'i', 0, &count);
+    if ((prev_mode & MODE_NOPRIVMSGS))
+      cancel_mode(sptr, chptr, 'n', 0, &count);
+    if ((prev_mode & MODE_LIMIT))
+    {
+      current_mode->limit = 0;
+      cancel_mode(sptr, chptr, 'l', 0, &count);
+    }
+    if ((prev_mode & MODE_KEY))
+    {
+      *current_mode->key = 0;
+      cancel_mode(sptr, chptr, 'k', prev_key, &count);
+    }
+    current_mode->mode &= ~prev_mode;
+
+    /* And deop and devoice all net.riders on my side */
+    mode = CHFL_CHANOP;
+    m = 'o';
+    for (;;)
+    {
+      struct Membership* member_next = 0;
+
+      for (member = chptr->members; member; member = member_next)
+      {
+        member_next = member->next_member;
+        if (IsBurstJoined(member))
+          continue;             /* This is not a net.rider from
+                                   this side of the net.junction */
+#if defined(NO_INVITE_NETRIDE)
+        /*
+         * Kick net riding users from invite only channels.
+         *  - Isomer 25-11-1999
+         */
+        if (chptr->mode.mode & MODE_INVITEONLY) {
+          /* kick is magical - lotsa zombies and other undead.
+           * I'm hoping this is the right idea, comments anyone?
+           * Set everyone to a zombie, remove ops, and then send kicks
+           * everywhere...
+           */
+           if (IsZombie(member)) { /* don't kick ppl twice */
+                member->status = member->status & ~mode;
+                continue;
+           }
+           member->status = (member->status & ~mode) | CHFL_ZOMBIE;
+
+           sendto_highprot_butone(0, 10, "%s " TOK_KICK "%s %s%s :Net Rider",
+            NumServ(&me), chptr->chname, NumNick(member->user));
+           sendto_channel_butserv(chptr, sptr,
+            ":%s KICK %s %s :Net Rider", me.name, chptr->chname,
+            member->user->name);
+
+           if (MyUser(member->user)) {
+             sendto_lowprot_butone(0, 9, ":%s PART %s",
+               member->user->name, chptr->chname, member->user->name);
+             sendto_highprot_butone(0, 10, "%s%s PART %s",
+               NumNick(member->user), chptr->chname);
+             remove_user_from_channel(member->user, chptr);
+           }
+           else {
+             member->status = (member->status & ~mode) | CHFL_ZOMBIE;
+           }
+           continue;
+        }
+#endif /* defined(NO_INVITE_NETRIDE) */
+        if ((member->status & mode))
+        {
+          member->status &= ~mode;
+          if (mode == CHFL_CHANOP)
+            SetDeopped(member);
+          cancel_mode(sptr, chptr, m, member->user->name, &count);
+        }
+      }
+      if (mode == CHFL_VOICE)
+        break;
+      mode = CHFL_VOICE;
+      m = 'v';
+    }
+
+    /* And finally wipeout all bans that are left */
+    for (ban = &chptr->banlist; *ban; ) {
+      struct SLink* tmp = *ban;
+      if ((tmp->flags & CHFL_BURST_BAN_WIPEOUT)) {
+        struct Membership* member_z;
+
+        *ban = tmp->next;
+        cancel_mode(sptr, chptr, 'b', tmp->value.ban.banstr, &count);
+
+        /* Copied from del_banid(): */
+        MyFree(tmp->value.ban.banstr);
+        MyFree(tmp->value.ban.who);
+        free_link(tmp);
+
+        /* Erase ban-valid-bit, for channel members that are banned */
+        for (member_z = chptr->members; member_z; member_z = member_z->next_member)
+          if ((member_z->status & CHFL_BANVALIDMASK) == CHFL_BANVALIDMASK)
+            ClearBanValid(member_z);
+      }
+      else
+        ban = &tmp->next;
+    }
+    /* Also wipeout overlapped bans */
+    if (!add_banid_not_called)
+    {
+      struct SLink *ban;
+      while ((ban = next_removed_overlapped_ban()))
+        cancel_mode(sptr, chptr, 'b', ban->value.ban.banstr, &count);
+    }
+    cancel_mode(sptr, chptr, 0, 0, &count);  /* flush */
+  }
+
+  if (send_it && !netride)
+  {
+    struct SLink *bl;
+    int deban;
+
+    if (add_banid_not_called || !(bl = next_removed_overlapped_ban()))
+    {
+      deban = 0;
+      bl = chptr->banlist;
+      *modebuf = '+';
+    }
+    else
+    {
+      deban = 1;
+      *modebuf = '-';
+    }
+
+    mblen2 = 1;
+    pblen2 = 0;
+    cnt = 0;
+    for (;;)
+    {
+      size_t nblen = 0;
+      if (bl)
+        nblen = strlen(bl->value.ban.banstr);
+      if (cnt == 6 || (!bl && cnt) || pblen2 + nblen + 12 > MODEBUFLEN) /* The last check is to make sure
+                                                                           that the receiving 2.9 will
+                                                                           still process this */
+      {
+        /* Time to send buffer */
+        modebuf[mblen2] = 0;
+        sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+            parv[0], chptr->chname, modebuf, parabuf);
+        *modebuf = deban ? '-' : '+';
+        mblen2 = 1;
+        pblen2 = 0;
+        cnt = 0;
+      }
+      if (!bl)                  /* Done ? */
+        break;
+      if (deban || (bl->flags & CHFL_BURST_BAN))
+      {
+        /* Add ban to buffers and remove it */
+        modebuf[mblen2++] = 'b';
+        parabuf[pblen2++] = ' ';
+        strcpy(parabuf + pblen2, bl->value.ban.banstr);
+        pblen2 += nblen;
+        cnt++;
+        bl->flags &= ~CHFL_BURST_BAN;
+      }
+      if (deban)
+      {
+        if (!(bl = next_removed_overlapped_ban()))
+        {
+          deban = 0;
+          modebuf[mblen2++] = '+';
+          bl = chptr->banlist;
+        }
+      }
+      else
+        bl = bl->next;
+    }
+    /* Flush MODE [-b]+b ...: */
+    if (cnt > 0 || mblen2 > 1)
+    {
+      modebuf[mblen2] = 0;
+      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s%s",
+          parv[0], chptr->chname, modebuf, parabuf);
+    }
+  }
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_close.c b/ircd/m_close.c
new file mode 100644 (file)
index 0000000..3fd7dd8
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_close.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mo_close - oper message handler
+ * - added by Darren Reed Jul 13 1992.
+ */
+int mo_close(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+  sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0],
+             net_close_unregistered_connections(sptr));
+  return 0;
+}
+
+
diff --git a/ircd/m_connect.c b/ircd/m_connect.c
new file mode 100644 (file)
index 0000000..5c317e3
--- /dev/null
@@ -0,0 +1,501 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_connect.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "crule.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * ms_connect - server message handler
+ * - Added by Jto 11 Feb 1989
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = port number
+ *    parv[3] = remote server
+ */
+int ms_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  unsigned short   port;
+  unsigned short   tmpport;
+  const char*      crule_name;
+  struct ConfItem* aconf;
+  struct Client*   acptr;
+  
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (!IsPrivileged(sptr))
+    return send_error_to_client(sptr, ERR_NOPRIVILEGES);
+
+  if (parc < 4) {
+    /*
+     * this is coming from a server which should have already
+     * checked it's args, if we don't have parc == 4, something
+     * isn't right.
+     */
+    return need_more_params(sptr, "CONNECT");
+  }
+
+  if (hunt_server(1, cptr, sptr,
+                  "%s%s " TOK_CONNECT " %s %s :%s", 3, parc, parv) != HUNTED_ISME)
+    return 0;
+
+  /*
+   * need to find the conf entry first so we can use the server name from
+   * the conf entry instead of parv[1] to find out if the server is already
+   * present below. --Bleep
+   */
+  if (0 == (aconf = conf_find_server(parv[1]))) {
+    sendto_one(sptr, "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
+               NumServ(&me), NumNick(sptr), parv[1]);
+    return 0;
+  }
+  /*
+   * use aconf->name to look up the server
+   */
+  if ((acptr = FindServer(aconf->name))) {
+    sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
+               NumServ(&me), NumNick(sptr), parv[1], "already exists from",
+               acptr->from->name);
+    return 0;
+  }
+  /*
+   * Evaluate connection rules...  If no rules found, allow the
+   * connect.   Otherwise stop with the first true rule (ie: rules
+   * are ored together.  Oper connects are effected only by D
+   * lines (CRULEALL) not d lines (CRULEAUTO).
+   */
+  if ((crule_name = conf_eval_crule(aconf))) {
+    sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
+               NumServ(&me), NumNick(sptr), crule_name);
+    return 0;
+  }
+  /*
+   * Get port number from params, port must be non-zero if it comes from a
+   * server.
+   */
+  if ((port = atoi(parv[2])) == 0) {
+    sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
+               NumServ(&me), NumNick(sptr));
+    return 0;
+  }
+  /*
+   * save the old port
+   */
+  tmpport = aconf->port;
+  aconf->port = port;
+  /*
+   * Notify all operators about remote connect requests
+   */
+  sendto_ops_butone(0, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
+                    me.name, parv[1], parv[2] ? parv[2] : "", 
+                    get_client_name(sptr, HIDE_IP));
+  ircd_log(L_INFO, "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
+
+  if (connect_server(aconf, sptr, 0)) {
+    sendto_one(sptr, "%s NOTICE %s%s :*** Connecting to %s.",
+               NumServ(&me), NumNick(sptr), aconf->name);
+  }
+  else {
+    sendto_one(sptr, "%s NOTICE %s%s :*** Connection to %s failed",
+               NumServ(&me), NumNick(sptr), aconf->name);
+  }
+  aconf->port = tmpport;
+  return 0;
+}
+
+/*
+ * mo_connect - oper message handler
+ * - Added by Jto 11 Feb 1989
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = port number
+ *    parv[3] = remote server
+ */
+int mo_connect(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  unsigned short   port;
+  unsigned short   tmpport;
+  const char*      crule_name;
+  struct ConfItem* aconf;
+  struct Client*   acptr;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+  if (parc < 2)
+    return need_more_params(sptr, "CONNECT");
+
+  if (parc > 3) {
+    /*
+     * if parc > 3, we are trying to connect two remote
+     * servers to each other
+     */
+    if (IsLocOp(sptr)) {
+      /*
+       * Only allow LocOps to make local CONNECTS --SRB
+       */
+      return 0;
+    }
+    else {
+      struct Client* acptr2;
+      struct Client* acptr3;
+
+      if (!(acptr3 = find_match_server(parv[3]))) {
+        send_error_to_client(sptr, ERR_NOSUCHSERVER, parv[3]);
+        return 0;
+      }
+
+      /*
+       * Look for closest matching server 
+       * needed for "/connect blah 4400 *"?
+       */
+      for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up) {
+        if (!match(parv[3], acptr2->name))
+          acptr3 = acptr2;
+      }
+      parv[3] = acptr3->name;
+      if (hunt_server(1, cptr, sptr, "%s%s " TOK_CONNECT " %s %s :%s",
+                      3, parc, parv) != HUNTED_ISME)
+        return 0;
+    }
+  }
+  /*
+   * need to find the conf entry first so we can use the server name from
+   * the conf entry instead of parv[1] to find out if the server is already
+   * present below. --Bleep
+   */
+  if (0 == (aconf = conf_find_server(parv[1]))) {
+    sendto_one(sptr,
+               ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
+               me.name, parv[0], parv[1]);
+    return 0;
+  }
+  /*
+   * use aconf->name to look up the server, see above
+   */
+  if ((acptr = FindServer(aconf->name))) {
+    sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
+               me.name, parv[0], parv[1], "already exists from",
+               acptr->from->name);
+    return 0;
+  }
+  /*
+   * Evaluate connection rules...  If no rules found, allow the
+   * connect.   Otherwise stop with the first true rule (ie: rules
+   * are ored together.  Oper connects are effected only by D
+   * lines (CRULEALL) not d lines (CRULEAUTO).
+   */
+  if ((crule_name = conf_eval_crule(aconf))) {
+    sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
+               me.name, parv[0], crule_name);
+    return 0;
+  }
+  /*
+   *  Get port number from user, if given. If not specified,
+   *  use the default from configuration structure. If missing
+   *  from there, then use the precompiled default.
+   */
+  port = aconf->port;
+  if (parc > 2) {
+    assert(0 != parv[2]);
+    if (0 == (port = atoi(parv[2]))) {
+      sendto_one(sptr, ":%s NOTICE %s :Connect: Invalid port number",
+                 me.name, parv[0]);
+      return 0;
+    }
+  }
+  if (0 == port && 0 == (port = SERVER_PORT)) {
+    sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
+               me.name, parv[0]);
+    return 0;
+  }
+
+  tmpport = aconf->port;
+  aconf->port = port;
+
+  if (connect_server(aconf, sptr, 0)) {
+    sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s.",
+               me.name, parv[0], aconf->name);
+  }
+  else {
+    sendto_one(sptr, ":%s NOTICE %s :*** Connection to %s failed",
+               me.name, parv[0], aconf->name);
+  }
+  aconf->port = tmpport;
+  return 0;
+}
+
+  
+#if 0
+/*
+ * XXX - remove when regression testing complete
+ *
+ *  m_connect                           - Added by Jto 11 Feb 1989
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = port number
+ *    parv[3] = remote server
+ */
+int m_connect(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  unsigned short   port;
+  unsigned short   tmpport;
+  struct ConfItem* aconf;
+  struct ConfItem* cconf;
+  struct Client*   acptr;
+
+  if (!IsPrivileged(sptr)) {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return -1;
+  }
+
+  if (IsLocOp(sptr) && parc > 3)        /* Only allow LocOps to make */
+    return 0;                   /* local CONNECTS --SRB      */
+
+  if (parc > 3 && MyUser(sptr)) {
+    struct Client* acptr2;
+    struct Client* acptr3;
+    if (!(acptr3 = find_match_server(parv[3]))) {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]);
+      return 0;
+    }
+
+    /* Look for closest matching server */
+    for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up)
+      if (!match(parv[3], acptr2->name))
+        acptr3 = acptr2;
+
+    parv[3] = acptr3->name;
+  }
+
+  if (hunt_server(1, cptr, sptr,
+                  "%s%s " TOK_CONNECT " %s %s :%s", 3, parc, parv) != HUNTED_ISME)
+    return 0;
+
+  if (parc < 2 || *parv[1] == '\0') {
+    return need_more_params(sptr, "CONNECT");
+#if 0
+    return -1;
+#endif
+  }
+
+  if ((acptr = FindServer(parv[1]))) {
+    if (MyUser(sptr))
+      sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
+          me.name, parv[0], parv[1], "already exists from", acptr->from->name);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
+          NumServ(&me), NumNick(sptr), parv[1], "already exists from",
+          acptr->from->name);
+    return 0;
+  }
+
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+    if (CONF_SERVER == aconf->status && 0 == match(parv[1], aconf->name))
+      break;
+  }
+#if 0
+  /*
+   * Checked first servernames, then try hostnames.
+   */
+  if (!aconf) {
+    for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
+      if (CONF_SERVER == aconf->status && 0 == match(parv[1], aconf->host))
+        break;
+    }
+  }
+#endif
+  if (!aconf) {
+    if (MyUser(sptr))
+      sendto_one(sptr, ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
+                 me.name, parv[0], parv[1]);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
+                 NumServ(&me), NumNick(sptr), parv[1]);
+    return 0;
+  }
+  /*
+   *  Get port number from user, if given. If not specified,
+   *  use the default from configuration structure. If missing
+   *  from there, then use the precompiled default.
+   */
+  tmpport = port = aconf->port;
+  if (parc > 2 && !BadPtr(parv[2])) {
+    if ((port = atoi(parv[2])) == 0) {
+      if (MyUser(sptr))
+        sendto_one(sptr, ":%s NOTICE %s :Connect: Invalid port number", me.name, parv[0]);
+      else
+        sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
+                   NumServ(&me), NumNick(sptr));
+      return 0;
+    }
+  }
+  else if (port == 0 && (port = PORTNUM) == 0) {
+    if (MyUser(sptr))
+      sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
+                 me.name, parv[0]);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :Connect: missing port number",
+                 NumServ(&me), NumNick(sptr));
+    return 0;
+  }
+
+  /*
+   * Evaluate connection rules...  If no rules found, allow the
+   * connect.   Otherwise stop with the first true rule (ie: rules
+   * are ored together.  Oper connects are effected only by D
+   * lines (CRULEALL) not d lines (CRULEAUTO).
+   */
+  for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
+    if ((CONF_CRULEALL == cconf->status) &&
+        (0 == match(cconf->host, aconf->name))) {
+      if (crule_eval(cconf->passwd)) {
+        if (MyUser(sptr))
+          sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
+                     me.name, parv[0], cconf->name);
+        else
+          sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
+                     NumServ(&me), NumNick(sptr), cconf->name);
+        return 0;
+      }
+    }
+  }
+
+  /*
+   * Notify all operators about remote connect requests
+   */
+  if (!IsAnOper(cptr)) {
+    sendto_ops_butone(0, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
+                      me.name, parv[1], parv[2] ? parv[2] : "",
+                      get_client_name(sptr, HIDE_IP));
+    ircd_log(L_INFO, "CONNECT From %s : %s %d",
+             parv[0], parv[1], parv[2] ? parv[2] : "");
+  }
+  aconf->port = port;
+  if (connect_server(aconf, sptr, 0)) {
+    if (MyUser(sptr))
+      sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s.",
+                 me.name, parv[0], aconf->name);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :*** Connecting to %s.",
+                 NumServ(&me), NumNick(sptr), aconf->name);
+  }
+  else {
+    if (MyUser(sptr))
+      sendto_one(sptr, ":%s NOTICE %s :*** Connection to %s failed",
+                 me.name, parv[0], aconf->name);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :*** Connection to %s failed",
+                 NumServ(&me), NumNick(sptr), aconf->name);
+  }
+  aconf->port = tmpport;
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_cprivmsg.c b/ircd/m_cprivmsg.c
new file mode 100644 (file)
index 0000000..19b986f
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_cprivmsg.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "s_user.h"
+
+#include <assert.h>
+
+/*
+ * m_cprivmsg - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick
+ * parv[2] = #channel
+ * parv[3] = Private message text
+ */
+int m_cprivmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 4 || EmptyString(parv[3]))
+    return need_more_params(sptr, "CPRIVMSG");
+
+  return whisper(sptr, parv[1], parv[2], parv[3], 0);
+}
+
+/*
+ * m_cnotice - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick
+ * parv[2] = #channel
+ * parv[3] = Private message text
+ */
+int m_cnotice(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 4 || EmptyString(parv[3]))
+    return need_more_params(sptr, "CNOTICE");
+
+  return whisper(sptr, parv[1], parv[2], parv[3], 1);
+}
+
+
diff --git a/ircd/m_create.c b/ircd/m_create.c
new file mode 100644 (file)
index 0000000..05bacc8
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_create.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_create - generic message handler
+ */
+int m_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+/*
+ * ms_create - server message handler
+ */
+int ms_create(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char            cbuf[BUFSIZE];  /* Buffer for list with channels
+                                     that `sptr' really creates */
+  time_t          chanTS;         /* Creation time for all channels
+                                     in the comma seperated list */
+  char*           p;
+  char*           name;
+  struct Channel* chptr;
+  int             badop;
+
+  if (IsServer(sptr)) {
+    /* PROTOCOL WARNING */
+    /* bail, don't core */
+    return 0;
+  }
+  /* sanity checks: Only accept CREATE messages from servers */
+  if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
+    return 0;
+
+  chanTS = atoi(parv[2]);
+
+  /* A create that didn't appear during a burst has that servers idea of
+   * the current time.  Use it for lag calculations.
+   */
+  if (!IsBurstOrBurstAck(sptr) && 0 != chanTS && MAGIC_REMOTE_JOIN_TS != chanTS)
+    sptr->user->server->serv->lag = TStime() - chanTS;
+
+  *cbuf = '\0';                 /* Start with empty buffer */
+
+  /* For each channel in the comma seperated list: */
+  for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, 0, ","))
+  {
+    badop = 0;                  /* Default is to accept the op */
+    if ((chptr = FindChannel(name)))
+    {
+      name = chptr->chname;
+      if (TStime() - chanTS > TS_LAG_TIME)
+      {
+        /* A bounce would not be accepted anyway - if we get here something
+           is wrong with the TS clock syncing (or we have more then
+           TS_LAG_TIME lag, or an admin is hacking */
+        badop = 2;
+        /* This causes a HACK notice on all upstream servers: */
+        sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s 0", NumServ(&me), name, NumNick(sptr));
+        /* This causes a WALLOPS on all downstream servers and a notice to our
+           own opers: */
+        parv[1] = name;         /* Corrupt parv[1], it is not used anymore anyway */
+        send_hack_notice(cptr, sptr, parc, parv, badop, 2);
+      }
+      else if (chptr->creationtime && chanTS > chptr->creationtime &&
+          chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
+      {
+        /* We (try) to bounce the mode, because the CREATE is used on an older
+           channel, probably a net.ride */
+        badop = 1;
+        /* Send a deop upstream: */
+        sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s " TIME_T_FMT, NumServ(&me),
+                   name, NumNick(sptr), chptr->creationtime);
+      }
+    }
+    else                        /* Channel doesn't exist: create it */
+      chptr = get_channel(sptr, name, CGT_CREATE);
+
+    /* Add and mark ops */
+    add_user_to_channel(chptr, sptr,
+        (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
+
+    /* Send user join to the local clients (if any) */
+    sendto_channel_butserv(chptr, sptr, ":%s " MSG_JOIN " :%s", parv[0], name);
+
+    if (badop)                  /* handle badop: convert CREATE into JOIN */
+      sendto_serv_butone(cptr, "%s%s " TOK_JOIN " %s " TIME_T_FMT,
+          NumNick(sptr), name, chptr->creationtime);
+    else
+    {
+      /* Send the op to local clients:
+         (if any; extremely unlikely, but it CAN happen) */
+      if (!IsModelessChannel(name))
+        sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
+            sptr->user->server->name, name, parv[0]);
+
+      /* Set/correct TS and add the channel to the
+         buffer for accepted channels: */
+      chptr->creationtime = chanTS;
+      if (*cbuf)
+        strcat(cbuf, ",");
+      strcat(cbuf, name);
+    }
+  }
+
+  if (*cbuf)                    /* Any channel accepted with ops ? */
+  {
+    sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
+        NumNick(sptr), cbuf, chanTS);
+  }
+
+  return 0;
+}
+
+#if 0
+/*
+ * m_create
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel names
+ * parv[2] = channel time stamp
+ */
+int m_create(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char            cbuf[BUFSIZE];  /* Buffer for list with channels
+                                     that `sptr' really creates */
+  time_t          chanTS;         /* Creation time for all channels
+                                     in the comma seperated list */
+  char*           p;
+  char*           name;
+  struct Channel* chptr;
+  int             badop;
+
+  /* sanity checks: Only accept CREATE messages from servers */
+  if (!IsServer(cptr) || parc < 3 || *parv[2] == '\0')
+    return 0;
+
+  chanTS = atoi(parv[2]);
+
+  /* A create that didn't appear during a burst has that servers idea of
+   * the current time.  Use it for lag calculations.
+   */
+  if (!IsBurstOrBurstAck(sptr) && 0 != chanTS && MAGIC_REMOTE_JOIN_TS != chanTS)
+    sptr->user->server->serv->lag = TStime() - chanTS;
+
+  *cbuf = '\0';                 /* Start with empty buffer */
+
+  /* For each channel in the comma seperated list: */
+  for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, 0, ","))
+  {
+    badop = 0;                  /* Default is to accept the op */
+    if ((chptr = FindChannel(name)))
+    {
+      name = chptr->chname;
+      if (TStime() - chanTS > TS_LAG_TIME)
+      {
+        /* A bounce would not be accepted anyway - if we get here something
+           is wrong with the TS clock syncing (or we have more then
+           TS_LAG_TIME lag, or an admin is hacking */
+        badop = 2;
+        /* This causes a HACK notice on all upstream servers: */
+        sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s 0", NumServ(&me), name, NumNick(sptr));
+        /* This causes a WALLOPS on all downstream servers and a notice to our
+           own opers: */
+        parv[1] = name;         /* Corrupt parv[1], it is not used anymore anyway */
+        send_hack_notice(cptr, sptr, parc, parv, badop, 2);
+      }
+      else if (chptr->creationtime && chanTS > chptr->creationtime &&
+          chptr->creationtime != MAGIC_REMOTE_JOIN_TS)
+      {
+        /* We (try) to bounce the mode, because the CREATE is used on an older
+           channel, probably a net.ride */
+        badop = 1;
+        /* Send a deop upstream: */
+        sendto_one(cptr, "%s " TOK_MODE " %s -o %s%s " TIME_T_FMT, NumServ(&me),
+                   name, NumNick(sptr), chptr->creationtime);
+      }
+    }
+    else                        /* Channel doesn't exist: create it */
+      chptr = get_channel(sptr, name, CGT_CREATE);
+
+    /* Add and mark ops */
+    add_user_to_channel(chptr, sptr,
+        (badop || IsModelessChannel(name)) ? CHFL_DEOPPED : CHFL_CHANOP);
+
+    /* Send user join to the local clients (if any) */
+    sendto_channel_butserv(chptr, sptr, ":%s " MSG_JOIN " :%s", parv[0], name);
+
+    if (badop)                  /* handle badop: convert CREATE into JOIN */
+      sendto_serv_butone(cptr, "%s%s " TOK_JOIN " %s " TIME_T_FMT,
+          NumNick(sptr), name, chptr->creationtime);
+    else
+    {
+      /* Send the op to local clients:
+         (if any; extremely unlikely, but it CAN happen) */
+      if (!IsModelessChannel(name))
+        sendto_channel_butserv(chptr, sptr, ":%s MODE %s +o %s",
+            sptr->user->server->name, name, parv[0]);
+
+      /* Set/correct TS and add the channel to the
+         buffer for accepted channels: */
+      chptr->creationtime = chanTS;
+      if (*cbuf)
+        strcat(cbuf, ",");
+      strcat(cbuf, name);
+    }
+  }
+
+  if (*cbuf)                    /* Any channel accepted with ops ? */
+  {
+    sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
+        NumNick(sptr), cbuf, chanTS);
+  }
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_defaults.c b/ircd/m_defaults.c
new file mode 100644 (file)
index 0000000..67fcc1b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_proto.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "supported.h"
+#include "version.h"
+
+#include <assert.h>
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+int m_not_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return send_error_to_client(cptr, ERR_NOPRIVILEGES);
+}
+
+int m_unregistered(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  sendto_one(cptr, ":%s %d * %s :Register first.",
+             me.name, ERR_NOTREGISTERED, parv[0]);
+  return 0;
+}
+
+int m_registered(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return send_error_to_client(sptr, ERR_ALREADYREGISTRED);
+}
+
+int m_ignore(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+int m_unsupported(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+#if 0
+  sendto_one(cptr, ":%s %d * %s :Unsupported command",
+             me.name, ERR_UNSUPPORTED, parv[0]);
+#endif
+  return 0;
+}
diff --git a/ircd/m_destruct.c b/ircd/m_destruct.c
new file mode 100644 (file)
index 0000000..fabc93e
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_destruct.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * ms_destruct - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel channelname
+ * parv[2] = channel time stamp
+ *
+ * This function does nothing, it does passes DESTRUCT to the other servers.
+ * In the future we will start to use this message.
+ *
+ */
+int ms_destruct(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t chanTS;                /* Creation time of the channel */
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if (parc < 3 || EmptyString(parv[2]))
+    return 0;
+
+    /* sanity checks: Only accept DESTRUCT messages from servers */
+  if (!IsServer(sptr))
+    return 0;
+
+  /* Don't pass on DESTRUCT messages for channels that exist */
+  if (FindChannel(parv[1]))
+    return 0;
+
+  chanTS = atoi(parv[2]);
+
+  /* Pass on DESTRUCT message */
+  sendto_highprot_butone(cptr, 10, "%s " TOK_DESTRUCT " %s " TIME_T_FMT,
+                         NumServ(sptr), parv[1], chanTS);
+
+  return 0;
+}
+
+#if 0 
+/*
+ * m_destruct
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel channelname
+ * parv[2] = channel time stamp
+ *
+ * This function does nothing, it does passes DESTRUCT to the other servers.
+ * In the future we will start to use this message.
+ *
+ */
+int m_destruct(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  time_t chanTS;                /* Creation time of the channel */
+
+  if (parc < 3 || *parv[2] == '\0')
+    return 0;
+
+#ifdef GODMODE
+  /* Allow DESTRUCT from user */
+  if (MyUser(sptr))
+    sptr = &me;
+  else
+#endif
+
+    /* sanity checks: Only accept DESTRUCT messages from servers */
+  if (!IsServer(sptr))
+    return 0;
+
+  /* Don't pass on DESTRUCT messages for channels that exist */
+  if (FindChannel(parv[1]))
+    return 0;
+
+  chanTS = atoi(parv[2]);
+
+  /* Pass on DESTRUCT message */
+  sendto_highprot_butone(cptr, 10, "%s DESTRUCT %s " TIME_T_FMT,
+      NumServ(sptr), parv[1], chanTS);
+
+  return 0;
+}
+#endif
diff --git a/ircd/m_desynch.c b/ircd/m_desynch.c
new file mode 100644 (file)
index 0000000..89b998c
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_desynch.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * ms_desynch - server message handler
+ *
+ * Writes to all +g users; for sending wall type debugging/anti-hack info.
+ * Added 23 Apr 1998  --Run
+ *
+ * parv[0] - sender prefix
+ * parv[parc-1] - message text
+ */
+int ms_desynch(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (IsServer(sptr) && parc >= 2)
+  {
+    int i;
+    struct Client *acptr;
+    /* Send message to local +g clients as if it were a wallops */
+    sprintf_irc(sendbuf, ":%s WALLOPS :%s", parv[0], parv[parc - 1]);
+    for (i = 0; i <= HighestFd; i++)
+      if ((acptr = LocalClientArray[i]) && !IsServer(acptr) && !IsMe(acptr) &&
+          SendDebug(acptr))
+        sendbufto_one(acptr);
+    /* Send message to remote +g clients */
+    sendto_g_serv_butone(cptr, "%s DESYNCH :%s", NumServ(sptr), parv[parc - 1]);
+  }
+  return 0;
+}
+
+#if 0
+/*
+ * m_desynch
+ *
+ * Writes to all +g users; for sending wall type debugging/anti-hack info.
+ * Added 23 Apr 1998  --Run
+ *
+ * parv[0] - sender prefix
+ * parv[parc-1] - message text
+ */
+int m_desynch(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  if (IsServer(sptr) && parc >= 2)
+  {
+    int i;
+    struct Client *acptr;
+    /* Send message to local +g clients as if it were a wallops */
+    sprintf_irc(sendbuf, ":%s WALLOPS :%s", parv[0], parv[parc - 1]);
+    for (i = 0; i <= HighestFd; i++)
+      if ((acptr = LocalClientArray[i]) && !IsServer(acptr) && !IsMe(acptr) &&
+          SendDebug(acptr))
+        sendbufto_one(acptr);
+    /* Send message to remote +g clients */
+    sendto_g_serv_butone(cptr, "%s DESYNCH :%s", NumServ(sptr), parv[parc - 1]);
+  }
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_die.c b/ircd/m_die.c
new file mode 100644 (file)
index 0000000..0459243
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_die.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "send.h"
+
+#include <assert.h>
+
+
+/*
+ * mo_die - oper message handler
+ */
+int mo_die(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+#if defined(OPER_DIE) || defined(LOCOP_DIE)
+  struct Client *acptr;
+  int i;
+
+#ifndef LOCOP_DIE
+  if (!MyUser(sptr) || !IsOper(sptr))
+#else
+#ifdef  OPER_DIE
+  if (!MyUser(sptr) || !IsAnOper(sptr))
+#else
+  if (!MyUser(sptr) || !IsLocOp(sptr))
+#endif
+#endif
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(acptr = LocalClientArray[i]))
+      continue;
+    if (IsUser(acptr))
+      sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s",
+                 me.name, acptr->name, get_client_name(sptr, HIDE_IP));
+    else if (IsServer(acptr))
+      sendto_one(acptr, ":%s ERROR :Terminated by %s",
+                 me.name, get_client_name(sptr, HIDE_IP));
+  }
+  server_die("received DIE");
+#endif /* defined(OPER_DIE) || defined(LOCOP_DIE) */
+  return 0;
+}
+
+  
+#if 0
+#if defined(OPER_DIE) || defined(LOCOP_DIE)
+/*
+ * m_die
+ */
+int m_die(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+  int i;
+
+#ifndef LOCOP_DIE
+  if (!MyUser(sptr) || !IsOper(sptr))
+#else
+#ifdef  OPER_DIE
+  if (!MyUser(sptr) || !IsAnOper(sptr))
+#else
+  if (!MyUser(sptr) || !IsLocOp(sptr))
+#endif
+#endif
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    if (!(acptr = LocalClientArray[i]))
+      continue;
+    if (IsUser(acptr))
+      sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s",
+                 me.name, acptr->name, get_client_name(sptr, HIDE_IP));
+    else if (IsServer(acptr))
+      sendto_one(acptr, ":%s ERROR :Terminated by %s",
+                 me.name, get_client_name(sptr, HIDE_IP));
+  }
+  server_die("received DIE");
+  return 0;
+}
+#endif
+#endif /* 0 */
+
diff --git a/ircd/m_endburst.c b/ircd/m_endburst.c
new file mode 100644 (file)
index 0000000..2426145
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_end_of_burst.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * ms_end_of_burst - server message handler
+ * - Added Xorath 6-14-96, rewritten by Run 24-7-96
+ * - and fixed by record and Kev 8/1/96
+ * - and really fixed by Run 15/8/96 :p
+ * This the last message in a net.burst.
+ * It clears a flag for the server sending the burst.
+ *
+ * parv[0] - sender prefix
+ */
+int ms_end_of_burst(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(0 != sptr);
+  if (!IsServer(sptr))
+    return 0;
+
+  sendto_op_mask(SNO_NETWORK, "Completed net.burst from %s.", sptr->name);
+  sendto_serv_butone(cptr, "%s EB", NumServ(sptr));
+  ClearBurst(sptr);
+  SetBurstAck(sptr);
+  if (MyConnect(sptr))
+    sendto_one(sptr, "%s EA", NumServ(&me));
+
+  return 0;
+}
+
+/*
+ * ms_end_of_burst_ack - server message handler
+ *
+ * This the acknowledge message of the `END_OF_BURST' message.
+ * It clears a flag for the server receiving the burst.
+ *
+ * parv[0] - sender prefix
+ */
+int ms_end_of_burst_ack(struct Client *cptr, struct Client *sptr, int parc, char **parv)
+{
+  if (!IsServer(sptr))
+    return 0;
+
+  sendto_op_mask(SNO_NETWORK, "%s acknowledged end of net.burst.", sptr->name);
+  sendto_serv_butone(cptr, "%s EA", NumServ(sptr));
+  ClearBurstAck(sptr);
+
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_end_of_burst  - Added Xorath 6-14-96, rewritten by Run 24-7-96
+ *                 - and fixed by record and Kev 8/1/96
+ *                 - and really fixed by Run 15/8/96 :p
+ * This the last message in a net.burst.
+ * It clears a flag for the server sending the burst.
+ *
+ * parv[0] - sender prefix
+ */
+int m_end_of_burst(struct Client *cptr, struct Client *sptr, int parc, char **parv)
+{
+  if (!IsServer(sptr))
+    return 0;
+
+  sendto_op_mask(SNO_NETWORK, "Completed net.burst from %s.", sptr->name);
+  sendto_serv_butone(cptr, "%s EB", NumServ(sptr));
+  ClearBurst(sptr);
+  SetBurstAck(sptr);
+  if (MyConnect(sptr))
+    sendto_one(sptr, "%s EA", NumServ(&me));
+
+  return 0;
+}
+/*
+ * m_end_of_burst_ack
+ *
+ * This the acknowledge message of the `END_OF_BURST' message.
+ * It clears a flag for the server receiving the burst.
+ *
+ * parv[0] - sender prefix
+ */
+int m_end_of_burst_ack(struct Client *cptr, struct Client *sptr, int parc, char **parv)
+{
+  if (!IsServer(sptr))
+    return 0;
+
+  sendto_op_mask(SNO_NETWORK, "%s acknowledged end of net.burst.", sptr->name);
+  sendto_serv_butone(cptr, "%s EA", NumServ(sptr));
+  ClearBurstAck(sptr);
+
+  return 0;
+}
+
+#endif /* 0 */
+
diff --git a/ircd/m_error.c b/ircd/m_error.c
new file mode 100644 (file)
index 0000000..f981a66
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_error.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * ms_error - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[parc-1] = text
+ */
+int ms_error(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *para;
+
+  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
+
+  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
+  /*
+   * Ignore error messages generated by normal user clients
+   * (because ill-behaving user clients would flood opers
+   * screen otherwise). Pass ERROR's from other sources to
+   * the local operator...
+   */
+  if (IsUser(cptr))
+    return 0;
+  if (IsUnknown(cptr))
+    return exit_client_msg(cptr, cptr, &me, "Register first");
+
+  if (cptr == sptr)
+    sendto_ops("ERROR :from %s -- %s", cptr->name, para);
+  else
+    sendto_ops("ERROR :from %s via %s -- %s", sptr->name, cptr->name, para);
+
+  if (sptr->serv)
+  {
+    MyFree(sptr->serv->last_error_msg);
+    DupString(sptr->serv->last_error_msg, para);
+  }
+
+  return 0;
+}
+
+/*
+ * mr_error - registration message handler
+ *
+ * parv[0] = sender prefix
+ * parv[parc-1] = text
+ */
+int mr_error(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *para;
+
+  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
+
+  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
+  /*
+   * Ignore error messages generated by normal user clients
+   * (because ill-behaving user clients would flood opers
+   * screen otherwise). Pass ERROR's from other sources to
+   * the local operator...
+   */
+  if (IsUser(cptr))
+    return 0;
+  if (IsUnknown(cptr))
+    return exit_client_msg(cptr, cptr, &me, "Register first");
+
+  if (cptr == sptr)
+    sendto_ops("ERROR :from %s -- %s", cptr->name, para);
+  else
+    sendto_ops("ERROR :from %s via %s -- %s", sptr->name, cptr->name, para);
+
+  if (sptr->serv)
+  {
+    MyFree(sptr->serv->last_error_msg);
+    DupString(sptr->serv->last_error_msg, para);
+  }
+
+  return 0;
+}
+
+#if 0
+/*
+ * m_error
+ *
+ * parv[0] = sender prefix
+ * parv[parc-1] = text
+ */
+int m_error(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *para;
+
+  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
+
+  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
+  /*
+   * Ignore error messages generated by normal user clients
+   * (because ill-behaving user clients would flood opers
+   * screen otherwise). Pass ERROR's from other sources to
+   * the local operator...
+   */
+  if (IsUser(cptr))
+    return 0;
+  if (IsUnknown(cptr))
+    return exit_client_msg(cptr, cptr, &me, "Register first");
+
+  if (cptr == sptr)
+    sendto_ops("ERROR :from %s -- %s", cptr->name, para);
+  else
+    sendto_ops("ERROR :from %s via %s -- %s", sptr->name, cptr->name, para);
+
+  if (sptr->serv)
+  {
+    MyFree(sptr->serv->last_error_msg);
+    DupString(sptr->serv->last_error_msg, para);
+  }
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_gline.c b/ircd/m_gline.c
new file mode 100644 (file)
index 0000000..aad3d0a
--- /dev/null
@@ -0,0 +1,1132 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_gline.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_misc.h"
+#include "send.h"
+#include "support.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * ms_gline - server message handler
+ *
+ * parv[0] = Send prefix
+ *
+ * From server:
+ *
+ * parv[1] = Target: server numeric
+ * parv[2] = [+|-]<G-line mask>
+ * parv[3] = Expiration offset
+ * parv[4] = Comment
+ *
+ * From client:
+ *
+ * parv[1] = [+|-]<G-line mask>
+ * parv[2] = Expiration offset
+ * parv[3] = Comment
+ *
+ */
+int ms_gline(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
+  struct Gline*  gline;
+  struct Gline*  prev;
+  char*          user;
+  char*          host;
+  int            active;
+  int            ip_mask;
+  int            gtype = 0;
+  time_t         expire = 0;
+
+  /*
+   * Remove expired G-lines
+   */
+  gline_remove_expired(TStime());
+#ifdef BADCHAN
+  /*
+   * Remove expired bad channels
+   */
+  bad_channel_remove_expired(TStime());
+#endif
+
+  if (IsServer(cptr)) {
+    if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
+      if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
+        return need_more_params(sptr, "GLINE");
+
+      if (*parv[2] == '-') /* add mode or delete mode? */
+        active = 0;
+      else
+        active = 1;
+
+      if (*parv[2] == '+' || *parv[2] == '-')
+        parv[2]++; /* step past mode indicator */
+
+      /*
+       * forward the message appropriately
+       */
+      if (0 == ircd_strcmp(parv[1], "*")) {
+        /*
+         * global!
+         */
+        sendto_serv_butone(cptr,
+                     active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
+                     NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
+      }
+      else if ((
+#if 1
+          /*
+           * REMOVE THIS after all servers upgraded to 2.10.01 and
+           * Uworld uses a numeric too
+           */
+          (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
+          (strlen(parv[1]) == 1 &&
+#endif
+          !(acptr = FindNServer(parv[1]))))
+        return 0;               /* no such server/user exists; forget it */
+      else
+#if 1
+/*
+ * REMOVE THIS after all servers upgraded to 2.10.01 and
+ * Uworld uses a numeric too
+ */
+      if (IsServer(acptr) || !MyConnect(acptr))
+#endif
+      {
+        /* single destination */
+        sendto_one(acptr,
+               active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
+               NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
+        return 0;               /* only the intended  destination
+                                   should add this gline */
+      }
+
+      if (!(host = strchr(parv[2], '@'))) {
+        /*
+         * convert user@host no @'s; assume username is '*'
+         */
+        user = "*";     
+        host = parv[2];
+      }
+      else {
+        user = parv[2];
+        *(host++) = '\0';       /* break up string at the '@' */
+      }
+      ip_mask = check_if_ipmask(host);  /* Store this boolean */
+#ifdef BADCHAN
+      if ('#' == *host || '&' == *host || '+' == *host)
+         gtype = 1;                /* BAD CHANNEL GLINE */
+#endif
+      for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
+           gline = gline->next)
+      {
+        if (0 == ircd_strcmp(gline->name, user) &&
+            0 == ircd_strcmp(gline->host, host))
+          break;
+        prev = gline;
+      }
+
+      if (!active && gline)
+      {
+        /*
+         * removing the gline, notify opers
+         */
+        sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
+            gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
+
+#ifdef GPATH
+       write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
+           TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
+            gline->host);
+#endif /* GPATH */
+
+        free_gline(gline, prev);        /* remove the gline */
+      }
+      else if (active)
+      {                         /* must be adding a gline */
+        expire = atoi(parv[3]) + TStime();      /* expire time? */
+        if (gline && gline->expire < expire)
+        {                       /* new expire time? */
+          /* yes, notify the opers */
+          sendto_op_mask(SNO_GLINE,
+             "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
+             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
+             expire);
+#ifdef GPATH
+          write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
+              "on %s for %s@%s to " TIME_T_FMT "\n",
+              TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
+              gline->name, gline->host, expire);
+#endif /* GPATH */
+
+          gline->expire = expire;       /* reset the expire time */
+        }
+        else if (!gline)
+        {                       /* create gline */
+          for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
+            if (!mmatch(gline->name, user) &&
+                (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
+                !mmatch(gline->host, host))
+              return 0;         /* found an existing G-line that matches */
+
+          /* add the line: */
+          add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
+        }
+      }
+    }
+  }
+  else if (parc < 2 || *parv[1] == '\0')
+  {
+    /* Not enough args and a user; list glines */
+    for (gline = GlobalGlineList; gline; gline = gline->next)
+      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
+          gline->name, gline->host, gline->expire, gline->reason,
+          GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
+          " (Inactive)");
+    sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
+  }
+  else
+  {
+    int priv;
+
+#ifdef LOCOP_LGLINE
+    priv = IsAnOper(cptr);
+#else
+    priv = IsOper(cptr);
+#endif
+
+    if (priv)
+    {                           /* non-oper not permitted to change things */
+      if (*parv[1] == '-')
+      {                         /* oper wants to deactivate the gline */
+        active = 0;
+        parv[1]++;
+      }
+      else if (*parv[1] == '+')
+      {                         /* oper wants to activate inactive gline */
+        active = 1;
+        parv[1]++;
+      }
+      else
+        active = -1;
+
+      if (parc > 2)
+        expire = atoi(parv[2]) + TStime();      /* oper wants to reset
+                                                   expire TS */
+    }
+    else
+      active = -1;
+
+    if (!(host = strchr(parv[1], '@')))
+    {
+      user = "*";               /* no @'s; assume username is '*' */
+      host = parv[1];
+    }
+    else
+    {
+      user = parv[1];
+      *(host++) = '\0';         /* break up string at the '@' */
+    }
+    ip_mask = check_if_ipmask(host);    /* Store this boolean */
+#ifdef BADCHAN
+    if ('#' == *host || '&' == *host || '+' == *host)
+#ifndef LOCAL_BADCHAN
+     return 0;
+#else
+     gtype = 1;  /* BAD CHANNEL */
+#endif
+#endif
+
+    for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
+         gline = gline->next)
+    {
+      if (!mmatch(gline->name, user) &&
+          (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
+          !mmatch(gline->host, host))
+        break;
+      prev = gline;
+    }
+
+    if (!gline)
+    {
+#ifdef OPER_LGLINE
+      if (priv && active && expire > CurrentTime)
+      {
+        /* Add local G-line */
+        if (parc < 4 || !strchr(parv[3], ' '))
+          return need_more_params(sptr, "GLINE");
+
+        add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
+      }
+      else
+#endif
+        sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
+            host);
+
+      return 0;
+    }
+
+    if (expire <= gline->expire)
+      expire = 0;
+
+    if ((active == -1 ||
+        (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
+        expire == 0)
+    {
+      /* oper wants a list of one gline only */
+      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
+          gline->host, gline->expire, gline->reason,
+          GlineIsActive(gline) ? "" : " (Inactive)");
+      sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
+      return 0;
+    }
+
+    if (active != -1 &&
+        (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
+    {
+      if (active)               /* reset activation on gline */
+        SetActive(gline);
+#ifdef OPER_LGLINE
+      else if (GlineIsLocal(gline))
+      {
+        /* Remove local G-line */
+        sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
+            parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
+#ifdef GPATH
+        write_log(GPATH, "# " TIME_T_FMT
+            " %s!%s@%s removed local %s for %s@%s\n",
+            TStime(), parv[0], cptr->user->username, cptr->user->host,
+            gtype ? "BADCHAN" : "GLINE",
+            gline->name, gline->host);
+#endif /* GPATH */
+        free_gline(gline, prev);        /* remove the gline */
+        return 0;
+      }
+#endif
+      else
+        ClearActive(gline);
+    }
+    else
+      active = -1;              /* for later sendto_ops and logging functions */
+
+    if (expire)
+      gline->expire = expire;   /* reset expiration time */
+
+    /* inform the operators what's up */
+    if (active != -1)
+    {                           /* changing the activation */
+       sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
+          "%s %sactivating %s for %s@%s and "
+          "resetting expiration time to " TIME_T_FMT,
+          parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
+          gline->name, gline->host, gline->expire);
+#ifdef GPATH
+      write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
+          "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
+          "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
+          TStime(), parv[0], cptr->user->username, cptr->user->host,
+          active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
+          gline->host, gline->expire);
+#endif /* GPATH */
+
+    }
+    else if (expire)
+    {                           /* changing only the expiration */
+      sendto_op_mask(SNO_GLINE,
+          "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
+          parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
+          gline->expire);
+#ifdef GPATH
+      write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
+          "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
+          cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
+          gline->name, gline->host, gline->expire);
+#endif /* GPATH */
+    }
+  }
+  return 0;
+}
+
+/*
+ * mo_gline - oper message handler
+ *
+ * parv[0] = Send prefix
+ *
+ * From server:
+ *
+ * parv[1] = Target: server numeric
+ * parv[2] = [+|-]<G-line mask>
+ * parv[3] = Expiration offset
+ * parv[4] = Comment
+ *
+ * From client:
+ *
+ * parv[1] = [+|-]<G-line mask>
+ * parv[2] = Expiration offset
+ * parv[3] = Comment
+ *
+ */
+int mo_gline(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
+  struct Gline*  gline;
+  struct Gline*  prev;
+  char*          user;
+  char*          host;
+  int            active;
+  int            ip_mask;
+  int            gtype = 0;
+  time_t         expire = 0;
+
+  /*
+   * Remove expired G-lines
+   */
+  gline_remove_expired(TStime());
+#ifdef BADCHAN
+  /*
+   * Remove expired bad channels
+   */
+  bad_channel_remove_expired(TStime());
+#endif
+
+  if (IsServer(cptr)) {
+    if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
+      if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
+        return need_more_params(sptr, "GLINE");
+
+      if (*parv[2] == '-') /* add mode or delete mode? */
+        active = 0;
+      else
+        active = 1;
+
+      if (*parv[2] == '+' || *parv[2] == '-')
+        parv[2]++; /* step past mode indicator */
+
+      /*
+       * forward the message appropriately
+       */
+      if (0 == ircd_strcmp(parv[1], "*")) {
+        /*
+         * global!
+         */
+        sendto_serv_butone(cptr,
+                     active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
+                     NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
+      }
+      else if ((
+#if 1
+          /*
+           * REMOVE THIS after all servers upgraded to 2.10.01 and
+           * Uworld uses a numeric too
+           */
+          (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
+          (strlen(parv[1]) == 1 &&
+#endif
+          !(acptr = FindNServer(parv[1]))))
+        return 0;               /* no such server/user exists; forget it */
+      else
+#if 1
+/*
+ * REMOVE THIS after all servers upgraded to 2.10.01 and
+ * Uworld uses a numeric too
+ */
+      if (IsServer(acptr) || !MyConnect(acptr))
+#endif
+      {
+        /* single destination */
+        sendto_one(acptr,
+               active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
+               NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
+        return 0;               /* only the intended  destination
+                                   should add this gline */
+      }
+
+      if (!(host = strchr(parv[2], '@'))) {
+        /*
+         * convert user@host no @'s; assume username is '*'
+         */
+        user = "*";     
+        host = parv[2];
+      }
+      else {
+        user = parv[2];
+        *(host++) = '\0';       /* break up string at the '@' */
+      }
+      ip_mask = check_if_ipmask(host);  /* Store this boolean */
+#ifdef BADCHAN
+      if ('#' == *host || '&' == *host || '+' == *host)
+         gtype = 1;                /* BAD CHANNEL GLINE */
+#endif
+      for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
+           gline = gline->next)
+      {
+        if (0 == ircd_strcmp(gline->name, user) &&
+            0 == ircd_strcmp(gline->host, host))
+          break;
+        prev = gline;
+      }
+
+      if (!active && gline)
+      {
+        /*
+         * removing the gline, notify opers
+         */
+        sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
+            gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
+
+#ifdef GPATH
+       write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
+           TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
+            gline->host);
+#endif /* GPATH */
+
+        free_gline(gline, prev);        /* remove the gline */
+      }
+      else if (active)
+      {                         /* must be adding a gline */
+        expire = atoi(parv[3]) + TStime();      /* expire time? */
+        if (gline && gline->expire < expire)
+        {                       /* new expire time? */
+          /* yes, notify the opers */
+          sendto_op_mask(SNO_GLINE,
+             "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
+             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
+             expire);
+#ifdef GPATH
+          write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
+              "on %s for %s@%s to " TIME_T_FMT "\n",
+              TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
+              gline->name, gline->host, expire);
+#endif /* GPATH */
+
+          gline->expire = expire;       /* reset the expire time */
+        }
+        else if (!gline)
+        {                       /* create gline */
+          for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
+            if (!mmatch(gline->name, user) &&
+                (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
+                !mmatch(gline->host, host))
+              return 0;         /* found an existing G-line that matches */
+
+          /* add the line: */
+          add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
+        }
+      }
+    }
+  }
+  else if (parc < 2 || *parv[1] == '\0')
+  {
+    /* Not enough args and a user; list glines */
+    for (gline = GlobalGlineList; gline; gline = gline->next)
+      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
+          gline->name, gline->host, gline->expire, gline->reason,
+          GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
+          " (Inactive)");
+    sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
+  }
+  else
+  {
+    int priv;
+
+#ifdef LOCOP_LGLINE
+    priv = IsAnOper(cptr);
+#else
+    priv = IsOper(cptr);
+#endif
+
+    if (priv)
+    {                           /* non-oper not permitted to change things */
+      if (*parv[1] == '-')
+      {                         /* oper wants to deactivate the gline */
+        active = 0;
+        parv[1]++;
+      }
+      else if (*parv[1] == '+')
+      {                         /* oper wants to activate inactive gline */
+        active = 1;
+        parv[1]++;
+      }
+      else
+        active = -1;
+
+      if (parc > 2)
+        expire = atoi(parv[2]) + TStime();      /* oper wants to reset
+                                                   expire TS */
+    }
+    else
+      active = -1;
+
+    if (!(host = strchr(parv[1], '@')))
+    {
+      user = "*";               /* no @'s; assume username is '*' */
+      host = parv[1];
+    }
+    else
+    {
+      user = parv[1];
+      *(host++) = '\0';         /* break up string at the '@' */
+    }
+    ip_mask = check_if_ipmask(host);    /* Store this boolean */
+#ifdef BADCHAN
+    if ('#' == *host || '&' == *host || '+' == *host)
+#ifndef LOCAL_BADCHAN
+     return 0;
+#else
+     gtype = 1;  /* BAD CHANNEL */
+#endif
+#endif
+
+    for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
+         gline = gline->next)
+    {
+      if (!mmatch(gline->name, user) &&
+          (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
+          !mmatch(gline->host, host))
+        break;
+      prev = gline;
+    }
+
+    if (!gline)
+    {
+#ifdef OPER_LGLINE
+      if (priv && active && expire > CurrentTime)
+      {
+        /* Add local G-line */
+        if (parc < 4 || !strchr(parv[3], ' '))
+          return need_more_params(sptr, "GLINE");
+
+        add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
+      }
+      else
+#endif
+        sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
+            host);
+
+      return 0;
+    }
+
+    if (expire <= gline->expire)
+      expire = 0;
+
+    if ((active == -1 ||
+        (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
+        expire == 0)
+    {
+      /* oper wants a list of one gline only */
+      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
+          gline->host, gline->expire, gline->reason,
+          GlineIsActive(gline) ? "" : " (Inactive)");
+      sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
+      return 0;
+    }
+
+    if (active != -1 &&
+        (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
+    {
+      if (active)               /* reset activation on gline */
+        SetActive(gline);
+#ifdef OPER_LGLINE
+      else if (GlineIsLocal(gline))
+      {
+        /* Remove local G-line */
+        sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
+            parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
+#ifdef GPATH
+        write_log(GPATH, "# " TIME_T_FMT
+            " %s!%s@%s removed local %s for %s@%s\n",
+            TStime(), parv[0], cptr->user->username, cptr->user->host,
+            gtype ? "BADCHAN" : "GLINE",
+            gline->name, gline->host);
+#endif /* GPATH */
+        free_gline(gline, prev);        /* remove the gline */
+        return 0;
+      }
+#endif
+      else
+        ClearActive(gline);
+    }
+    else
+      active = -1;              /* for later sendto_ops and logging functions */
+
+    if (expire)
+      gline->expire = expire;   /* reset expiration time */
+
+    /* inform the operators what's up */
+    if (active != -1)
+    {                           /* changing the activation */
+       sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
+          "%s %sactivating %s for %s@%s and "
+          "resetting expiration time to " TIME_T_FMT,
+          parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
+          gline->name, gline->host, gline->expire);
+#ifdef GPATH
+      write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
+          "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
+          "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
+          TStime(), parv[0], cptr->user->username, cptr->user->host,
+          active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
+          gline->host, gline->expire);
+#endif /* GPATH */
+
+    }
+    else if (expire)
+    {                           /* changing only the expiration */
+      sendto_op_mask(SNO_GLINE,
+          "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
+          parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
+          gline->expire);
+#ifdef GPATH
+      write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
+          "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
+          cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
+          gline->name, gline->host, gline->expire);
+#endif /* GPATH */
+    }
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_gline
+ *
+ * parv[0] = Send prefix
+ *
+ * From server:
+ *
+ * parv[1] = Target: server numeric
+ * parv[2] = [+|-]<G-line mask>
+ * parv[3] = Expiration offset
+ * parv[4] = Comment
+ *
+ * From client:
+ *
+ * parv[1] = [+|-]<G-line mask>
+ * parv[2] = Expiration offset
+ * parv[3] = Comment
+ *
+ */
+int m_gline(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client* acptr = 0;  /* Init. to avoid compiler warning. */
+  struct Gline*  gline;
+  struct Gline*  prev;
+  char*          user;
+  char*          host;
+  int            active;
+  int            ip_mask;
+  int            gtype = 0;
+  time_t         expire = 0;
+
+  /*
+   * Remove expired G-lines
+   */
+  gline_remove_expired(TStime());
+#ifdef BADCHAN
+  /*
+   * Remove expired bad channels
+   */
+  bad_channel_remove_expired(TStime());
+#endif
+
+  if (IsServer(cptr)) {
+    if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD)) {
+      if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
+        return need_more_params(sptr, "GLINE");
+
+      if (*parv[2] == '-') /* add mode or delete mode? */
+        active = 0;
+      else
+        active = 1;
+
+      if (*parv[2] == '+' || *parv[2] == '-')
+        parv[2]++; /* step past mode indicator */
+
+      /*
+       * forward the message appropriately
+       */
+      if (0 == ircd_strcmp(parv[1], "*")) {
+        /*
+         * global!
+         */
+        sendto_serv_butone(cptr,
+                     active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
+                     NumServ(cptr), parv[1], parv[2], parv[3], parv[4]);
+      }
+      else if ((
+#if 1
+          /*
+           * REMOVE THIS after all servers upgraded to 2.10.01 and
+           * Uworld uses a numeric too
+           */
+          (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
+          (strlen(parv[1]) == 1 &&
+#endif
+          !(acptr = FindNServer(parv[1]))))
+        return 0;               /* no such server/user exists; forget it */
+      else
+#if 1
+/*
+ * REMOVE THIS after all servers upgraded to 2.10.01 and
+ * Uworld uses a numeric too
+ */
+      if (IsServer(acptr) || !MyConnect(acptr))
+#endif
+      {
+        /* single destination */
+        sendto_one(acptr,
+               active ? "%s " TOK_GLINE " %s +%s %s :%s" : "%s " TOK_GLINE " %s -%s",
+               NumServ(sptr), parv[1], parv[2], parv[3], parv[4]);
+        return 0;               /* only the intended  destination
+                                   should add this gline */
+      }
+
+      if (!(host = strchr(parv[2], '@'))) {
+        /*
+         * convert user@host no @'s; assume username is '*'
+         */
+        user = "*";     
+        host = parv[2];
+      }
+      else {
+        user = parv[2];
+        *(host++) = '\0';       /* break up string at the '@' */
+      }
+      ip_mask = check_if_ipmask(host);  /* Store this boolean */
+#ifdef BADCHAN
+      if ('#' == *host || '&' == *host || '+' == *host)
+         gtype = 1;                /* BAD CHANNEL GLINE */
+#endif
+      for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
+           gline = gline->next)
+      {
+        if (0 == ircd_strcmp(gline->name, user) &&
+            0 == ircd_strcmp(gline->host, host))
+          break;
+        prev = gline;
+      }
+
+      if (!active && gline)
+      {
+        /*
+         * removing the gline, notify opers
+         */
+        sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
+            gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
+
+#ifdef GPATH
+       write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
+           TStime(), parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, 
+            gline->host);
+#endif /* GPATH */
+
+        free_gline(gline, prev);        /* remove the gline */
+      }
+      else if (active)
+      {                         /* must be adding a gline */
+        expire = atoi(parv[3]) + TStime();      /* expire time? */
+        if (gline && gline->expire < expire)
+        {                       /* new expire time? */
+          /* yes, notify the opers */
+          sendto_op_mask(SNO_GLINE,
+             "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
+             parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
+             expire);
+#ifdef GPATH
+          write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
+              "on %s for %s@%s to " TIME_T_FMT "\n",
+              TStime(), parv[0], gtype ? "BADCHAN" : "GLINE",
+              gline->name, gline->host, expire);
+#endif /* GPATH */
+
+          gline->expire = expire;       /* reset the expire time */
+        }
+        else if (!gline)
+        {                       /* create gline */
+          for (gline = (gtype) ? BadChanGlineList : GlobalGlineList; gline; gline = gline->next)
+            if (!mmatch(gline->name, user) &&
+                (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
+                !mmatch(gline->host, host))
+              return 0;         /* found an existing G-line that matches */
+
+          /* add the line: */
+          add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
+        }
+      }
+    }
+  }
+  else if (parc < 2 || *parv[1] == '\0')
+  {
+    /* Not enough args and a user; list glines */
+    for (gline = GlobalGlineList; gline; gline = gline->next)
+      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
+          gline->name, gline->host, gline->expire, gline->reason,
+          GlineIsActive(gline) ? (GlineIsLocal(gline) ? " (local)" : "") :
+          " (Inactive)");
+    sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
+  }
+  else
+  {
+    int priv;
+
+#ifdef LOCOP_LGLINE
+    priv = IsAnOper(cptr);
+#else
+    priv = IsOper(cptr);
+#endif
+
+    if (priv)
+    {                           /* non-oper not permitted to change things */
+      if (*parv[1] == '-')
+      {                         /* oper wants to deactivate the gline */
+        active = 0;
+        parv[1]++;
+      }
+      else if (*parv[1] == '+')
+      {                         /* oper wants to activate inactive gline */
+        active = 1;
+        parv[1]++;
+      }
+      else
+        active = -1;
+
+      if (parc > 2)
+        expire = atoi(parv[2]) + TStime();      /* oper wants to reset
+                                                   expire TS */
+    }
+    else
+      active = -1;
+
+    if (!(host = strchr(parv[1], '@')))
+    {
+      user = "*";               /* no @'s; assume username is '*' */
+      host = parv[1];
+    }
+    else
+    {
+      user = parv[1];
+      *(host++) = '\0';         /* break up string at the '@' */
+    }
+    ip_mask = check_if_ipmask(host);    /* Store this boolean */
+#ifdef BADCHAN
+    if ('#' == *host || '&' == *host || '+' == *host)
+#ifndef LOCAL_BADCHAN
+     return 0;
+#else
+     gtype = 1;  /* BAD CHANNEL */
+#endif
+#endif
+
+    for (gline = (gtype) ? BadChanGlineList : GlobalGlineList, prev = 0; gline;
+         gline = gline->next)
+    {
+      if (!mmatch(gline->name, user) &&
+          (ip_mask ? GlineIsIpMask(gline) : !GlineIsIpMask(gline)) &&
+          !mmatch(gline->host, host))
+        break;
+      prev = gline;
+    }
+
+    if (!gline)
+    {
+#ifdef OPER_LGLINE
+      if (priv && active && expire > CurrentTime)
+      {
+        /* Add local G-line */
+        if (parc < 4 || !strchr(parv[3], ' '))
+          return need_more_params(sptr, "GLINE");
+
+        add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
+      }
+      else
+#endif
+        sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
+            host);
+
+      return 0;
+    }
+
+    if (expire <= gline->expire)
+      expire = 0;
+
+    if ((active == -1 ||
+        (active ? GlineIsActive(gline) : !GlineIsActive(gline))) &&
+        expire == 0)
+    {
+      /* oper wants a list of one gline only */
+      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], gline->name,
+          gline->host, gline->expire, gline->reason,
+          GlineIsActive(gline) ? "" : " (Inactive)");
+      sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
+      return 0;
+    }
+
+    if (active != -1 &&
+        (active ? !GlineIsActive(gline) : GlineIsActive(gline)))
+    {
+      if (active)               /* reset activation on gline */
+        SetActive(gline);
+#ifdef OPER_LGLINE
+      else if (GlineIsLocal(gline))
+      {
+        /* Remove local G-line */
+        sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
+            parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host);
+#ifdef GPATH
+        write_log(GPATH, "# " TIME_T_FMT
+            " %s!%s@%s removed local %s for %s@%s\n",
+            TStime(), parv[0], cptr->user->username, cptr->user->host,
+            gtype ? "BADCHAN" : "GLINE",
+            gline->name, gline->host);
+#endif /* GPATH */
+        free_gline(gline, prev);        /* remove the gline */
+        return 0;
+      }
+#endif
+      else
+        ClearActive(gline);
+    }
+    else
+      active = -1;              /* for later sendto_ops and logging functions */
+
+    if (expire)
+      gline->expire = expire;   /* reset expiration time */
+
+    /* inform the operators what's up */
+    if (active != -1)
+    {                           /* changing the activation */
+       sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
+          "%s %sactivating %s for %s@%s and "
+          "resetting expiration time to " TIME_T_FMT,
+          parv[0], active ? "re" : "de", gtype ? "BADCHAN" : "GLINE",
+          gline->name, gline->host, gline->expire);
+#ifdef GPATH
+      write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
+          "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
+          "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
+          TStime(), parv[0], cptr->user->username, cptr->user->host,
+          active ? "re" : "de", gtype ? "BADCHAN" : "GLINE", gline->name, 
+          gline->host, gline->expire);
+#endif /* GPATH */
+
+    }
+    else if (expire)
+    {                           /* changing only the expiration */
+      sendto_op_mask(SNO_GLINE,
+          "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
+          parv[0], gtype ? "BADCHAN" : "GLINE", gline->name, gline->host, 
+          gline->expire);
+#ifdef GPATH
+      write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
+          "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
+          cptr->user->username, cptr->user->host, gtype ? "BADCHAN" : "GLINE",
+          gline->name, gline->host, gline->expire);
+#endif /* GPATH */
+    }
+  }
+  return 0;
+}
+
+#endif /* 0 */
+
diff --git a/ircd/m_help.c b/ircd/m_help.c
new file mode 100644 (file)
index 0000000..460c1ca
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_help.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_help - generic message handler
+ */
+int m_help(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int i;
+
+  for (i = 0; msgtab[i].cmd; i++)
+    sendto_one(sptr, ":%s NOTICE %s :%s", me.name, parv[0], msgtab[i].cmd);
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_help
+ *
+ * parv[0] = sender prefix
+ */
+int m_help(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  int i;
+
+  for (i = 0; msgtab[i].cmd; i++)
+    sendto_one(sptr, ":%s NOTICE %s :%s", me.name, parv[0], msgtab[i].cmd);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_info.c b/ircd/m_info.c
new file mode 100644 (file)
index 0000000..a81e623
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_info.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "version.h"
+
+#include <assert.h>
+
+/*
+ * m_info - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char **text = infotext;
+
+  if (hunt_server(1, cptr, sptr, "%s%s " TOK_INFO " :%s", 1, parc, parv) == HUNTED_ISME)
+  {
+    while (text[2])
+    {
+      if (!IsOper(sptr))
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text);
+      text++;
+    }
+    if (IsOper(sptr))
+    {
+      while (*text)
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++);
+      sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
+    }
+    sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
+        me.name, RPL_INFO, parv[0], creation, generation);
+    sendto_one(sptr, ":%s %d %s :On-line since %s",
+        me.name, RPL_INFO, parv[0], myctime(me.firsttime));
+    sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+  }
+  return 0;
+}
+
+/*
+ * ms_info - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int ms_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char **text = infotext;
+
+  if (hunt_server(1, cptr, sptr, "%s%s " TOK_INFO " :%s", 1, parc, parv) == HUNTED_ISME)
+  {
+    while (text[2])
+    {
+      if (!IsOper(sptr))
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text);
+      text++;
+    }
+    if (IsOper(sptr))
+    {
+      while (*text)
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++);
+      sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
+    }
+    sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
+        me.name, RPL_INFO, parv[0], creation, generation);
+    sendto_one(sptr, ":%s %d %s :On-line since %s",
+        me.name, RPL_INFO, parv[0], myctime(me.firsttime));
+    sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+  }
+  return 0;
+}
+
+/*
+ * mo_info - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int mo_info(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char **text = infotext;
+
+  if (hunt_server(1, cptr, sptr, "%s%s " TOK_INFO " :%s", 1, parc, parv) == HUNTED_ISME)
+  {
+    while (text[2])
+    {
+      if (!IsOper(sptr))
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text);
+      text++;
+    }
+    if (IsOper(sptr))
+    {
+      while (*text)
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++);
+      sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
+    }
+    sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
+        me.name, RPL_INFO, parv[0], creation, generation);
+    sendto_one(sptr, ":%s %d %s :On-line since %s",
+        me.name, RPL_INFO, parv[0], myctime(me.firsttime));
+    sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+  }
+  return 0;
+}
+
+  
+#if 0
+/*
+ * m_info
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_info(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  const char **text = infotext;
+
+  if (hunt_server(1, cptr, sptr, "%s%s " TOK_INFO " :%s", 1, parc, parv) == HUNTED_ISME)
+  {
+    while (text[2])
+    {
+      if (!IsOper(sptr))
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text);
+      text++;
+    }
+    if (IsOper(sptr))
+    {
+      while (*text)
+        sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++);
+      sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
+    }
+    sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
+        me.name, RPL_INFO, parv[0], creation, generation);
+    sendto_one(sptr, ":%s %d %s :On-line since %s",
+        me.name, RPL_INFO, parv[0], myctime(me.firsttime));
+    sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+  }
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_invite.c b/ircd/m_invite.c
new file mode 100644 (file)
index 0000000..1ee016c
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_invite.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+#include <assert.h>
+
+/*
+ * m_invite - generic message handler
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to invite
+ *   parv[2] - channel name
+ *
+ * - INVITE now is accepted only if who does it is chanop (this of course
+ *   implies that channel must exist and he must be on it).
+ *
+ * - On the other side it IS processed even if channel is NOT invite only
+ *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
+ *
+ * - Invite with no parameters now lists the channels you are invited to.
+ *                                                         - Isomer 23 Oct 99
+ */
+int m_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  
+  if (parc < 2 ) { 
+    /*
+     * list the channels you have an invite to.
+     */
+    struct SLink *lp;
+    for (lp = sptr->user->invited; lp; lp = lp->next)
+      sendto_one(cptr, rpl_str(RPL_INVITELIST), me.name, cptr->name,
+                 lp->value.chptr->chname);
+    sendto_one(cptr, rpl_str(RPL_ENDOFINVITELIST), me.name, cptr->name);
+    return 0;
+  }
+
+  if (parc < 3 || EmptyString(parv[2]))
+    return need_more_params(sptr, "INVITE");
+
+  if (!(acptr = FindUser(parv[1]))) {
+    sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+    return 0;
+  }
+
+  if (is_silenced(sptr, acptr))
+    return 0;
+
+  clean_channelname(parv[2]);
+
+  if (!IsChannelPrefix(*parv[2]))
+    return 0;
+
+  if (!(chptr = FindChannel(parv[2]))) {
+    if (IsModelessChannel(parv[2]) || IsLocalChannel(parv[2])) {
+      sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[2]);
+      return 0;
+    }
+
+    /* Do not disallow to invite to non-existant #channels, otherwise they
+       would simply first be created, causing only MORE bandwidth usage. */
+
+    if (check_target_limit(sptr, acptr, acptr->name, 0))
+      return 0;
+
+    sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
+               acptr->name, parv[2]);
+
+    if (acptr->user->away)
+      sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
+                 acptr->name, acptr->user->away);
+
+    if (MyUser(acptr))
+      sendto_prefix_one(acptr, sptr, ":%s " MSG_INVITE " %s :%s", sptr->name,
+                        acptr->name, parv[2]);
+    else
+      sendto_one(acptr, "%s%s " TOK_INVITE " %s :%s", NumNick(sptr),
+                 acptr->name, parv[2]);
+
+    return 0;
+  }
+
+  if (!find_channel_member(sptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+               chptr->chname);
+    return 0;
+  }
+
+  if (find_channel_member(acptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_USERONCHANNEL),
+               me.name, parv[0], acptr->name, chptr->chname);
+    return 0;
+  }
+
+  if (!is_chan_op(sptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+               me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  /* If we get here, it was a VALID and meaningful INVITE */
+
+  if (check_target_limit(sptr, acptr, acptr->name, 0))
+    return 0;
+
+  sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
+             acptr->name, chptr->chname);
+
+  if (acptr->user->away)
+    sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
+               acptr->name, acptr->user->away);
+
+  if (MyConnect(acptr)) {
+    add_invite(acptr, chptr);
+    sendto_prefix_one(acptr, sptr, ":%s " MSG_INVITE " %s :%s", 
+                      sptr->name, acptr->name, chptr->chname);
+  }
+  else
+    sendto_one(acptr, "%s%s " TOK_INVITE " %s :%s", 
+               NumNick(sptr), acptr->name, chptr->chname);
+
+  return 0;
+}
+
+/*
+ * ms_invite - server message handler
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to invite
+ *   parv[2] - channel name
+ *
+ * - INVITE now is accepted only if who does it is chanop (this of course
+ *   implies that channel must exist and he must be on it).
+ *
+ * - On the other side it IS processed even if channel is NOT invite only
+ *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
+ *
+ * - Invite with no parameters now lists the channels you are invited to.
+ *                                                         - Isomer 23 Oct 99
+ */
+int ms_invite(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  
+  if (IsServer(sptr)) {
+    /*
+     * this will blow up if we get an invite from a server
+     * we look for channel membership in sptr below. 
+     */
+    /* PROTOCOL WARNING */
+    return 0;
+  }
+  if (parc < 3 || EmptyString(parv[2])) {
+    /*
+     * should have been handled upstream, ignore it.
+     */
+    /* PROTOCOL WARNING */
+    return 0;
+  }
+  if ('#' != *parv[2]) {
+    /*
+     * should not be sent
+     */
+    /* PROTOCOL WARNING */
+    return 0;
+  }
+  if (!(acptr = FindUser(parv[1]))) {
+    sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+    return 0;
+  }
+  if (!MyUser(acptr)) {
+    /*
+     * just relay the message
+     */
+    sendto_one(acptr, "%s%s " TOK_INVITE " %s :%s",
+               NumNick(sptr), acptr->name, parv[2]);
+    return 0;
+  }
+
+  if (is_silenced(sptr, acptr))
+    return 0;
+
+  if (!(chptr = FindChannel(parv[2]))) {
+    /*
+     * allow invites to non existant channels, bleah
+     * avoid JOIN, INVITE, PART abuse
+     */
+    sendto_prefix_one(acptr, sptr, ":%s " MSG_INVITE " %s :%s", sptr->name,
+                      acptr->name, parv[2]);
+    return 0;
+  }
+
+  if (!find_channel_member(sptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+               chptr->chname);
+    return 0;
+  }
+  if (find_channel_member(acptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_USERONCHANNEL),
+               me.name, parv[0], acptr->name, chptr->chname);
+    return 0;
+  }
+  add_invite(acptr, chptr);
+  sendto_prefix_one(acptr, sptr, ":%s " MSG_INVITE " %s :%s", sptr->name,
+                    acptr->name, chptr->chname);
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_invite
+ *
+ *   parv[0] - sender prefix
+ *   parv[1] - user to invite
+ *   parv[2] - channel name
+ *
+ * - INVITE now is accepted only if who does it is chanop (this of course
+ *   implies that channel must exist and he must be on it).
+ *
+ * - On the other side it IS processed even if channel is NOT invite only
+ *   leaving room for other enhancements like inviting banned ppl.  -- Nemesi
+ *
+ * - Invite with no parameters now lists the channels you are invited to.
+ *                                                         - Isomer 23 Oct 99
+ */
+int m_invite(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+  struct Channel *chptr;
+  
+  if (parc < 2 ) { 
+    /*
+     * list the channels you have an invite to.
+     */
+    struct SLink *lp;
+    for (lp = sptr->user->invited; lp; lp = lp->next)
+      sendto_one(cptr, rpl_str(RPL_INVITELIST), me.name, cptr->name,
+                lp->value.chptr->chname);
+    sendto_one(cptr, rpl_str(RPL_ENDOFINVITELIST), me.name, cptr->name);
+    return 0;
+  }
+
+  if (parc < 3 || *parv[2] == '\0')
+    return need_more_params(sptr, "INVITE");
+
+  if (!(acptr = FindUser(parv[1])))
+  {
+    sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+    return 0;
+  }
+
+  if (is_silenced(sptr, acptr))
+    return 0;
+
+  if (MyUser(sptr))
+    clean_channelname(parv[2]);
+  else if (IsLocalChannel(parv[2]))
+    return 0;
+
+  if (*parv[2] == '0' || !IsChannelName(parv[2]))
+    return 0;
+
+  if (!(chptr = FindChannel(parv[2])))
+  {
+    if (IsModelessChannel(parv[2]) || IsLocalChannel(parv[2]))
+    {
+      sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0], parv[2]);
+      return 0;
+    }
+
+    /* Do not disallow to invite to non-existant #channels, otherwise they
+       would simply first be created, causing only MORE bandwidth usage. */
+    if (MyConnect(sptr))
+    {
+      if (check_target_limit(sptr, acptr, acptr->name, 0))
+        return 0;
+
+      sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
+          acptr->name, parv[2]);
+
+      if (acptr->user->away)
+        sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
+            acptr->name, acptr->user->away);
+    }
+
+    sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
+        acptr->name, parv[2]);
+
+    return 0;
+  }
+
+  if (!find_channel_member(sptr, chptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+        chptr->chname);
+    return 0;
+  }
+
+  if (find_channel_member(acptr, chptr))
+  {
+    sendto_one(sptr, err_str(ERR_USERONCHANNEL),
+        me.name, parv[0], acptr->name, chptr->chname);
+    return 0;
+  }
+
+  if (MyConnect(sptr))
+  {
+    if (!is_chan_op(sptr, chptr))
+    {
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+          me.name, parv[0], chptr->chname);
+      return 0;
+    }
+
+    /* If we get here, it was a VALID and meaningful INVITE */
+
+    if (check_target_limit(sptr, acptr, acptr->name, 0))
+      return 0;
+
+    sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
+        acptr->name, chptr->chname);
+
+    if (acptr->user->away)
+      sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
+          acptr->name, acptr->user->away);
+  }
+
+  if (MyConnect(acptr)) {
+    add_invite(acptr, chptr);
+  sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", parv[0],
+      acptr->name, chptr->chname);
+  }
+  else
+    sendto_highprot_butone(acptr, 10, "%s%s " TOK_INVITE " %s :%s", 
+       NumNick(sptr), acptr->name, chptr->chname);
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_ison.c b/ircd/m_ison.c
new file mode 100644 (file)
index 0000000..d97691d
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_ison.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "send.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * 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
+ *
+ * XXX - this is virtually the same as send_user_info, but doesn't send
+ * no nick found, might be refactored so that m_userhost, m_userip, and
+ * m_ison all use the same function with different formatters. --Bleep
+ */
+int m_ison(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client* acptr;
+  char*          name;
+  char*          p = 0;
+  char           buf[BUFSIZE];
+  char*          iter = buf;
+  char*          end = &buf[BUFSIZE - NICKLEN - 4];
+
+  if (parc < 2)
+    return need_more_params(sptr, "ISON");
+
+  iter = sprintf_irc(buf, rpl_str(RPL_ISON), me.name, sptr->name);
+
+  for (name = ircd_strtok(&p, parv[1], " "); name; name = ircd_strtok(&p, 0, " ")) {
+    if ((acptr = FindUser(name))) {
+      strcpy(iter, acptr->name);
+      iter += strlen(iter);
+      if (iter >= end)
+        break;
+      *iter++ = ' ';
+    }
+  }
+  *iter = '\0';
+  if (' ' == *--iter)
+    *iter = '\0';
+
+  send_buffer(sptr, buf);
+  return 0;
+}
+
+
diff --git a/ircd/m_join.c b/ircd/m_join.c
new file mode 100644 (file)
index 0000000..036139d
--- /dev/null
@@ -0,0 +1,962 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_join.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(XXX_BOGUS_TEMP_HACK)
+#include "handlers.h"      /* m_names */
+#endif
+
+/*
+ * m_join - generic message handler
+ */
+int m_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  static char     jbuf[BUFSIZE];
+  static char     mbuf[BUFSIZE];
+  struct Membership* member;
+  struct Channel* chptr;
+  char*           name;
+  char*           keysOrTS = NULL;
+  int             i = 0;
+  int             zombie = 0;
+  int             sendcreate = 0;
+  unsigned int    flags = 0;
+  size_t          jlen = 0;
+  size_t          mlen = 0;
+  size_t*         buflen;
+  char*           p = NULL;
+  char*           bufptr;
+
+  /*
+   * Doesn't make sense having a server join a channel, and besides
+   * the server cores.
+   */
+  if (IsServer(sptr))
+    return 0;
+
+  if (parc < 2 || *parv[1] == '\0')
+    return need_more_params(sptr, "JOIN");
+
+  for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
+    if (*p == '0'
+        && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
+    {
+      /* If it's a single "0", remember the place; we will start parsing
+         the channels after the last 0 in the line -Kev */
+      parv[1] = p;
+      if (!*(p + 1))
+        break;
+      p++;
+    }
+    else
+    {                           /* Step through to the next comma or until the
+                                   end of the line, in an attempt to save CPU
+                                   -Kev */
+      while (*p != ',' && *p != '\0')
+        p++;
+      if (!*p)
+        break;
+    }
+
+  keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
+                                   parv[2] needs to be NULL for the call to
+                                   m_names below -Kev */
+  parv[2] = p = NULL;
+
+  *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
+  /*
+   *  Rebuild list of channels joined to be the actual result of the
+   *  JOIN.  Note that "JOIN 0" is the destructive problem.
+   */
+  for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
+  {
+    size_t len;
+    if (MyConnect(sptr))
+      clean_channelname(name);
+    else if (IsLocalChannel(name))
+      continue;
+    if (*name == '0' && *(name + 1) == '\0')
+    {
+      /* Remove the user from all his channels -Kev */
+      while ((member = sptr->user->channel))
+      {
+        chptr = member->channel;
+        if (!IsZombie(member))
+          sendto_channel_butserv(chptr, sptr, PartFmt2,
+              parv[0], chptr->chname, "Left all channels");
+        remove_user_from_channel(sptr, chptr);
+      }
+      /* Just in case */
+      *mbuf = *jbuf = '\0';
+      mlen = jlen = 0;
+    }
+    else
+    {                           /* not a /join 0, so treat it as
+                                   a /join #channel -Kev */
+      if (!IsChannelName(name))
+      {
+        if (MyUser(sptr))
+          sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+        continue;
+      }
+
+      if (MyConnect(sptr))
+      {
+#ifdef BADCHAN
+        if (bad_channel(name) && !IsAnOper(sptr))
+        {
+          sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
+          continue;
+        }
+#endif
+        /*
+         * Local client is first to enter previously nonexistant
+         * channel so make them (rightfully) the Channel Operator.
+         * This looks kind of ugly because we try to avoid calling the strlen()
+         */
+        if (ChannelExists(name))
+        {
+          flags = CHFL_DEOPPED;
+          sendcreate = 0;
+        }
+        else if (strlen(name) > CHANNELLEN)
+        {
+          *(name + CHANNELLEN) = '\0';
+          if (ChannelExists(name))
+          {
+            flags = CHFL_DEOPPED;
+            sendcreate = 0;
+          }
+          else
+          {
+            flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+            sendcreate = 1;
+          }
+        }
+        else
+        {
+          flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+          sendcreate = 1;
+        }
+
+#ifdef OPER_NO_CHAN_LIMIT
+        /*
+         * Opers are allowed to join any number of channels
+         */
+        if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
+#else
+        if (sptr->user->joined >= MAXCHANNELSPERUSER)
+#endif
+        {
+          chptr = get_channel(sptr, name, CGT_NO_CREATE);
+          sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
+                     me.name, parv[0], chptr ? chptr->chname : name);
+          /*
+           * Can't return, else he won't get on ANY channels!
+           * Break out of the for loop instead.  -Kev
+           */
+          break;
+        }
+      }
+      chptr = get_channel(sptr, name, CGT_CREATE);
+      if (chptr && (member = find_member_link(chptr, sptr)))
+      {
+        if (IsZombie(member))
+        {
+          zombie = 1;
+          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
+          remove_user_from_channel(sptr, chptr);
+          chptr = get_channel(sptr, name, CGT_CREATE);
+        }
+        else
+          continue;
+      }
+      name = chptr->chname;
+      if (!chptr->creationtime) /* A remote JOIN created this channel ? */
+        chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
+      if (parc > 2)
+      {
+        if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
+          chptr->creationtime = atoi(keysOrTS);
+        else
+          parc = 2;             /* Don't pass it on */
+      }
+      if (!zombie)
+      {
+        if (!MyConnect(sptr))
+          flags = CHFL_DEOPPED;
+        if (sptr->flags & FLAGS_TS8)
+          flags |= CHFL_SERVOPOK;
+      }
+      if (MyConnect(sptr))
+      {
+        int created = chptr->users == 0;
+        if (check_target_limit(sptr, chptr, chptr->chname, created))
+        {
+          if (created)          /* Did we create the channel? */
+            sub1_from_channel(chptr);   /* Remove it again! */
+          continue;
+        }
+        if ((i = can_join(sptr, chptr, keysOrTS)))
+        {
+#ifdef OPER_WALK_THROUGH_LMODES
+         if (i > MAGIC_OPER_OVERRIDE)
+         {
+           switch(i - MAGIC_OPER_OVERRIDE)
+           {
+           case ERR_CHANNELISFULL: i = 'l'; break;
+           case ERR_INVITEONLYCHAN: i = 'i'; break;
+           case ERR_BANNEDFROMCHAN: i = 'b'; break;
+           case ERR_BADCHANNELKEY: i = 'k'; break;
+           }
+           sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
+         }
+         else
+         {
+            sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
+           continue;
+         }
+#else    
+          sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
+          continue;
+#endif
+        }
+      }
+      /*
+       * Complete user entry to the new channel (if any)
+       */
+      add_user_to_channel(chptr, sptr, flags);
+
+      /*
+       * Notify all other users on the new channel
+       */
+      sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
+
+      if (MyUser(sptr))
+      {
+        del_invite(sptr, chptr);
+        if (chptr->topic[0] != '\0')
+        {
+          sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
+              parv[0], name, chptr->topic);
+          sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
+              chptr->topic_nick, chptr->topic_time);
+        }
+        parv[1] = name;
+        m_names(cptr, sptr, 2, parv);
+      }
+    }
+
+    /* Select proper buffer; mbuf for creation, jbuf otherwise */
+
+    if (*name == '&')
+      continue;                 /* Head off local channels at the pass */
+
+    bufptr = (sendcreate == 0) ? jbuf : mbuf;
+    buflen = (sendcreate == 0) ? &jlen : &mlen;
+    len = strlen(name);
+    if (*buflen < BUFSIZE - len - 2)
+    {
+      if (*bufptr)
+      {
+        strcat(bufptr, ",");    /* Add to join buf */
+        *buflen += 1;
+      }
+      strncat(bufptr, name, BUFSIZE - *buflen - 1);
+      *buflen += len;
+    }
+    sendcreate = 0;             /* Reset sendcreate */
+  }
+
+  if (*jbuf)                    /* Propgate joins to P10 servers */
+    sendto_serv_butone(cptr, 
+        parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
+  if (*mbuf)                    /* and now creation events */
+    sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
+        NumNick(sptr), mbuf, TStime());
+
+  if (MyUser(sptr))
+  {                             /* shouldn't ever set TS for remote JOIN's */
+    if (*jbuf)
+    {                           /* check for channels that need TS's */
+      p = NULL;
+      for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
+      {
+        chptr = get_channel(sptr, name, CGT_NO_CREATE);
+        if (chptr && chptr->mode.mode & MODE_SENDTS)
+        {                       /* send a TS? */
+          sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
+              chptr->chname, chptr->creationtime);      /* ok, send TS */
+          chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+/*
+ * ms_join - server message handler
+ */
+int ms_join(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  static char     jbuf[BUFSIZE];
+  static char     mbuf[BUFSIZE];
+  struct Membership* member;
+  struct Channel* chptr;
+  char*           name;
+  char*           keysOrTS = NULL;
+  int             i = 0;
+  int             zombie = 0;
+  int             sendcreate = 0;
+  unsigned int    flags = 0;
+  size_t          jlen = 0;
+  size_t          mlen = 0;
+  size_t*         buflen;
+  char*           p = NULL;
+  char*           bufptr;
+
+  /*
+   * Doesn't make sense having a server join a channel, and besides
+   * the server cores.
+   */
+  if (IsServer(sptr))
+    return 0;
+
+  if (parc < 2 || *parv[1] == '\0')
+    return need_more_params(sptr, "JOIN");
+
+  for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
+    if (*p == '0'
+        && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
+    {
+      /* If it's a single "0", remember the place; we will start parsing
+         the channels after the last 0 in the line -Kev */
+      parv[1] = p;
+      if (!*(p + 1))
+        break;
+      p++;
+    }
+    else
+    {                           /* Step through to the next comma or until the
+                                   end of the line, in an attempt to save CPU
+                                   -Kev */
+      while (*p != ',' && *p != '\0')
+        p++;
+      if (!*p)
+        break;
+    }
+
+  keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
+                                   parv[2] needs to be NULL for the call to
+                                   m_names below -Kev */
+  parv[2] = p = NULL;
+
+  *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
+  /*
+   *  Rebuild list of channels joined to be the actual result of the
+   *  JOIN.  Note that "JOIN 0" is the destructive problem.
+   */
+  for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
+  {
+    size_t len;
+    if (MyConnect(sptr))
+      clean_channelname(name);
+    else if (IsLocalChannel(name))
+      continue;
+    if (*name == '0' && *(name + 1) == '\0')
+    {
+      /* Remove the user from all his channels -Kev */
+      while ((member = sptr->user->channel))
+      {
+        chptr = member->channel;
+        if (!IsZombie(member))
+          sendto_channel_butserv(chptr, sptr, PartFmt2,
+              parv[0], chptr->chname, "Left all channels");
+        remove_user_from_channel(sptr, chptr);
+      }
+      /* Just in case */
+      *mbuf = *jbuf = '\0';
+      mlen = jlen = 0;
+    }
+    else
+    {                           /* not a /join 0, so treat it as
+                                   a /join #channel -Kev */
+      if (!IsChannelName(name))
+      {
+        if (MyUser(sptr))
+          sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+        continue;
+      }
+
+      if (MyConnect(sptr))
+      {
+#ifdef BADCHAN
+        if (bad_channel(name) && !IsAnOper(sptr))
+        {
+          sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
+          continue;
+        }
+#endif
+        /*
+         * Local client is first to enter previously nonexistant
+         * channel so make them (rightfully) the Channel Operator.
+         * This looks kind of ugly because we try to avoid calling the strlen()
+         */
+        if (ChannelExists(name))
+        {
+          flags = CHFL_DEOPPED;
+          sendcreate = 0;
+        }
+        else if (strlen(name) > CHANNELLEN)
+        {
+          *(name + CHANNELLEN) = '\0';
+          if (ChannelExists(name))
+          {
+            flags = CHFL_DEOPPED;
+            sendcreate = 0;
+          }
+          else
+          {
+            flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+            sendcreate = 1;
+          }
+        }
+        else
+        {
+          flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+          sendcreate = 1;
+        }
+
+#ifdef OPER_NO_CHAN_LIMIT
+        /*
+         * Opers are allowed to join any number of channels
+         */
+        if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
+#else
+        if (sptr->user->joined >= MAXCHANNELSPERUSER)
+#endif
+        {
+          chptr = get_channel(sptr, name, CGT_NO_CREATE);
+          sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
+                     me.name, parv[0], chptr ? chptr->chname : name);
+          /*
+           * Can't return, else he won't get on ANY channels!
+           * Break out of the for loop instead.  -Kev
+           */
+          break;
+        }
+      }
+      chptr = get_channel(sptr, name, CGT_CREATE);
+      if (chptr && (member = find_member_link(chptr, sptr)))
+      {
+        if (IsZombie(member))
+        {
+          zombie = 1;
+          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
+          remove_user_from_channel(sptr, chptr);
+          chptr = get_channel(sptr, name, CGT_CREATE);
+        }
+        else
+          continue;
+      }
+      name = chptr->chname;
+      if (!chptr->creationtime) /* A remote JOIN created this channel ? */
+        chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
+      if (parc > 2)
+      {
+        if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
+          chptr->creationtime = atoi(keysOrTS);
+        else
+          parc = 2;             /* Don't pass it on */
+      }
+      if (!zombie)
+      {
+        if (!MyConnect(sptr))
+          flags = CHFL_DEOPPED;
+        if (sptr->flags & FLAGS_TS8)
+          flags |= CHFL_SERVOPOK;
+      }
+      if (MyConnect(sptr))
+      {
+        int created = chptr->users == 0;
+        if (check_target_limit(sptr, chptr, chptr->chname, created))
+        {
+          if (created)          /* Did we create the channel? */
+            sub1_from_channel(chptr);   /* Remove it again! */
+          continue;
+        }
+        if ((i = can_join(sptr, chptr, keysOrTS)))
+        {
+          sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
+          continue;
+        }
+      }
+      /*
+       * Complete user entry to the new channel (if any)
+       */
+      add_user_to_channel(chptr, sptr, flags);
+
+      /*
+       * Notify all other users on the new channel
+       */
+      sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
+
+      if (MyUser(sptr))
+      {
+        del_invite(sptr, chptr);
+        if (chptr->topic[0] != '\0')
+        {
+          sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
+              parv[0], name, chptr->topic);
+          sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
+              chptr->topic_nick, chptr->topic_time);
+        }
+        parv[1] = name;
+        m_names(cptr, sptr, 2, parv);
+      }
+    }
+
+    /* Select proper buffer; mbuf for creation, jbuf otherwise */
+
+    if (*name == '&')
+      continue;                 /* Head off local channels at the pass */
+
+    bufptr = (sendcreate == 0) ? jbuf : mbuf;
+    buflen = (sendcreate == 0) ? &jlen : &mlen;
+    len = strlen(name);
+    if (*buflen < BUFSIZE - len - 2)
+    {
+      if (*bufptr)
+      {
+        strcat(bufptr, ",");    /* Add to join buf */
+        *buflen += 1;
+      }
+      strncat(bufptr, name, BUFSIZE - *buflen - 1);
+      *buflen += len;
+    }
+    sendcreate = 0;             /* Reset sendcreate */
+  }
+
+  if (*jbuf)                    /* Propgate joins to P10 servers */
+    sendto_serv_butone(cptr, 
+        parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
+  if (*mbuf)                    /* and now creation events */
+    sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
+        NumNick(sptr), mbuf, TStime());
+
+  if (MyUser(sptr))
+  {                             /* shouldn't ever set TS for remote JOIN's */
+    if (*jbuf)
+    {                           /* check for channels that need TS's */
+      p = NULL;
+      for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
+      {
+        chptr = get_channel(sptr, name, CGT_NO_CREATE);
+        if (chptr && chptr->mode.mode & MODE_SENDTS)
+        {                       /* send a TS? */
+          sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
+              chptr->chname, chptr->creationtime);      /* ok, send TS */
+          chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_join
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = channel keys (client), or channel TS (server)
+ */
+int m_join(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  static char     jbuf[BUFSIZE];
+  static char     mbuf[BUFSIZE];
+  struct Membership* member;
+  struct Channel* chptr;
+  char*           name;
+  char*           keysOrTS = NULL;
+  int             i = 0;
+  int             zombie = 0;
+  int             sendcreate = 0;
+  unsigned int    flags = 0;
+  size_t          jlen = 0;
+  size_t          mlen = 0;
+  size_t*         buflen;
+  char*           p = NULL;
+  char*           bufptr;
+
+  /*
+   * Doesn't make sense having a server join a channel, and besides
+   * the server cores.
+   */
+  if (IsServer(sptr))
+    return 0;
+
+  if (parc < 2 || *parv[1] == '\0')
+    return need_more_params(sptr, "JOIN");
+
+  for (p = parv[1]; *p; p++)    /* find the last "JOIN 0" in the line -Kev */
+    if (*p == '0'
+        && (*(p + 1) == ',' || *(p + 1) == '\0' || !IsChannelChar(*(p + 1))))
+    {
+      /* If it's a single "0", remember the place; we will start parsing
+         the channels after the last 0 in the line -Kev */
+      parv[1] = p;
+      if (!*(p + 1))
+        break;
+      p++;
+    }
+    else
+    {                           /* Step through to the next comma or until the
+                                   end of the line, in an attempt to save CPU
+                                   -Kev */
+      while (*p != ',' && *p != '\0')
+        p++;
+      if (!*p)
+        break;
+    }
+
+  keysOrTS = parv[2];           /* Remember where our keys are or the TS is;
+                                   parv[2] needs to be NULL for the call to
+                                   m_names below -Kev */
+  parv[2] = p = NULL;
+
+  *jbuf = *mbuf = '\0';         /* clear both join and mode buffers -Kev */
+  /*
+   *  Rebuild list of channels joined to be the actual result of the
+   *  JOIN.  Note that "JOIN 0" is the destructive problem.
+   */
+  for (name = ircd_strtok(&p, parv[1], ","); name; name = ircd_strtok(&p, NULL, ","))
+  {
+    size_t len;
+    if (MyConnect(sptr))
+      clean_channelname(name);
+    else if (IsLocalChannel(name))
+      continue;
+    if (*name == '0' && *(name + 1) == '\0')
+    {
+      /* Remove the user from all his channels -Kev */
+      while ((member = sptr->user->channel))
+      {
+        chptr = member->channel;
+        if (!IsZombie(member))
+          sendto_channel_butserv(chptr, sptr, PartFmt2,
+              parv[0], chptr->chname, "Left all channels");
+        remove_user_from_channel(sptr, chptr);
+      }
+      /* Just in case */
+      *mbuf = *jbuf = '\0';
+      mlen = jlen = 0;
+    }
+    else
+    {                           /* not a /join 0, so treat it as
+                                   a /join #channel -Kev */
+      if (!IsChannelName(name))
+      {
+        if (MyUser(sptr))
+          sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+        continue;
+      }
+
+      if (MyConnect(sptr))
+      {
+#ifdef BADCHAN
+        if (bad_channel(name) && !IsAnOper(sptr))
+        {
+          sendto_one(sptr, err_str(ERR_BADCHANNAME), me.name, parv[0], name);
+          continue;
+        }
+#endif
+        /*
+         * Local client is first to enter previously nonexistant
+         * channel so make them (rightfully) the Channel Operator.
+         * This looks kind of ugly because we try to avoid calling the strlen()
+         */
+        if (ChannelExists(name))
+        {
+          flags = CHFL_DEOPPED;
+          sendcreate = 0;
+        }
+        else if (strlen(name) > CHANNELLEN)
+        {
+          *(name + CHANNELLEN) = '\0';
+          if (ChannelExists(name))
+          {
+            flags = CHFL_DEOPPED;
+            sendcreate = 0;
+          }
+          else
+          {
+            flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+            sendcreate = 1;
+          }
+        }
+        else
+        {
+          flags = IsModelessChannel(name) ? CHFL_DEOPPED : CHFL_CHANOP;
+          sendcreate = 1;
+        }
+
+#ifdef OPER_NO_CHAN_LIMIT
+        /*
+         * Opers are allowed to join any number of channels
+         */
+        if (sptr->user->joined >= MAXCHANNELSPERUSER && !IsAnOper(sptr))
+#else
+        if (sptr->user->joined >= MAXCHANNELSPERUSER)
+#endif
+        {
+          chptr = get_channel(sptr, name, CGT_NO_CREATE);
+          sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
+                     me.name, parv[0], chptr ? chptr->chname : name);
+          /*
+           * Can't return, else he won't get on ANY channels!
+           * Break out of the for loop instead.  -Kev
+           */
+          break;
+        }
+      }
+      chptr = get_channel(sptr, name, CGT_CREATE);
+      if (chptr && (member = find_member_link(chptr, sptr)))
+      {
+        if (IsZombie(member))
+        {
+          zombie = 1;
+          flags = member->status & (CHFL_DEOPPED | CHFL_SERVOPOK);
+          remove_user_from_channel(sptr, chptr);
+          chptr = get_channel(sptr, name, CGT_CREATE);
+        }
+        else
+          continue;
+      }
+      name = chptr->chname;
+      if (!chptr->creationtime) /* A remote JOIN created this channel ? */
+        chptr->creationtime = MAGIC_REMOTE_JOIN_TS;
+      if (parc > 2)
+      {
+        if (chptr->creationtime == MAGIC_REMOTE_JOIN_TS)
+          chptr->creationtime = atoi(keysOrTS);
+        else
+          parc = 2;             /* Don't pass it on */
+      }
+      if (!zombie)
+      {
+        if (!MyConnect(sptr))
+          flags = CHFL_DEOPPED;
+        if (sptr->flags & FLAGS_TS8)
+          flags |= CHFL_SERVOPOK;
+      }
+      if (MyConnect(sptr))
+      {
+        int created = chptr->users == 0;
+        if (check_target_limit(sptr, chptr, chptr->chname, created))
+        {
+          if (created)          /* Did we create the channel? */
+            sub1_from_channel(chptr);   /* Remove it again! */
+          continue;
+        }
+        if ((i = can_join(sptr, chptr, keysOrTS)))
+        {
+          sendto_one(sptr, err_str(i), me.name, parv[0], chptr->chname);
+#ifdef OPER_WALK_THROUGH_LMODES
+         if (i > MAGIC_OPER_OVERRIDE)
+         {
+           switch(i - MAGIC_OPER_OVERRIDE)
+           {
+           case ERR_CHANNELISFULL: i = 'l'; break;
+           case ERR_INVITEONLYCHAN: i = 'i'; break;
+           case ERR_BANNEDFROMCHAN: i = 'b'; break;
+           case ERR_BADCHANNELKEY: i = 'k'; break;
+           }
+           sendto_op_mask(SNO_HACK4,"OPER JOIN: %s JOIN %s (overriding +%c)",sptr->name,chptr->chname,i);
+         }
+         else
+           continue;     
+#else    
+          continue;
+#endif
+        }
+      }
+      /*
+       * Complete user entry to the new channel (if any)
+       */
+      add_user_to_channel(chptr, sptr, flags);
+
+      /*
+       * Notify all other users on the new channel
+       */
+      sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", parv[0], name);
+
+      if (MyUser(sptr))
+      {
+        del_invite(sptr, chptr);
+        if (chptr->topic[0] != '\0')
+        {
+          sendto_one(sptr, rpl_str(RPL_TOPIC), me.name,
+              parv[0], name, chptr->topic);
+          sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME), me.name, parv[0], name,
+              chptr->topic_nick, chptr->topic_time);
+        }
+        parv[1] = name;
+        m_names(cptr, sptr, 2, parv);
+      }
+    }
+
+    /* Select proper buffer; mbuf for creation, jbuf otherwise */
+
+    if (*name == '&')
+      continue;                 /* Head off local channels at the pass */
+
+    bufptr = (sendcreate == 0) ? jbuf : mbuf;
+    buflen = (sendcreate == 0) ? &jlen : &mlen;
+    len = strlen(name);
+    if (*buflen < BUFSIZE - len - 2)
+    {
+      if (*bufptr)
+      {
+        strcat(bufptr, ",");    /* Add to join buf */
+        *buflen += 1;
+      }
+      strncat(bufptr, name, BUFSIZE - *buflen - 1);
+      *buflen += len;
+    }
+    sendcreate = 0;             /* Reset sendcreate */
+  }
+
+  if (*jbuf)                    /* Propgate joins to P10 servers */
+    sendto_serv_butone(cptr, 
+        parc > 2 ? "%s%s " TOK_JOIN " %s %s" : "%s%s " TOK_JOIN " %s", NumNick(sptr), jbuf, keysOrTS);
+  if (*mbuf)                    /* and now creation events */
+    sendto_serv_butone(cptr, "%s%s " TOK_CREATE " %s " TIME_T_FMT,
+        NumNick(sptr), mbuf, TStime());
+
+  if (MyUser(sptr))
+  {                             /* shouldn't ever set TS for remote JOIN's */
+    if (*jbuf)
+    {                           /* check for channels that need TS's */
+      p = NULL;
+      for (name = ircd_strtok(&p, jbuf, ","); name; name = ircd_strtok(&p, NULL, ","))
+      {
+        chptr = get_channel(sptr, name, CGT_NO_CREATE);
+        if (chptr && chptr->mode.mode & MODE_SENDTS)
+        {                       /* send a TS? */
+          sendto_serv_butone(cptr, "%s " TOK_MODE " %s + " TIME_T_FMT, NumServ(&me),
+              chptr->chname, chptr->creationtime);      /* ok, send TS */
+          chptr->mode.mode &= ~MODE_SENDTS;     /* reset flag */
+        }
+      }
+    }
+  }
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_kick.c b/ircd/m_kick.c
new file mode 100644 (file)
index 0000000..bde9a71
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_kick.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_kick - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[parc-1] = kick comment
+ */
+int m_kick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client*  who;
+  struct Channel* chptr;
+  struct Membership* member = 0;
+  char*           channel_name;
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 3 || *parv[1] == '\0')
+    return need_more_params(sptr, "KICK");
+
+  channel_name = parv[1];
+
+  if (IsLocalChannel(channel_name) && !MyUser(sptr))
+    return 0;
+
+  if (IsModelessChannel(channel_name)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+               channel_name);
+    return 0;
+  }
+
+  chptr = get_channel(sptr, channel_name, CGT_NO_CREATE);
+  if (!chptr) {
+    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], channel_name);
+    return 0;
+  }
+
+  if (!IsServer(cptr) && !is_chan_op(sptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+               me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  if (MyUser(sptr)) {
+    if (!(who = find_chasing(sptr, parv[2], 0)))
+      return 0;                 /* No such user left! */
+  }
+  else if (!(who = findNUser(parv[2])))
+    return 0;                   /* No such user left! */
+
+  /*
+   * if the user is +k, prevent a kick from local user
+   */
+  if (IsChannelService(who) && MyUser(sptr)) {
+    sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
+        parv[0], who->name, chptr->chname);
+    return 0;
+  }
+
+#ifdef NO_OPER_DEOP_LCHAN
+  /*
+   * Prevent kicking opers from local channels -DM-
+   */
+  if (IsOperOnLocalChannel(who, chptr->chname)) {
+    sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
+               parv[0], who->name, chptr->chname);
+    return 0;
+  }
+#endif
+
+  /* 
+   * Servers can now send kicks without hacks during a netburst - they
+   * are kicking users from a +i channel.
+   *  - Isomer 25-11-1999
+   */
+  if (IsServer(sptr)
+#if defined(NO_INVITE_NETRIDE)
+      && !IsBurstOrBurstAck(sptr)
+#endif
+     ) {
+    send_hack_notice(cptr, sptr, parc, parv, 1, 3);
+  }
+
+  if (IsServer(sptr) ||
+      ((member = find_member_link(chptr, who)) && !IsZombie(member)))
+  {
+    struct Membership* sptr_link = find_member_link(chptr, sptr);
+    if (who->from != cptr &&
+        ((sptr_link && IsDeopped(sptr_link)) || (!sptr_link && IsUser(sptr))))
+    {
+      /*
+       * Bounce here:
+       * cptr must be a server (or cptr == sptr and
+       * sptr->flags can't have DEOPPED set
+       * when CHANOP is set).
+       */
+      sendto_one(cptr, "%s%s " TOK_JOIN " %s", NumNick(who), chptr->chname);
+      if (IsChanOp(member))
+      {
+         sendto_one(cptr, "%s " TOK_MODE " %s +o %s%s " TIME_T_FMT,
+              NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
+      }
+      if (HasVoice(member))
+      {
+         sendto_one(cptr, "%s " TOK_MODE " %s +v %s%s " TIME_T_FMT,
+              NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
+      }
+    }
+    else
+    {
+      char* comment = (EmptyString(parv[parc - 1])) ? parv[0] : parv[parc - 1];
+      if (strlen(comment) > TOPICLEN)
+        comment[TOPICLEN] = '\0';
+
+      if (!IsLocalChannel(channel_name))
+      {
+        sendto_highprot_butone(cptr, 10, "%s%s " TOK_KICK " %s %s%s :%s",
+            NumNick(sptr), chptr->chname, NumNick(who), comment);
+      }
+      if (member) {
+        sendto_channel_butserv(chptr, sptr,
+            ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
+        make_zombie(member, who, cptr, sptr, chptr);
+      }
+    }
+  }
+  else if (MyUser(sptr))
+    sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
+        me.name, parv[0], who->name, chptr->chname);
+
+  return 0;
+}
+
+/*
+ * ms_kick - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[parc-1] = kick comment
+ */
+int ms_kick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client*  who;
+  struct Channel* chptr;
+  struct Membership* member = 0;
+  char*           channel_name;
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 3 || *parv[1] == '\0')
+    return need_more_params(sptr, "KICK");
+
+  channel_name = parv[1];
+
+  if (IsLocalChannel(channel_name) && !MyUser(sptr))
+    return 0;
+
+  if (IsModelessChannel(channel_name)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+               channel_name);
+    return 0;
+  }
+
+  chptr = get_channel(sptr, channel_name, CGT_NO_CREATE);
+  if (!chptr) {
+    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], channel_name);
+    return 0;
+  }
+
+  if (!IsServer(cptr) && !is_chan_op(sptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+               me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  if (MyUser(sptr)) {
+    if (!(who = find_chasing(sptr, parv[2], 0)))
+      return 0;                 /* No such user left! */
+  }
+  else if (!(who = findNUser(parv[2])))
+    return 0;                   /* No such user left! */
+
+  /*
+   * if the user is +k, prevent a kick from local user
+   */
+  if (IsChannelService(who) && MyUser(sptr)) {
+    sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
+        parv[0], who->name, chptr->chname);
+    return 0;
+  }
+
+#ifdef NO_OPER_DEOP_LCHAN
+  /*
+   * Prevent kicking opers from local channels -DM-
+   */
+  if (IsOperOnLocalChannel(who, chptr->chname)) {
+    sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
+               parv[0], who->name, chptr->chname);
+    return 0;
+  }
+#endif
+
+#if defined(NO_INVITE_NETRIDE)
+  /* 
+   * Servers can now send kicks without hacks during a netburst - they
+   * are kicking users from a +i channel.
+   *  - Isomer 25-11-1999
+   */
+  if (IsServer(sptr) && !IsBurstOrBurstAck(sptr)) {
+#else
+  if (IsServer(sptr)) {
+#endif
+    send_hack_notice(cptr, sptr, parc, parv, 1, 3);
+  }
+
+  if (IsServer(sptr) ||
+      ((member = find_member_link(chptr, who)) && !IsZombie(member)))
+  {
+    struct Membership* sptr_link = find_member_link(chptr, sptr);
+    if (who->from != cptr &&
+        ((sptr_link && IsDeopped(sptr_link)) || (!sptr_link && IsUser(sptr))))
+    {
+      /*
+       * Bounce here:
+       * cptr must be a server (or cptr == sptr and
+       * sptr->flags can't have DEOPPED set
+       * when CHANOP is set).
+       */
+      sendto_one(cptr, "%s%s " TOK_JOIN " %s", NumNick(who), chptr->chname);
+      if (IsChanOp(member))
+      {
+         sendto_one(cptr, "%s " TOK_MODE " %s +o %s%s " TIME_T_FMT,
+              NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
+      }
+      if (HasVoice(member))
+      {
+         sendto_one(cptr, "%s " TOK_MODE " %s +v %s%s " TIME_T_FMT,
+              NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
+      }
+    }
+    else
+    {
+      char* comment = (EmptyString(parv[parc - 1])) ? parv[0] : parv[parc - 1];
+      if (strlen(comment) > TOPICLEN)
+        comment[TOPICLEN] = '\0';
+
+      if (!IsLocalChannel(channel_name)) {
+        if (IsServer(sptr)) {
+          sendto_highprot_butone(cptr, 10, "%s " TOK_KICK " %s %s%s :%s",
+                                 NumServ(sptr), chptr->chname, NumNick(who),
+                                 comment);
+        }
+        else {
+          sendto_highprot_butone(cptr, 10, "%s%s " TOK_KICK " %s %s%s :%s",
+                                 NumNick(sptr), chptr->chname, NumNick(who),
+                                 comment);
+        }
+      }
+      if (member) {
+        sendto_channel_butserv(chptr, sptr,
+            ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
+        make_zombie(member, who, cptr, sptr, chptr);
+      }
+    }
+  }
+  else if (MyUser(sptr))
+    sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
+        me.name, parv[0], who->name, chptr->chname);
+
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_kick
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[2] = client to kick
+ * parv[parc-1] = kick comment
+ */
+int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client*  who;
+  struct Channel* chptr;
+  struct Membership* member = 0;
+  char*           channel_name;
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 3 || *parv[1] == '\0')
+    return need_more_params(sptr, "KICK");
+
+  channel_name = parv[1];
+
+  if (IsLocalChannel(channel_name) && !MyUser(sptr))
+    return 0;
+
+  if (IsModelessChannel(channel_name)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+               channel_name);
+    return 0;
+  }
+
+  chptr = get_channel(sptr, channel_name, CGT_NO_CREATE);
+  if (!chptr) {
+    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], channel_name);
+    return 0;
+  }
+
+  if (!IsServer(cptr) && !is_chan_op(sptr, chptr)) {
+    sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+               me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  if (MyUser(sptr)) {
+    if (!(who = find_chasing(sptr, parv[2], 0)))
+      return 0;                 /* No such user left! */
+  }
+  else if (!(who = findNUser(parv[2])))
+    return 0;                   /* No such user left! */
+
+  /*
+   * if the user is +k, prevent a kick from local user
+   */
+  if (IsChannelService(who) && MyUser(sptr)) {
+    sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
+        parv[0], who->name, chptr->chname);
+    return 0;
+  }
+
+#ifdef NO_OPER_DEOP_LCHAN
+  /*
+   * Prevent kicking opers from local channels -DM-
+   */
+  if (IsOperOnLocalChannel(who, chptr->chname)) {
+    sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
+               parv[0], who->name, chptr->chname);
+    return 0;
+  }
+#endif
+
+  /* 
+   * Servers can now send kicks without hacks during a netburst - they
+   * are kicking users from a +i channel.
+   *  - Isomer 25-11-1999
+   */
+  if (IsServer(sptr)
+#if defined(NO_INVITE_NETRIDE)
+      && !IsBurstOrBurstAck(sptr)
+#endif
+     ) {
+    send_hack_notice(cptr, sptr, parc, parv, 1, 3);
+  }
+
+  if (IsServer(sptr) ||
+      ((member = find_member_link(chptr, who)) && !IsZombie(member)))
+  {
+    struct Membership* sptr_link = find_member_link(chptr, sptr);
+    if (who->from != cptr &&
+        ((sptr_link && IsDeopped(sptr_link)) || (!sptr_link && IsUser(sptr))))
+    {
+      /*
+       * Bounce here:
+       * cptr must be a server (or cptr == sptr and
+       * sptr->flags can't have DEOPPED set
+       * when CHANOP is set).
+       */
+      sendto_one(cptr, "%s%s " TOK_JOIN " %s", NumNick(who), chptr->chname);
+      if (IsChanOp(member))
+      {
+         sendto_one(cptr, "%s " TOK_MODE " %s +o %s%s " TIME_T_FMT,
+              NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
+      }
+      if (HasVoice(member))
+      {
+         sendto_one(cptr, "%s " TOK_MODE " %s +v %s%s " TIME_T_FMT,
+              NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
+      }
+    }
+    else
+    {
+      char* comment = (EmptyString(parv[parc - 1])) ? parv[0] : parv[parc - 1];
+      if (strlen(comment) > TOPICLEN)
+        comment[TOPICLEN] = '\0';
+
+      if (!IsLocalChannel(channel_name))
+      {
+        sendto_highprot_butone(cptr, 10, "%s%s " TOK_KICK " %s %s%s :%s",
+            NumNick(sptr), chptr->chname, NumNick(who), comment);
+      }
+      if (member) {
+        sendto_channel_butserv(chptr, sptr,
+            ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
+        make_zombie(member, who, cptr, sptr, chptr);
+      }
+    }
+  }
+  else if (MyUser(sptr))
+    sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
+        me.name, parv[0], who->name, chptr->chname);
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_kill.c b/ircd/m_kill.c
new file mode 100644 (file)
index 0000000..9bbcb50
--- /dev/null
@@ -0,0 +1,624 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_kill.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_misc.h"
+#include "send.h"
+#include "whowas.h"
+
+#include <assert.h>
+#include <string.h>
+
+#if defined(DEBUGMODE)
+#define SYSLOG_KILL
+#endif
+
+/*
+ * ms_kill - server message handler template
+ *
+ * NOTE: IsServer(cptr) == true;
+ *
+ * parv[0]      = sender prefix
+ * parv[1]      = kill victim
+ * parv[parc-1] = kill path
+ */
+int ms_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* victim;
+  const char*    inpath;
+  char*          user;
+  char*          path;
+  char*          killer;
+  char           buf[BUFSIZE];
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  /*
+   * XXX - a server sending less than 3 params could really desync
+   * things
+   */
+  if (parc < 3)
+    return need_more_params(sptr, "KILL");
+
+  user = parv[1];
+  path = parv[parc - 1];        /* Either defined or NULL (parc >= 3) */
+
+  if (!(victim = findNUser(parv[1]))) {
+    if (IsUser(sptr))
+      sendto_one(sptr,
+                 "%s NOTICE %s%s :KILL target disconnected before I got him :(",
+                 NumServ(&me), NumNick(sptr));
+    return 0;
+  }
+#if 0
+  /*
+   * XXX - strictly speaking, the next 2 checks shouldn't be needed
+   * this function only handles kills from servers, and the check
+   * is done before the message is propagated --Bleep
+   */
+  if (IsServer(victim) || IsMe(victim)) {
+    return send_error_to_client(sptr, ERR_CANTKILLSERVER);
+    return 0;
+  }
+  if (IsLocOp(sptr) && !MyConnect(victim)) {
+    return send_error_to_client(sptr, ERR_NOPRIVILEGES);
+    return 0;
+  }
+  /*
+   * XXX - this is guaranteed by the parser not to happen
+   */
+  if (EmptyString(path))
+    path = "*no-path*";                /* Bogus server sending??? */
+#endif
+  /*
+   * Notify all *local* opers about the KILL (this includes the one
+   * originating the kill, if from this server--the special numeric
+   * reply message is not generated anymore).
+   *
+   * Note: "victim->name" is used instead of "user" because we may
+   *       have changed the target because of the nickname change.
+   */
+  inpath = cptr->name;
+
+  sendto_op_mask(IsServer(sptr) ? SNO_SERVKILL : SNO_OPERKILL,
+                 "Received KILL message for %s. From %s Path: %s!%s",
+                 victim->name, parv[0], cptr->name, path);
+
+#if defined(SYSLOG_KILL)
+  ircd_log_kill(victim, sptr, cptr->name, path);
+#endif
+  /*
+   * 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.
+   */
+#if defined(EVERYONE_SENDS_NUMERICS)
+  /*
+   * just pass parv[0] here, it's the numeric nick of the sender
+   */
+  sendto_highprot_butone(cptr, 10, "%s " TOK_KILL " %s%s :%s!%s",
+                         parv[0], NumNick(victim), cptr->name, path);
+#else
+  /*
+   * translate to numerics
+   */
+  if (IsServer(sptr))
+    sendto_highprot_butone(cptr, 10, "%s " TOK_KILL " %s%s :%s!%s",
+                           NumServ(sptr), NumNick(victim), cptr->name, path);
+  else
+    sendto_highprot_butone(cptr, 10, "%s%s " TOK_KILL " %s%s :%s!%s",
+                           NumNick(sptr), NumNick(victim), cptr->name, path);
+#endif
+  /*
+   * We *can* have crossed a NICK with this numeric... --Run
+   *
+   * Note the following situation:
+   *  KILL SAA -->       X
+   *  <-- S NICK ... SAA | <-- SAA QUIT <-- S NICK ... SAA <-- SQUIT S
+   * Where the KILL reaches point X before the QUIT does.
+   * This would then *still* cause an orphan because the KILL doesn't reach S
+   * (because of the SQUIT), the QUIT is ignored (because of the KILL)
+   * and the second NICK ... SAA causes an orphan on the server at the
+   * right (which then isn't removed when the SQUIT arrives).
+   * Therefore we still need to detect numeric nick collisions too.
+   *
+   * Bounce the kill back to the originator, if the client can't be found
+   * by the next hop (short lag) the bounce won't propagate further.
+   */
+  if (MyConnect(victim))
+    sendto_one(cptr, "%s " TOK_KILL " %s%s :%s!%s (Ghost 5 Numeric Collided)",
+               NumServ(&me), NumNick(victim), cptr->name, path);
+  /*
+   * 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)
+   */
+  victim->flags |= FLAGS_KILLED;
+
+  /*
+   * Tell the victim she/he has been zapped, but *only* if
+   * the victim is on current server--no sense in sending the
+   * notification chasing the above kill, it won't get far
+   * anyway (as this user don't exist there any more either)
+   */
+  if (MyConnect(victim))
+    sendto_prefix_one(victim, sptr, ":%s KILL %s :%s!%s",
+                      sptr->name, victim->name, cptr->name, path);
+  /*
+   * the first space in path will be at the end of the
+   * opers name:
+   * bla.bla.bla!host.net.dom!opername (comment)
+   */
+  if ((killer = strchr(path, ' '))) {
+    while (killer > path && '!' != *killer)
+      --killer;
+    if ('!' == *killer)
+      ++killer;
+  }
+  else
+    killer = path;
+  sprintf_irc(buf, "Killed (%s)", killer);
+
+  return exit_client(cptr, victim, sptr, buf);
+}
+
+/*
+ * mo_kill - oper message handler template
+ *
+ * NOTE: IsPrivileged(sptr), IsAnOper(sptr) == true
+ *       IsServer(cptr), IsServer(sptr) == false
+ *
+ * parv[0]      = sender prefix
+ * parv[1]      = kill victim
+ * parv[parc-1] = kill path
+ */
+int mo_kill(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* victim;
+  const char*    inpath;
+  char*          user;
+  char*          path;
+  char*          comment;
+  char           buf[BUFSIZE];
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  /*
+   * oper connection to this server, cptr is always sptr
+   */
+  assert(cptr == sptr);
+  assert(IsAnOper(sptr));
+
+#if defined(OPER_KILL)
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return need_more_params(sptr, "KILL");
+
+  user = parv[1];
+  if (!(victim = FindClient(user))) {
+    /*
+     * If the user has recently changed nick, we automaticly
+     * rewrite the KILL for this new nickname--this keeps
+     * servers in synch when nick change and kill collide
+     */
+    if (!(victim = get_history(user, (long)15)))
+      return send_error_to_client(sptr, ERR_NOSUCHNICK, user);
+
+    sendto_one(sptr, ":%s NOTICE %s :Changed KILL %s into %s",
+               me.name, parv[0], user, victim->name);
+  }
+  if (!MyConnect(victim) && IsLocOp(cptr))
+    return send_error_to_client(sptr, ERR_NOPRIVILEGES);
+
+  if (IsServer(victim) || IsMe(victim)) {
+    return send_error_to_client(sptr, ERR_CANTKILLSERVER);
+  }
+  /*
+   * if the user is +k, prevent a kill from local user
+   */
+  if (IsChannelService(victim))
+    return send_error_to_client(sptr, ERR_ISCHANSERVICE, "KILL", victim->name);
+
+
+#ifdef LOCAL_KILL_ONLY
+  if (!MyConnect(victim)) {
+    sendto_one(sptr, ":%s NOTICE %s :Nick %s isnt on your server",
+               me.name, parv[0], victim->name);
+    return 0;
+  }
+#endif
+  /*
+   * The kill originates from this server, initialize path.
+   * (In which case the 'path' may contain user suplied
+   * explanation ...or some nasty comment, sigh... >;-)
+   *
+   * ...!operhost!oper
+   * ...!operhost!oper (comment)
+   */
+
+  comment = parv[parc - 1];        /* Either defined or NULL (parc >= 3) */
+
+  if (strlen(comment) > TOPICLEN)
+    comment[TOPICLEN] = '\0';
+
+  inpath = sptr->user->host;
+
+  sprintf_irc(buf,
+              "%s%s (%s)", cptr->name, IsOper(sptr) ? "" : "(L)", comment);
+  path = buf;
+
+  /*
+   * Notify all *local* opers about the KILL (this includes the one
+   * originating the kill, if from this server--the special numeric
+   * reply message is not generated anymore).
+   *
+   * Note: "victim->name" is used instead of "user" because we may
+   *       have changed the target because of the nickname change.
+   */
+  sendto_op_mask(SNO_OPERKILL,
+                 "Received KILL message for %s. From %s Path: %s!%s",
+                 victim->name, parv[0], inpath, path);
+
+#if defined(SYSLOG_KILL)
+  ircd_log_kill(victim, sptr, inpath, path);
+#endif
+  /*
+   * 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(victim)) {
+    sendto_highprot_butone(cptr, 10, "%s%s " TOK_KILL " %s%s :%s!%s",
+                           NumNick(sptr), NumNick(victim), inpath, path);
+
+   /*
+    * 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)
+    */
+    victim->flags |= FLAGS_KILLED;
+
+    sprintf_irc(buf, "Killed by %s (%s)", sptr->name, comment);
+  }
+  else {
+  /*
+   * Tell the victim she/he has been zapped, but *only* if
+   * the victim is on current server--no sense in sending the
+   * notification chasing the above kill, it won't get far
+   * anyway (as this user don't exist there any more either)
+   */
+    sendto_prefix_one(victim, sptr, ":%s KILL %s :%s!%s",
+                      parv[0], victim->name, inpath, path);
+    sprintf_irc(buf, "Local kill by %s (%s)", sptr->name, comment);
+  }
+
+  return exit_client(cptr, victim, sptr, buf);
+
+#else /* !defined(OPER_KILL) */
+
+  return send_error_to_client(sptr, ERR_NOPRIVILEGES);
+
+#endif /* !defined(OPER_KILL) */
+}
+
+#if 0
+/*
+ * m_kill
+ *
+ * parv[0] = sender prefix
+ * parv[1] = kill victim
+ * parv[parc-1] = kill path
+ */
+int m_kill(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client* acptr;
+  const char*    inpath = get_client_name(cptr, HIDE_IP);
+  char*          user;
+  char*          path;
+  char*          killer;
+  int            chasing = 0;
+  char           buf[BUFSIZE];
+  char           buf2[BUFSIZE];
+
+  if (parc < 3 || *parv[1] == '\0')
+    return need_more_params(sptr, parv[0], "KILL");
+
+  user = parv[1];
+  path = parv[parc - 1];        /* Either defined or NULL (parc >= 3) */
+
+#ifdef        OPER_KILL
+  if (!IsPrivileged(cptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+#else
+  if (!IsServer(cptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+#endif
+  if (IsAnOper(cptr))
+  {
+    if (EmptyString(path))
+      return need_more_params(sptr, parv[0], "KILL");
+
+    if (strlen(path) > (size_t)TOPICLEN)
+      path[TOPICLEN] = '\0';
+  }
+
+  if (MyUser(sptr))
+  {
+    if (!(acptr = FindClient(user)))
+    {
+      /*
+       * If the user has recently changed nick, we automaticly
+       * rewrite the KILL for this new nickname--this keeps
+       * servers in synch when nick change and kill collide
+       */
+      if (!(acptr = get_history(user, (long)15)))
+      {
+        sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], user);
+        return 0;
+      }
+      sendto_one(sptr, ":%s NOTICE %s :Changed KILL %s into %s",
+          me.name, parv[0], user, acptr->name);
+      chasing = 1;
+    }
+  }
+  else if (!(acptr = findNUser(user)))
+  {
+    if (IsUser(sptr))
+      sendto_one(sptr,
+          "%s NOTICE %s%s :KILL target disconnected before I got him :(",
+          NumServ(&me), NumNick(sptr));
+    return 0;
+  }
+  if (!MyConnect(acptr) && IsLocOp(cptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  if (IsServer(acptr) || IsMe(acptr))
+  {
+    sendto_one(sptr, err_str(ERR_CANTKILLSERVER), me.name, parv[0]);
+    return 0;
+  }
+
+  /* if the user is +k, prevent a kill from local user */
+  if (IsChannelService(acptr) && MyUser(sptr))
+  {
+    sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
+        parv[0], "KILL", acptr->name);
+    return 0;
+  }
+
+#ifdef        LOCAL_KILL_ONLY
+  if (MyConnect(sptr) && !MyConnect(acptr))
+  {
+    sendto_one(sptr, ":%s NOTICE %s :Nick %s isnt on your server",
+        me.name, parv[0], acptr->name);
+    return 0;
+  }
+#endif
+  if (!IsServer(cptr))
+  {
+    /*
+     * The kill originates from this server, initialize path.
+     * (In which case the 'path' may contain user suplied
+     * explanation ...or some nasty comment, sigh... >;-)
+     *
+     * ...!operhost!oper
+     * ...!operhost!oper (comment)
+     */
+    inpath = cptr->sockhost;
+
+    if (!EmptyString(path))
+    {
+      sprintf_irc(buf,
+          "%s%s (%s)", cptr->name, IsOper(sptr) ? "" : "(L)", path);
+      path = buf;
+    }
+    else
+      path = cptr->name;
+  }
+  else if (EmptyString(path))
+    path = "*no-path*";                /* Bogus server sending??? */
+  /*
+   * Notify all *local* opers about the KILL (this includes the one
+   * originating the kill, if from this server--the special numeric
+   * reply message is not generated anymore).
+   *
+   * Note: "acptr->name" is used instead of "user" because we may
+   *       have changed the target because of the nickname change.
+   */
+  if (IsLocOp(sptr) && !MyConnect(acptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  sendto_op_mask(IsServer(sptr) ? SNO_SERVKILL : SNO_OPERKILL,
+      "Received KILL message for %s. From %s Path: %s!%s",
+      acptr->name, parv[0], inpath, path);
+#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
+  if (MyUser(acptr))
+  {                                /* get more infos when your local
+                                   clients are killed -- _dl */
+    if (IsServer(sptr))
+      ircd_log(L_TRACE,
+          "A local client %s!%s@%s KILLED from %s [%s] Path: %s!%s)",
+          acptr->name, acptr->user->username, acptr->user->host,
+          parv[0], sptr->name, inpath, path);
+    else
+      ircd_log(L_TRACE,
+          "A local client %s!%s@%s KILLED by %s [%s!%s@%s] (%s!%s)",
+          acptr->name, acptr->user->username, acptr->user->host,
+          parv[0], sptr->name, sptr->user->username, sptr->user->host,
+          inpath, path);
+  }
+  else if (IsOper(sptr))
+    ircd_log(L_TRACE, "KILL From %s For %s Path %s!%s",
+        parv[0], acptr->name, inpath, path);
+#endif
+  /*
+   * 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(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
+  {
+    sendto_highprot_butone(cptr, 10, ":%s " TOK_KILL " %s%s :%s!%s",
+        parv[0], NumNick(acptr), inpath, path);
+    /* We *can* have crossed a NICK with this numeric... --Run */
+    /* Note the following situation:
+     *  KILL SAA -->       X
+     *  <-- S NICK ... SAA | <-- SAA QUIT <-- S NICK ... SAA <-- SQUIT S
+     * Where the KILL reaches point X before the QUIT does.
+     * This would then *still* cause an orphan because the KILL doesn't reach S
+     * (because of the SQUIT), the QUIT is ignored (because of the KILL)
+     * and the second NICK ... SAA causes an orphan on the server at the
+     * right (which then isn't removed when the SQUIT arrives).
+     * Therefore we still need to detect numeric nick collisions too.
+     */
+    if (MyConnect(acptr) && IsServer(cptr))
+      sendto_one(cptr, "%s " TOK_KILL " %s%s :%s!%s (Ghost5)",
+          NumServ(&me), NumNick(acptr), inpath, path);
+    acptr->flags |= FLAGS_KILLED;
+  }
+
+  /*
+   * Tell the victim she/he has been zapped, but *only* if
+   * the victim is on current server--no sense in sending the
+   * notification chasing the above kill, it won't get far
+   * anyway (as this user don't exist there any more either)
+   */
+  if (MyConnect(acptr))
+    sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s",
+        parv[0], acptr->name, inpath, path);
+  /*
+   * 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)
+   */
+  if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
+    sprintf_irc(buf2, "Local kill by %s (%s)", sptr->name,
+        EmptyString(parv[parc - 1]) ? sptr->name : parv[parc - 1]);
+  else
+  {
+    if ((killer = strchr(path, ' ')))
+    {
+      while (*killer && *killer != '!')
+        killer--;
+      if (!*killer)
+        killer = path;
+      else
+        killer++;
+    }
+    else
+      killer = path;
+    sprintf_irc(buf2, "Killed (%s)", killer);
+  }
+  return exit_client(cptr, acptr, sptr, buf2);
+}
+
+#endif /* 0 */
+
diff --git a/ircd/m_links.c b/ircd/m_links.c
new file mode 100644 (file)
index 0000000..fb4273a
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_links.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+#include <assert.h>
+
+/*
+ * m_links - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ *
+ * or
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+int m_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;
+  struct Client *acptr;
+
+  if (parc > 2)
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s LINKS %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    mask = parv[2];
+  }
+  else
+    mask = parc < 2 ? 0 : parv[1];
+
+  for (acptr = GlobalClientList, collapse(mask); acptr; acptr = acptr->next)
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (!BadPtr(mask) && match(mask, acptr->name))
+      continue;
+    sendto_one(sptr, rpl_str(RPL_LINKS),
+        me.name, parv[0], acptr->name, acptr->serv->up->name,
+#ifndef GODMODE
+        acptr->hopcount, acptr->serv->prot,
+#else /* GODMODE */
+        acptr->hopcount, acptr->serv->prot, acptr->serv->timestamp,
+        NumServ(acptr),
+#endif /* GODMODE */
+        (acptr->info[0] ? acptr->info : "(Unknown Location)"));
+  }
+
+  sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
+      BadPtr(mask) ? "*" : mask);
+  return 0;
+}
+
+/*
+ * ms_links - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ *
+ * or
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+int ms_links(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;
+  struct Client *acptr;
+
+  if (parc > 2)
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s LINKS %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    mask = parv[2];
+  }
+  else
+    mask = parc < 2 ? 0 : parv[1];
+
+  for (acptr = GlobalClientList, collapse(mask); acptr; acptr = acptr->next)
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (!BadPtr(mask) && match(mask, acptr->name))
+      continue;
+    sendto_one(sptr, rpl_str(RPL_LINKS),
+        me.name, parv[0], acptr->name, acptr->serv->up->name,
+#ifndef GODMODE
+        acptr->hopcount, acptr->serv->prot,
+#else /* GODMODE */
+        acptr->hopcount, acptr->serv->prot, acptr->serv->timestamp,
+        NumServ(acptr),
+#endif /* GODMODE */
+        (acptr->info[0] ? acptr->info : "(Unknown Location)"));
+  }
+
+  sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
+      BadPtr(mask) ? "*" : mask);
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_links
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername mask
+ *
+ * or
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server to query
+ * parv[2] = servername mask
+ */
+int m_links(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *mask;
+  struct Client *acptr;
+
+  if (parc > 2)
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s LINKS %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    mask = parv[2];
+  }
+  else
+    mask = parc < 2 ? 0 : parv[1];
+
+  for (acptr = GlobalClientList, collapse(mask); acptr; acptr = acptr->next)
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (!BadPtr(mask) && match(mask, acptr->name))
+      continue;
+    sendto_one(sptr, rpl_str(RPL_LINKS),
+        me.name, parv[0], acptr->name, acptr->serv->up->name,
+#ifndef GODMODE
+        acptr->hopcount, acptr->serv->prot,
+#else /* GODMODE */
+        acptr->hopcount, acptr->serv->prot, acptr->serv->timestamp,
+        NumServ(acptr),
+#endif /* GODMODE */
+        (acptr->info[0] ? acptr->info : "(Unknown Location)"));
+  }
+
+  sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
+      BadPtr(mask) ? "*" : mask);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_list.c b/ircd/m_list.c
new file mode 100644 (file)
index 0000000..0b9ccf7
--- /dev/null
@@ -0,0 +1,550 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_list.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_list - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel list or user/time limit
+ * parv[2...] = more user/time limits
+ */
+int m_list(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *name, *p = 0;
+  int show_usage = 0, show_channels = 0, param;
+  struct ListingArgs args = {
+    2147483647,                 /* max_time */
+    0,                          /* min_time */
+    4294967295U,                /* max_users */
+    0,                          /* min_users */
+    0,                          /* topic_limits */
+    2147483647,                 /* max_topic_time */
+    0,                          /* min_topic_time */
+    0                        /* chptr */
+  };
+
+  if (sptr->listing)            /* Already listing ? */
+  {
+    sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
+    MyFree(sptr->listing);
+    sptr->listing = 0;
+    sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
+    if (parc < 2)
+      return 0;                 /* Let LIST abort a listing. */
+  }
+
+  if (parc < 2)                 /* No arguments given to /LIST ? */
+  {
+#ifdef DEFAULT_LIST_PARAM
+    static char *defparv[MAXPARA + 1];
+    static int defparc = 0;
+    static char lp[] = DEFAULT_LIST_PARAM;
+    int i;
+
+    /*
+     * XXX - strtok used
+     */
+    if (!defparc)
+    {
+      char *s = lp, *t;
+
+      defparc = 1;
+      defparv[defparc++] = t = strtok(s, " ");
+      while (t && defparc < MAXPARA)
+      {
+        if ((t = strtok(0, " ")))
+          defparv[defparc++] = t;
+      }
+    }
+    for (i = 1; i < defparc; i++)
+      parv[i] = defparv[i];
+    parv[i] = 0;
+    parc = defparc;
+#endif /* DEFAULT_LIST_PARAM */
+  }
+
+  /* Decode command */
+  for (param = 1; !show_usage && parv[param]; param++)
+  {
+    char *p = parv[param];
+    do
+    {
+      int is_time = 0;
+      switch (*p)
+      {
+        case 'T':
+        case 't':
+          is_time++;
+          args.topic_limits = 1;
+          /* Fall through */
+        case 'C':
+        case 'c':
+          is_time++;
+          p++;
+          if (*p != '<' && *p != '>')
+          {
+            show_usage = 1;
+            break;
+          }
+          /* Fall through */
+        case '<':
+        case '>':
+        {
+          p++;
+          if (!IsDigit(*p))
+            show_usage = 1;
+          else
+          {
+            if (is_time)
+            {
+              time_t val = atoi(p);
+              if (p[-1] == '<')
+              {
+                if (val < 80000000)     /* Toggle UTC/offset */
+                {
+                  /*
+                   * Demands that
+                   * 'TStime() - chptr->creationtime < val * 60'
+                   * Which equals
+                   * 'chptr->creationtime > TStime() - val * 60'
+                   */
+                  if (is_time == 1)
+                    args.min_time = TStime() - val * 60;
+                  else
+                    args.min_topic_time = TStime() - val * 60;
+                }
+                else if (is_time == 1)  /* Creation time in UTC was entered */
+                  args.max_time = val;
+                else            /* Topic time in UTC was entered */
+                  args.max_topic_time = val;
+              }
+              else if (val < 80000000)
+              {
+                if (is_time == 1)
+                  args.max_time = TStime() - val * 60;
+                else
+                  args.max_topic_time = TStime() - val * 60;
+              }
+              else if (is_time == 1)
+                args.min_time = val;
+              else
+                args.min_topic_time = val;
+            }
+            else if (p[-1] == '<')
+              args.max_users = atoi(p);
+            else
+              args.min_users = atoi(p);
+            if ((p = strchr(p, ',')))
+              p++;
+          }
+          break;
+        }
+        default:
+          if (!IsChannelName(p))
+          {
+            show_usage = 1;
+            break;
+          }
+          if (parc != 2)        /* Don't allow a mixture of channels with <,> */
+            show_usage = 1;
+          show_channels = 1;
+          p = 0;
+          break;
+      }
+    }
+    while (!show_usage && p);   /* p points after comma, or is NULL */
+  }
+
+  if (show_usage)
+  {
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        "Usage: \002/QUOTE LIST\002 \037parameters\037");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        "Where \037parameters\037 is a space or comma seperated "
+        "list of one or more of:");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002<\002\037max_users\037    ; Show all channels with less "
+        "than \037max_users\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002>\002\037min_users\037    ; Show all channels with more "
+        "than \037min_users\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002C<\002\037max_minutes\037 ; Channels that exist less "
+        "than \037max_minutes\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002C>\002\037min_minutes\037 ; Channels that exist more "
+        "than \037min_minutes\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002T<\002\037max_minutes\037 ; Channels with a topic last "
+        "set less than \037max_minutes\037 ago.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002T>\002\037min_minutes\037 ; Channels with a topic last "
+        "set more than \037min_minutes\037 ago.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        "Example: LIST <3,>1,C<10,T>0  ; 2 users, younger than 10 min., "
+        "topic set.");
+    return 0;
+  }
+
+  sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
+
+  if (!show_channels)
+  {
+    if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
+        args.max_topic_time > args.min_topic_time)      /* Sanity check */
+    {
+      sptr->listing = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
+      assert(0 != sptr->listing);
+      memcpy(sptr->listing, &args, sizeof(struct ListingArgs));
+      if ((sptr->listing->chptr = GlobalChannelList)) {
+        int m = GlobalChannelList->mode.mode & MODE_LISTED;
+        list_next_channels(sptr, 64);
+        GlobalChannelList->mode.mode |= m;
+        return 0;
+      }
+      MyFree(sptr->listing);
+      sptr->listing = 0;
+    }
+    sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+    return 0;
+  }
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = FindChannel(name);
+    if (chptr && ShowChannel(sptr, chptr) && sptr->user)
+      sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
+          chptr->chname,
+          chptr->users - number_of_zombies(chptr), chptr->topic);
+  }
+
+  sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_list
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel list or user/time limit
+ * parv[2...] = more user/time limits
+ */
+int m_list(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr;
+  char *name, *p = 0;
+  int show_usage = 0, show_channels = 0, param;
+  struct ListingArgs args = {
+    2147483647,                 /* max_time */
+    0,                          /* min_time */
+    4294967295U,                /* max_users */
+    0,                          /* min_users */
+    0,                          /* topic_limits */
+    2147483647,                 /* max_topic_time */
+    0,                          /* min_topic_time */
+    0                        /* chptr */
+  };
+
+  if (sptr->listing)            /* Already listing ? */
+  {
+    sptr->listing->chptr->mode.mode &= ~MODE_LISTED;
+    MyFree(sptr->listing);
+    sptr->listing = 0;
+    sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, sptr->name);
+    if (parc < 2)
+      return 0;                 /* Let LIST abort a listing. */
+  }
+
+  if (parc < 2)                 /* No arguments given to /LIST ? */
+  {
+#ifdef DEFAULT_LIST_PARAM
+    static char *defparv[MAXPARA + 1];
+    static int defparc = 0;
+    static char lp[] = DEFAULT_LIST_PARAM;
+    int i;
+
+    if (!defparc)
+    {
+      char *s = lp, *t;
+
+      defparc = 1;
+      defparv[defparc++] = t = strtok(s, " ");
+      while (t && defparc < MAXPARA)
+      {
+        if ((t = strtok(0, " ")))
+          defparv[defparc++] = t;
+      }
+    }
+    for (i = 1; i < defparc; i++)
+      parv[i] = defparv[i];
+    parv[i] = 0;
+    parc = defparc;
+#endif /* DEFAULT_LIST_PARAM */
+  }
+
+  /* Decode command */
+  for (param = 1; !show_usage && parv[param]; param++)
+  {
+    char *p = parv[param];
+    do
+    {
+      int is_time = 0;
+      switch (*p)
+      {
+        case 'T':
+        case 't':
+          is_time++;
+          args.topic_limits = 1;
+          /* Fall through */
+        case 'C':
+        case 'c':
+          is_time++;
+          p++;
+          if (*p != '<' && *p != '>')
+          {
+            show_usage = 1;
+            break;
+          }
+          /* Fall through */
+        case '<':
+        case '>':
+        {
+          p++;
+          if (!IsDigit(*p))
+            show_usage = 1;
+          else
+          {
+            if (is_time)
+            {
+              time_t val = atoi(p);
+              if (p[-1] == '<')
+              {
+                if (val < 80000000)     /* Toggle UTC/offset */
+                {
+                  /*
+                   * Demands that
+                   * 'TStime() - chptr->creationtime < val * 60'
+                   * Which equals
+                   * 'chptr->creationtime > TStime() - val * 60'
+                   */
+                  if (is_time == 1)
+                    args.min_time = TStime() - val * 60;
+                  else
+                    args.min_topic_time = TStime() - val * 60;
+                }
+                else if (is_time == 1)  /* Creation time in UTC was entered */
+                  args.max_time = val;
+                else            /* Topic time in UTC was entered */
+                  args.max_topic_time = val;
+              }
+              else if (val < 80000000)
+              {
+                if (is_time == 1)
+                  args.max_time = TStime() - val * 60;
+                else
+                  args.max_topic_time = TStime() - val * 60;
+              }
+              else if (is_time == 1)
+                args.min_time = val;
+              else
+                args.min_topic_time = val;
+            }
+            else if (p[-1] == '<')
+              args.max_users = atoi(p);
+            else
+              args.min_users = atoi(p);
+            if ((p = strchr(p, ',')))
+              p++;
+          }
+          break;
+        }
+        default:
+          if (!IsChannelName(p))
+          {
+            show_usage = 1;
+            break;
+          }
+          if (parc != 2)        /* Don't allow a mixture of channels with <,> */
+            show_usage = 1;
+          show_channels = 1;
+          p = 0;
+          break;
+      }
+    }
+    while (!show_usage && p);   /* p points after comma, or is NULL */
+  }
+
+  if (show_usage)
+  {
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        "Usage: \002/QUOTE LIST\002 \037parameters\037");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        "Where \037parameters\037 is a space or comma seperated "
+        "list of one or more of:");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002<\002\037max_users\037    ; Show all channels with less "
+        "than \037max_users\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002>\002\037min_users\037    ; Show all channels with more "
+        "than \037min_users\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002C<\002\037max_minutes\037 ; Channels that exist less "
+        "than \037max_minutes\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002C>\002\037min_minutes\037 ; Channels that exist more "
+        "than \037min_minutes\037.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002T<\002\037max_minutes\037 ; Channels with a topic last "
+        "set less than \037max_minutes\037 ago.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        " \002T>\002\037min_minutes\037 ; Channels with a topic last "
+        "set more than \037min_minutes\037 ago.");
+    sendto_one(sptr, rpl_str(RPL_LISTUSAGE), me.name, parv[0],
+        "Example: LIST <3,>1,C<10,T>0  ; 2 users, younger than 10 min., "
+        "topic set.");
+    return 0;
+  }
+
+  sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, parv[0]);
+
+  if (!show_channels)
+  {
+    if (args.max_users > args.min_users + 1 && args.max_time > args.min_time &&
+        args.max_topic_time > args.min_topic_time)      /* Sanity check */
+    {
+      sptr->listing = (struct ListingArgs*) MyMalloc(sizeof(struct ListingArgs));
+      assert(0 != sptr->listing);
+      memcpy(sptr->listing, &args, sizeof(struct ListingArgs));
+      if ((sptr->listing->chptr = GlobalChannelList)) {
+        int m = GlobalChannelList->mode.mode & MODE_LISTED;
+        list_next_channels(sptr, 64);
+        GlobalChannelList->mode.mode |= m;
+        return 0;
+      }
+      MyFree(sptr->listing);
+      sptr->listing = 0;
+    }
+    sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+    return 0;
+  }
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = FindChannel(name);
+    if (chptr && ShowChannel(sptr, chptr) && sptr->user)
+      sendto_one(sptr, rpl_str(RPL_LIST), me.name, parv[0],
+          ShowChannel(sptr, chptr) ? chptr->chname : "*",
+          chptr->users - number_of_zombies(chptr), chptr->topic);
+  }
+
+  sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, parv[0]);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_lusers.c b/ircd/m_lusers.c
new file mode 100644 (file)
index 0000000..ebf6751
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_lusers.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_user.h"
+#include "s_serv.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_lusers - generic message handler
+ *
+ * parv[0] = sender
+ * parv[1] = ignored
+ * parv[2] = server to query
+ */
+int m_lusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int longoutput = MyUser(sptr) || IsOper(sptr);
+  if (parc > 2)
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_LUSERS " %s :%s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+
+  sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
+      UserStats.clients - UserStats.inv_clients, UserStats.inv_clients, UserStats.servers);
+  if (longoutput && UserStats.opers)
+    sendto_one(sptr, rpl_str(RPL_LUSEROP), me.name, parv[0], UserStats.opers);
+  if (UserStats.unknowns > 0)
+    sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN), me.name, parv[0],
+        UserStats.unknowns);
+  if (longoutput && UserStats.channels > 0)
+    sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS), me.name, parv[0],
+        UserStats.channels);
+  sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, parv[0], UserStats.local_clients,
+      UserStats.local_servers);
+
+  if (MyUser(sptr) || Protocol(cptr) < 10)
+    sendto_one(sptr,
+        ":%s NOTICE %s :Highest connection count: %d (%d clients)",
+        me.name, parv[0], max_connection_count, max_client_count);
+  else
+    sendto_one(sptr,
+        "%s NOTICE %s%s :Highest connection count: %d (%d clients)",
+        NumServ(&me), NumNick(sptr), max_connection_count, max_client_count);
+
+  return 0;
+}
+
+/*
+ * ms_lusers - server message handler
+ *
+ * parv[0] = sender
+ * parv[1] = ignored
+ * parv[2] = server to query
+ */
+int ms_lusers(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int longoutput = MyUser(sptr) || IsOper(sptr);
+  if (parc > 2)
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_LUSERS " %s :%s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+
+  sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
+      UserStats.clients - UserStats.inv_clients, UserStats.inv_clients, UserStats.servers);
+  if (longoutput && UserStats.opers)
+    sendto_one(sptr, rpl_str(RPL_LUSEROP), me.name, parv[0], UserStats.opers);
+  if (UserStats.unknowns > 0)
+    sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN), me.name, parv[0],
+        UserStats.unknowns);
+  if (longoutput && UserStats.channels > 0)
+    sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS), me.name, parv[0],
+        UserStats.channels);
+  sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, parv[0], UserStats.local_clients,
+      UserStats.local_servers);
+
+  if (MyUser(sptr) || Protocol(cptr) < 10)
+    sendto_one(sptr,
+        ":%s NOTICE %s :Highest connection count: %d (%d clients)",
+        me.name, parv[0], max_connection_count, max_client_count);
+  else
+    sendto_one(sptr,
+        "%s NOTICE %s%s :Highest connection count: %d (%d clients)",
+        NumServ(&me), NumNick(sptr), max_connection_count, max_client_count);
+
+  return 0;
+}
+
+  
+#if 0
+/*
+ * m_lusers
+ *
+ * parv[0] = sender
+ * parv[1] = ignored
+ * parv[2] = server to query
+ */
+int m_lusers(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  int longoutput = MyUser(sptr) || IsOper(sptr);
+  if (parc > 2)
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_LUSERS " %s :%s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+
+  sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
+      UserStats.clients - UserStats.inv_clients, UserStats.inv_clients, UserStats.servers);
+  if (longoutput && UserStats.opers)
+    sendto_one(sptr, rpl_str(RPL_LUSEROP), me.name, parv[0], UserStats.opers);
+  if (UserStats.unknowns > 0)
+    sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN), me.name, parv[0],
+        UserStats.unknowns);
+  if (longoutput && UserStats.channels > 0)
+    sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS), me.name, parv[0],
+        UserStats.channels);
+  sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, parv[0], UserStats.local_clients,
+      UserStats.local_servers);
+
+  if (MyUser(sptr) || Protocol(cptr) < 10)
+    sendto_one(sptr,
+        ":%s NOTICE %s :Highest connection count: %d (%d clients)",
+        me.name, parv[0], max_connection_count, max_client_count);
+  else
+    sendto_one(sptr,
+        "%s NOTICE %s%s :Highest connection count: %d (%d clients)",
+        NumServ(&me), NumNick(sptr), max_connection_count, max_client_count);
+
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_map.c b/ircd/m_map.c
new file mode 100644 (file)
index 0000000..16b55cb
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_map.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "map.h"
+#include "numeric.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_map - generic message handler
+ * -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server mask
+ */
+int m_map(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (parc < 2)
+    parv[1] = "*";
+
+  dump_map(sptr, &me, parv[1], 0);
+  sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]);
+
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_map  -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = server mask
+ */
+int m_map(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  if (parc < 2)
+    parv[1] = "*";
+
+  dump_map(sptr, &me, parv[1], 0);
+  sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]);
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_mode.c b/ircd/m_mode.c
new file mode 100644 (file)
index 0000000..8758e54
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_mode.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#include "handlers.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_mode - generic message handler
+ */
+int m_mode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int             badop;
+  int             sendts;
+  struct Channel* chptr = 0;
+  char modebuf[MODEBUFLEN];
+  char parabuf[MODEBUFLEN];
+  char nparabuf[MODEBUFLEN];
+
+
+  if (parc < 2)
+    return need_more_params(sptr, "MODE");
+
+  /*
+   * if local user, cleanup channel name, don't allow local channel operations
+   * for remote clients
+   */
+  if (MyUser(sptr))
+    clean_channelname(parv[1]);
+  else if (IsLocalChannel(parv[1]))
+    return 0;
+
+  /* 
+   * try to find the channel
+   */
+  if ('#' == *parv[1] || '&' == *parv[1])
+    chptr = FindChannel(parv[1]);
+  if (!chptr)
+    return set_user_mode(cptr, sptr, parc, parv);
+
+  sptr->flags &= ~FLAGS_TS8;
+  /*
+   * sending an error wasnt good, lets just send an empty mode reply..  poptix
+   */
+  if (IsModelessChannel(chptr->chname)) {
+    if (IsUser(sptr))
+      sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+                 chptr->chname, "+nt", "");
+    return 0;
+  }
+
+  if (parc < 3) {
+    /*
+     * no parameters, send channel modes
+     */
+    *modebuf = *parabuf = '\0';
+    modebuf[1] = '\0';
+    channel_modes(sptr, modebuf, parabuf, chptr);
+    sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+               chptr->chname, modebuf, parabuf);
+    sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
+               chptr->chname, chptr->creationtime);
+    return 0;
+  }
+
+  LocalChanOperMode = 0;
+
+  if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
+                          modebuf, parabuf, nparabuf, &badop))) {
+    sendto_one(sptr, err_str(find_channel_member(sptr, chptr) ? ERR_CHANOPRIVSNEEDED :
+        ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  if (badop >= 2)
+    send_hack_notice(cptr, sptr, parc, parv, badop, 1);
+
+  if (strlen(modebuf) > 1 || sendts > 0) {
+    if (badop != 2 && strlen(modebuf) > 1) {
+#ifdef OPER_MODE_LCHAN
+      if (LocalChanOperMode) {
+        sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s",
+                               me.name, chptr->chname, modebuf, parabuf);
+        sendto_op_mask(SNO_HACK4,"OPER MODE: %s MODE %s %s %s",
+                       sptr->name, chptr->chname, modebuf, parabuf);
+      }
+      else
+#endif
+      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
+          parv[0], chptr->chname, modebuf, parabuf);
+    }
+    if (IsLocalChannel(chptr->chname))
+      return 0;
+    /* We send a creationtime of 0, to mark it as a hack --Run */
+    if (IsServer(sptr) && (badop == 2 || sendts > 0)) {
+      if (*modebuf == '\0')
+        strcpy(modebuf, "+");
+      if (badop != 2) {
+        sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s " TIME_T_FMT,
+            NumServ(sptr), chptr->chname, modebuf, nparabuf,
+            (badop == 4) ? (time_t) 0 : chptr->creationtime);
+      }
+    }
+    else {
+      if (IsServer(sptr))
+         sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s",
+           NumServ(sptr), chptr->chname, modebuf, nparabuf);
+      else
+         sendto_highprot_butone(cptr, 10, "%s%s " TOK_MODE " %s %s %s",
+           NumNick(sptr), chptr->chname, modebuf, nparabuf);
+    }
+  }
+  return 0;
+}
+
+/*
+ * ms_mode - server message handler
+ */
+int ms_mode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int             badop;
+  int             sendts;
+  struct Channel* chptr = 0;
+  char modebuf[MODEBUFLEN];
+  char parabuf[MODEBUFLEN];
+  char nparabuf[MODEBUFLEN];
+
+  if (parc < 2)
+    return need_more_params(sptr, "MODE");
+
+  /*
+   * if local user, cleanup channel name, don't allow local channel operations
+   * for remote clients
+   */
+  if (MyUser(sptr))
+    clean_channelname(parv[1]);
+  else if (IsLocalChannel(parv[1]))
+    return 0;
+
+  /* 
+   * try to find the channel
+   */
+  if ('#' == *parv[1] || '&' == *parv[1])
+    chptr = FindChannel(parv[1]);
+  if (!chptr)
+    return set_user_mode(cptr, sptr, parc, parv);
+
+  sptr->flags &= ~FLAGS_TS8;
+  /*
+   * sending an error wasnt good, lets just send an empty mode reply..  poptix
+   */
+  if (IsModelessChannel(chptr->chname)) {
+    if (IsUser(sptr))
+      sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+                 chptr->chname, "+nt", "");
+    return 0;
+  }
+
+  if (parc < 3) {
+    /*
+     * no parameters, send channel modes
+     */
+    *modebuf = *parabuf = '\0';
+    modebuf[1] = '\0';
+    channel_modes(sptr, modebuf, parabuf, chptr);
+    sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+               chptr->chname, modebuf, parabuf);
+    sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
+               chptr->chname, chptr->creationtime);
+    return 0;
+  }
+
+  LocalChanOperMode = 0;
+
+  if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
+                          modebuf, parabuf, nparabuf, &badop))) {
+    sendto_one(sptr, err_str(find_channel_member(sptr, chptr) ? ERR_CHANOPRIVSNEEDED :
+        ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  if (badop >= 2)
+    send_hack_notice(cptr, sptr, parc, parv, badop, 1);
+
+  if (strlen(modebuf) > 1 || sendts > 0) {
+    if (badop != 2 && strlen(modebuf) > 1) {
+#ifdef OPER_MODE_LCHAN
+      if (LocalChanOperMode) {
+        sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s",
+                               me.name, chptr->chname, modebuf, parabuf);
+        sendto_op_mask(SNO_HACK4,"OPER MODE: %s MODE %s %s %s",
+                       me.name, chptr->chname, modebuf, parabuf);
+      }
+      else
+#endif
+      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
+          parv[0], chptr->chname, modebuf, parabuf);
+    }
+    if (IsLocalChannel(chptr->chname))
+      return 0;
+    /* We send a creationtime of 0, to mark it as a hack --Run */
+    if (IsServer(sptr) && (badop == 2 || sendts > 0)) {
+      if (*modebuf == '\0')
+        strcpy(modebuf, "+");
+      if (badop != 2) {
+        sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s " TIME_T_FMT,
+            NumServ(sptr), chptr->chname, modebuf, nparabuf,
+            (badop == 4) ? (time_t) 0 : chptr->creationtime);
+      }
+    }
+    else {
+      if (IsServer(sptr))
+         sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s",
+           NumServ(sptr), chptr->chname, modebuf, nparabuf);
+      else
+         sendto_highprot_butone(cptr, 10, "%s%s " TOK_MODE " %s %s %s",
+           NumNick(sptr), chptr->chname, modebuf, nparabuf);
+    }
+  }
+  return 0;
+}
+
+#if 0
+/*
+ * m_mode
+ * parv[0] - sender
+ * parv[1] - channel
+ */
+int m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  int             badop;
+  int             sendts;
+  struct Channel* chptr = 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "MODE");
+
+  /*
+   * if local user, cleanup channel name, don't allow local channel operations
+   * for remote clients
+   */
+  if (MyUser(sptr))
+    clean_channelname(parv[1]);
+  else if (IsLocalChannel(parv[1]))
+    return 0;
+
+  /* 
+   * try to find the channel
+   */
+  if ('#' == *parv[1] || '&' == *parv[1])
+    chptr = FindChannel(parv[1]);
+  if (!chptr)
+    return set_user_mode(cptr, sptr, parc, parv);
+
+  sptr->flags &= ~FLAGS_TS8;
+  /*
+   * sending an error wasnt good, lets just send an empty mode reply..  poptix
+   */
+  if (IsModelessChannel(chptr->chname)) {
+    if (IsUser(sptr))
+      sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+                 chptr->chname, "+nt", "");
+    return 0;
+  }
+
+  if (parc < 3) {
+    /*
+     * no parameters, send channel modes
+     */
+    *modebuf = *parabuf = '\0';
+    modebuf[1] = '\0';
+    channel_modes(sptr, modebuf, parabuf, chptr);
+    sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+               chptr->chname, modebuf, parabuf);
+    sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
+               chptr->chname, chptr->creationtime);
+    return 0;
+  }
+
+  LocalChanOperMode = 0;
+
+  if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
+                          modebuf, parabuf, nparabuf, &badop))) {
+    sendto_one(sptr, err_str(find_channel_member(sptr, chptr) ? ERR_CHANOPRIVSNEEDED :
+        ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
+    return 0;
+  }
+
+  if (badop >= 2)
+    send_hack_notice(cptr, sptr, parc, parv, badop, 1);
+
+  if (strlen(modebuf) > 1 || sendts > 0) {
+    if (badop != 2 && strlen(modebuf) > 1) {
+#ifdef OPER_MODE_LCHAN
+      if (LocalChanOperMode) {
+        sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s",
+                               me.name, chptr->chname, modebuf, parabuf);
+        sendto_op_mask(SNO_HACK4,"OPER MODE: %s MODE %s %s %s",
+                       me.name, chptr->chname, modebuf, parabuf);
+      }
+      else
+#endif
+      sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
+          parv[0], chptr->chname, modebuf, parabuf);
+    }
+    if (IsLocalChannel(chptr->chname))
+      return 0;
+    /* We send a creationtime of 0, to mark it as a hack --Run */
+    if (IsServer(sptr) && (badop == 2 || sendts > 0)) {
+      if (*modebuf == '\0')
+        strcpy(modebuf, "+");
+      if (badop != 2) {
+        sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s " TIME_T_FMT,
+            NumServ(sptr), chptr->chname, modebuf, nparabuf,
+            (badop == 4) ? (time_t) 0 : chptr->creationtime);
+      }
+    }
+    else {
+      if (IsServer(sptr))
+         sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s",
+           NumServ(sptr), chptr->chname, modebuf, nparabuf);
+      else
+         sendto_highprot_butone(cptr, 10, "%s%s " TOK_MODE " %s %s %s",
+           NumNick(sptr), chptr->chname, modebuf, nparabuf);
+    }
+  }
+  return 0;
+}
+
+#endif /* 0 */
diff --git a/ircd/m_motd.c b/ircd/m_motd.c
new file mode 100644 (file)
index 0000000..84ab253
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_motd.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_motd - generic message handler
+ *
+ * parv[0] - sender prefix
+ * parv[1] - servername
+ *
+ * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
+ * T line patch - display motd based on hostmask
+ * modified again 7 sep 97 by Ghostwolf with code and ideas 
+ * stolen from comstud & Xorath.  All motd files are read into
+ * memory in read_motd() in s_conf.c
+ *
+ * When NODEFAULTMOTD is defined, then it is possible that
+ * sptr == NULL, which means that this function is called from
+ * register_user.
+ */
+int m_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct tm *tm = &motd_tm;     /* Default: Most general case */
+  struct TRecord *ptr;
+  int count;
+  struct MotdItem *temp;
+
+#ifdef NODEFAULTMOTD
+  int no_motd;
+
+  if (sptr)
+  {
+    no_motd = 0;
+#endif
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_MOTD " %s", 1, parc,
+        parv) != HUNTED_ISME)
+      return 0;
+#ifdef NODEFAULTMOTD
+  }
+  else
+  {
+    sptr = cptr;
+    no_motd = 1;
+  }
+#endif
+
+  /*
+   * Find out if this is a remote query or if we have a T line for our hostname
+   */
+  if (IsServer(cptr))
+  {
+    tm = 0;                  /* Remote MOTD */
+    temp = rmotd;
+  }
+  else
+  {
+    for (ptr = tdata; ptr; ptr = ptr->next)
+    {
+      if (!match(ptr->hostmask, cptr->sockhost))
+        break;
+    }
+    if (ptr)
+    {
+      temp = ptr->tmotd;
+      tm = &ptr->tmotd_tm;
+    }
+    else
+      temp = motd;
+  }
+  if (temp == 0)
+  {
+    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
+    return 0;
+  }
+#ifdef NODEFAULTMOTD
+  if (!no_motd)
+  {
+#endif
+    if (tm)                     /* Not remote? */
+    {
+      sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+      sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
+          parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+          tm->tm_hour, tm->tm_min);
+      count = 100;
+    }
+    else
+      count = 3;
+    for (; temp; temp = temp->next)
+    {
+      sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line);
+      if (--count == 0)
+        break;
+    }
+#ifdef NODEFAULTMOTD
+  }
+  else
+  {
+    sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+    sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_MOTD, parv[0],
+        "\ 2Type /MOTD to read the AUP before continuing using this service.\ 2");
+    sendto_one(sptr,
+        ":%s %d %s :The message of the day was last changed: %d/%d/%d", me.name,
+        RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+  }
+#endif
+  sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+  return 0;
+}
+
+/*
+ * ms_motd - server message handler
+ *
+ * parv[0] - sender prefix
+ * parv[1] - servername
+ *
+ * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
+ * T line patch - display motd based on hostmask
+ * modified again 7 sep 97 by Ghostwolf with code and ideas 
+ * stolen from comstud & Xorath.  All motd files are read into
+ * memory in read_motd() in s_conf.c
+ *
+ * When NODEFAULTMOTD is defined, then it is possible that
+ * sptr == NULL, which means that this function is called from
+ * register_user.
+ */
+int ms_motd(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct tm *tm = &motd_tm;     /* Default: Most general case */
+  struct TRecord *ptr;
+  int count;
+  struct MotdItem *temp;
+
+#ifdef NODEFAULTMOTD
+  int no_motd;
+
+  if (sptr)
+  {
+    no_motd = 0;
+#endif
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_MOTD " %s", 1, parc,
+        parv) != HUNTED_ISME)
+      return 0;
+#ifdef NODEFAULTMOTD
+  }
+  else
+  {
+    sptr = cptr;
+    no_motd = 1;
+  }
+#endif
+
+  /*
+   * Find out if this is a remote query or if we have a T line for our hostname
+   */
+  if (IsServer(cptr))
+  {
+    tm = 0;                  /* Remote MOTD */
+    temp = rmotd;
+  }
+  else
+  {
+    for (ptr = tdata; ptr; ptr = ptr->next)
+    {
+      if (!match(ptr->hostmask, cptr->sockhost))
+        break;
+    }
+    if (ptr)
+    {
+      temp = ptr->tmotd;
+      tm = &ptr->tmotd_tm;
+    }
+    else
+      temp = motd;
+  }
+  if (temp == 0)
+  {
+    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
+    return 0;
+  }
+#ifdef NODEFAULTMOTD
+  if (!no_motd)
+  {
+#endif
+    if (tm)                     /* Not remote? */
+    {
+      sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+      sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
+          parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+          tm->tm_hour, tm->tm_min);
+      count = 100;
+    }
+    else
+      count = 3;
+    for (; temp; temp = temp->next)
+    {
+      sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line);
+      if (--count == 0)
+        break;
+    }
+#ifdef NODEFAULTMOTD
+  }
+  else
+  {
+    sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+    sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_MOTD, parv[0],
+        "\ 2Type /MOTD to read the AUP before continuing using this service.\ 2");
+    sendto_one(sptr,
+        ":%s %d %s :The message of the day was last changed: %d/%d/%d", me.name,
+        RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+  }
+#endif
+  sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+  return 0;
+}
+
+#if 0
+/*
+ * m_motd
+ *
+ * parv[0] - sender prefix
+ * parv[1] - servername
+ *
+ * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
+ * T line patch - display motd based on hostmask
+ * modified again 7 sep 97 by Ghostwolf with code and ideas 
+ * stolen from comstud & Xorath.  All motd files are read into
+ * memory in read_motd() in s_conf.c
+ *
+ * When NODEFAULTMOTD is defined, then it is possible that
+ * sptr == NULL, which means that this function is called from
+ * register_user.
+ */
+int m_motd(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct tm *tm = &motd_tm;     /* Default: Most general case */
+  struct TRecord *ptr;
+  int count;
+  struct MotdItem *temp;
+
+#ifdef NODEFAULTMOTD
+  int no_motd;
+
+  if (sptr)
+  {
+    no_motd = 0;
+#endif
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_MOTD " %s", 1, parc,
+        parv) != HUNTED_ISME)
+      return 0;
+#ifdef NODEFAULTMOTD
+  }
+  else
+  {
+    sptr = cptr;
+    no_motd = 1;
+  }
+#endif
+
+  /*
+   * Find out if this is a remote query or if we have a T line for our hostname
+   */
+  if (IsServer(cptr))
+  {
+    tm = 0;                  /* Remote MOTD */
+    temp = rmotd;
+  }
+  else
+  {
+    for (ptr = tdata; ptr; ptr = ptr->next)
+    {
+      if (!match(ptr->hostmask, cptr->sockhost))
+        break;
+    }
+    if (ptr)
+    {
+      temp = ptr->tmotd;
+      tm = &ptr->tmotd_tm;
+    }
+    else
+      temp = motd;
+  }
+  if (temp == 0)
+  {
+    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
+    return 0;
+  }
+#ifdef NODEFAULTMOTD
+  if (!no_motd)
+  {
+#endif
+    if (tm)                     /* Not remote? */
+    {
+      sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+      sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
+          parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+          tm->tm_hour, tm->tm_min);
+      count = 100;
+    }
+    else
+      count = 3;
+    for (; temp; temp = temp->next)
+    {
+      sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line);
+      if (--count == 0)
+        break;
+    }
+#ifdef NODEFAULTMOTD
+  }
+  else
+  {
+    sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+    sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_MOTD, parv[0],
+        "\ 2Type /MOTD to read the AUP before continuing using this service.\ 2");
+    sendto_one(sptr,
+        ":%s %d %s :The message of the day was last changed: %d/%d/%d", me.name,
+        RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
+  }
+#endif
+  sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_names.c b/ircd/m_names.c
new file mode 100644 (file)
index 0000000..160bbef
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_names.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * m_names - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ */
+int m_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  struct Client *c2ptr;
+  struct Membership* member;
+  struct Channel *ch2ptr = 0;
+  int idx, flag, len, mlen;
+  char *s, *para = parc > 1 ? parv[1] : 0;
+  char buf[BUFSIZE];
+
+  if (parc > 2 && hunt_server(1, cptr, sptr, "%s%s " TOK_NAMES " %s %s", 2, parc, parv))
+    return 0;
+
+  mlen = strlen(me.name) + 10 + strlen(sptr->name);
+
+  if (!EmptyString(para))
+  {
+    s = strchr(para, ',');
+    if (s)
+    {
+      parv[1] = ++s;
+      m_names(cptr, sptr, parc, parv);
+    }
+    clean_channelname(para);
+    ch2ptr = FindChannel(para);
+  }
+
+  /*
+   * First, do all visible channels (public and the one user self is)
+   */
+
+  for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
+  {
+    if ((chptr != ch2ptr) && !EmptyString(para))
+      continue;                 /* -- wanted a specific channel */
+    if (!MyConnect(sptr) && EmptyString(para))
+      continue;
+#ifndef GODMODE
+    if (!ShowChannel(sptr, chptr))
+      continue;                 /* -- users on this are not listed */
+#endif
+
+    /* Find users on same channel (defined by chptr) */
+
+    strcpy(buf, "* ");
+    len = strlen(chptr->chname);
+    strcpy(buf + 2, chptr->chname);
+    strcpy(buf + 2 + len, " :");
+
+    if (PubChannel(chptr))
+      *buf = '=';
+    else if (SecretChannel(chptr))
+      *buf = '@';
+    idx = len + 4;
+    flag = 1;
+    for (member = chptr->members; member; member = member->next_member)
+    {
+      c2ptr = member->user;
+#ifndef GODMODE
+      if (sptr != c2ptr && IsInvisible(c2ptr) && !find_channel_member(sptr, chptr))
+        continue;
+#endif
+      if (IsZombie(member))
+      {
+        if (member->user != sptr)
+          continue;
+        else
+        {
+          strcat(buf, "!");
+          idx++;
+        }
+      }
+      else if (IsChanOp(member))
+      {
+        strcat(buf, "@");
+        idx++;
+      }
+      else if (HasVoice(member))
+      {
+        strcat(buf, "+");
+        idx++;
+      }
+      strcat(buf, c2ptr->name);
+      strcat(buf, " ");
+      idx += strlen(c2ptr->name) + 1;
+      flag = 1;
+#ifdef GODMODE
+      {
+        char yxx[6];
+        sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
+        assert(c2ptr == findNUser(yxx));
+        sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
+        idx += 6;
+      }
+      if (mlen + idx + NICKLEN + 11 > BUFSIZE)
+#else
+      if (mlen + idx + NICKLEN + 5 > BUFSIZE)
+#endif
+        /* space, modifier, nick, \r \n \0 */
+      {
+        sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+        strcpy(buf, "* ");
+        ircd_strncpy(buf + 2, chptr->chname, len + 1);
+        buf[len + 2] = 0;
+        strcat(buf, " :");
+        if (PubChannel(chptr))
+          *buf = '=';
+        else if (SecretChannel(chptr))
+          *buf = '@';
+        idx = len + 4;
+        flag = 0;
+      }
+    }
+    if (flag)
+      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+  }
+  if (!EmptyString(para))
+  {
+    sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0],
+        ch2ptr ? ch2ptr->chname : para);
+    return (1);
+  }
+
+  /* Second, do all non-public, non-secret channels in one big sweep */
+
+  strcpy(buf, "* * :");
+  idx = 5;
+  flag = 0;
+  for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
+  {
+    struct Channel *ch3ptr;
+    int showflag = 0, secret = 0;
+
+#ifndef GODMODE
+    if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
+#else
+    if (!IsUser(c2ptr))
+#endif
+      continue;
+    member = c2ptr->user->channel;
+    /*
+     * Don't show a client if they are on a secret channel or when
+     * they are on a channel sptr is on since they have already
+     * been show earlier. -avalon
+     */
+    while (member)
+    {
+      ch3ptr = member->channel;
+#ifndef GODMODE
+      if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
+#endif
+        showflag = 1;
+      if (SecretChannel(ch3ptr))
+        secret = 1;
+      member = member->next_channel;
+    }
+    if (showflag)               /* Have we already shown them ? */
+      continue;
+#ifndef GODMODE
+    if (secret)                 /* On any secret channels ? */
+      continue;
+#endif
+    strcat(buf, c2ptr->name);
+    strcat(buf, " ");
+    idx += strlen(c2ptr->name) + 1;
+    flag = 1;
+#ifdef GODMODE
+    {
+      char yxx[6];
+      sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
+      assert(c2ptr == findNUser(yxx));
+      sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
+      idx += 6;
+    }
+#endif
+#ifdef GODMODE
+    if (mlen + idx + NICKLEN + 9 > BUFSIZE)
+#else
+    if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
+#endif
+    {
+      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+      strcpy(buf, "* * :");
+      idx = 5;
+      flag = 0;
+    }
+  }
+  if (flag)
+    sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+  sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
+  return 1;
+  return 0;
+}
+
+/*
+ * ms_names - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ */
+int ms_names(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  struct Client *c2ptr;
+  struct Membership* member;
+  struct Channel *ch2ptr = 0;
+  int idx, flag, len, mlen;
+  char *s, *para = parc > 1 ? parv[1] : 0;
+  char buf[BUFSIZE];
+
+  if (parc > 2 && hunt_server(1, cptr, sptr, "%s%s " TOK_NAMES " %s %s", 2, parc, parv))
+    return 0;
+
+  mlen = strlen(me.name) + 10 + strlen(sptr->name);
+
+  if (!EmptyString(para))
+  {
+    s = strchr(para, ',');
+    if (s)
+    {
+      parv[1] = ++s;
+      m_names(cptr, sptr, parc, parv);
+    }
+    clean_channelname(para);
+    ch2ptr = FindChannel(para);
+  }
+
+  /*
+   * First, do all visible channels (public and the one user self is)
+   */
+
+  for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
+  {
+    if ((chptr != ch2ptr) && !EmptyString(para))
+      continue;                 /* -- wanted a specific channel */
+    if (!MyConnect(sptr) && EmptyString(para))
+      continue;
+#ifndef GODMODE
+    if (!ShowChannel(sptr, chptr))
+      continue;                 /* -- users on this are not listed */
+#endif
+
+    /* Find users on same channel (defined by chptr) */
+
+    strcpy(buf, "* ");
+    len = strlen(chptr->chname);
+    strcpy(buf + 2, chptr->chname);
+    strcpy(buf + 2 + len, " :");
+
+    if (PubChannel(chptr))
+      *buf = '=';
+    else if (SecretChannel(chptr))
+      *buf = '@';
+    idx = len + 4;
+    flag = 1;
+    for (member = chptr->members; member; member = member->next_member)
+    {
+      c2ptr = member->user;
+#ifndef GODMODE
+      if (sptr != c2ptr && IsInvisible(c2ptr) && !find_channel_member(sptr, chptr))
+        continue;
+#endif
+      if (IsZombie(member))
+      {
+        if (member->user != sptr)
+          continue;
+        else
+        {
+          strcat(buf, "!");
+          idx++;
+        }
+      }
+      else if (IsChanOp(member))
+      {
+        strcat(buf, "@");
+        idx++;
+      }
+      else if (HasVoice(member))
+      {
+        strcat(buf, "+");
+        idx++;
+      }
+      strcat(buf, c2ptr->name);
+      strcat(buf, " ");
+      idx += strlen(c2ptr->name) + 1;
+      flag = 1;
+#ifdef GODMODE
+      {
+        char yxx[6];
+        sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
+        assert(c2ptr == findNUser(yxx));
+        sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
+        idx += 6;
+      }
+      if (mlen + idx + NICKLEN + 11 > BUFSIZE)
+#else
+      if (mlen + idx + NICKLEN + 5 > BUFSIZE)
+#endif
+        /* space, modifier, nick, \r \n \0 */
+      {
+        sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+        strcpy(buf, "* ");
+        ircd_strncpy(buf + 2, chptr->chname, len + 1);
+        buf[len + 2] = 0;
+        strcat(buf, " :");
+        if (PubChannel(chptr))
+          *buf = '=';
+        else if (SecretChannel(chptr))
+          *buf = '@';
+        idx = len + 4;
+        flag = 0;
+      }
+    }
+    if (flag)
+      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+  }
+  if (!EmptyString(para))
+  {
+    sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0],
+        ch2ptr ? ch2ptr->chname : para);
+    return (1);
+  }
+
+  /* Second, do all non-public, non-secret channels in one big sweep */
+
+  strcpy(buf, "* * :");
+  idx = 5;
+  flag = 0;
+  for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
+  {
+    struct Channel *ch3ptr;
+    int showflag = 0, secret = 0;
+
+#ifndef GODMODE
+    if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
+#else
+    if (!IsUser(c2ptr))
+#endif
+      continue;
+    member = c2ptr->user->channel;
+    /*
+     * Don't show a client if they are on a secret channel or when
+     * they are on a channel sptr is on since they have already
+     * been show earlier. -avalon
+     */
+    while (member)
+    {
+      ch3ptr = member->channel;
+#ifndef GODMODE
+      if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
+#endif
+        showflag = 1;
+      if (SecretChannel(ch3ptr))
+        secret = 1;
+      member = member->next_channel;
+    }
+    if (showflag)               /* Have we already shown them ? */
+      continue;
+#ifndef GODMODE
+    if (secret)                 /* On any secret channels ? */
+      continue;
+#endif
+    strcat(buf, c2ptr->name);
+    strcat(buf, " ");
+    idx += strlen(c2ptr->name) + 1;
+    flag = 1;
+#ifdef GODMODE
+    {
+      char yxx[6];
+      sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
+      assert(c2ptr == findNUser(yxx));
+      sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
+      idx += 6;
+    }
+#endif
+#ifdef GODMODE
+    if (mlen + idx + NICKLEN + 9 > BUFSIZE)
+#else
+    if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
+#endif
+    {
+      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+      strcpy(buf, "* * :");
+      idx = 5;
+      flag = 0;
+    }
+  }
+  if (flag)
+    sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+  sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
+  return 1;
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_names                              - Added by Jto 27 Apr 1989
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ */
+int m_names(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr;
+  struct Client *c2ptr;
+  struct Membership* member;
+  struct Channel *ch2ptr = 0;
+  int idx, flag, len, mlen;
+  char *s, *para = parc > 1 ? parv[1] : 0;
+  char buf[BUFSIZE];
+
+  if (parc > 2 && hunt_server(1, cptr, sptr, "%s%s " TOK_NAMES " %s %s", 2, parc, parv))
+    return 0;
+
+  mlen = strlen(me.name) + 10 + strlen(sptr->name);
+
+  if (!EmptyString(para))
+  {
+    s = strchr(para, ',');
+    if (s)
+    {
+      parv[1] = ++s;
+      m_names(cptr, sptr, parc, parv);
+    }
+    clean_channelname(para);
+    ch2ptr = FindChannel(para);
+  }
+
+  /*
+   * First, do all visible channels (public and the one user self is)
+   */
+
+  for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
+  {
+    if ((chptr != ch2ptr) && !EmptyString(para))
+      continue;                 /* -- wanted a specific channel */
+    if (!MyConnect(sptr) && EmptyString(para))
+      continue;
+#ifndef GODMODE
+    if (!ShowChannel(sptr, chptr))
+      continue;                 /* -- users on this are not listed */
+#endif
+
+    /* Find users on same channel (defined by chptr) */
+
+    strcpy(buf, "* ");
+    len = strlen(chptr->chname);
+    strcpy(buf + 2, chptr->chname);
+    strcpy(buf + 2 + len, " :");
+
+    if (PubChannel(chptr))
+      *buf = '=';
+    else if (SecretChannel(chptr))
+      *buf = '@';
+    idx = len + 4;
+    flag = 1;
+    for (member = chptr->members; member; member = member->next_member)
+    {
+      c2ptr = member->user;
+#ifndef GODMODE
+      if (sptr != c2ptr && IsInvisible(c2ptr) && !find_channel_member(sptr, chptr))
+        continue;
+#endif
+      if (IsZombie(member))
+      {
+        if (member->user != sptr)
+          continue;
+        else
+        {
+          strcat(buf, "!");
+          idx++;
+        }
+      }
+      else if (IsChanOp(member))
+      {
+        strcat(buf, "@");
+        idx++;
+      }
+      else if (HasVoice(member))
+      {
+        strcat(buf, "+");
+        idx++;
+      }
+      strcat(buf, c2ptr->name);
+      strcat(buf, " ");
+      idx += strlen(c2ptr->name) + 1;
+      flag = 1;
+#ifdef GODMODE
+      {
+        char yxx[6];
+        sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
+        assert(c2ptr == findNUser(yxx));
+        sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
+        idx += 6;
+      }
+      if (mlen + idx + NICKLEN + 11 > BUFSIZE)
+#else
+      if (mlen + idx + NICKLEN + 5 > BUFSIZE)
+#endif
+        /* space, modifier, nick, \r \n \0 */
+      {
+        sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+        strcpy(buf, "* ");
+        ircd_strncpy(buf + 2, chptr->chname, len + 1);
+        buf[len + 2] = 0;
+        strcat(buf, " :");
+        if (PubChannel(chptr))
+          *buf = '=';
+        else if (SecretChannel(chptr))
+          *buf = '@';
+        idx = len + 4;
+        flag = 0;
+      }
+    }
+    if (flag)
+      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+  }
+  if (!EmptyString(para))
+  {
+    sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0],
+        ch2ptr ? ch2ptr->chname : para);
+    return (1);
+  }
+
+  /* Second, do all non-public, non-secret channels in one big sweep */
+
+  strcpy(buf, "* * :");
+  idx = 5;
+  flag = 0;
+  for (c2ptr = GlobalClientList; c2ptr; c2ptr = c2ptr->next)
+  {
+    struct Channel *ch3ptr;
+    int showflag = 0, secret = 0;
+
+#ifndef GODMODE
+    if (!IsUser(c2ptr) || (sptr != c2ptr && IsInvisible(c2ptr)))
+#else
+    if (!IsUser(c2ptr))
+#endif
+      continue;
+    member = c2ptr->user->channel;
+    /*
+     * Don't show a client if they are on a secret channel or when
+     * they are on a channel sptr is on since they have already
+     * been show earlier. -avalon
+     */
+    while (member)
+    {
+      ch3ptr = member->channel;
+#ifndef GODMODE
+      if (PubChannel(ch3ptr) || find_channel_member(sptr, ch3ptr))
+#endif
+        showflag = 1;
+      if (SecretChannel(ch3ptr))
+        secret = 1;
+      member = member->next_channel;
+    }
+    if (showflag)               /* Have we already shown them ? */
+      continue;
+#ifndef GODMODE
+    if (secret)                 /* On any secret channels ? */
+      continue;
+#endif
+    strcat(buf, c2ptr->name);
+    strcat(buf, " ");
+    idx += strlen(c2ptr->name) + 1;
+    flag = 1;
+#ifdef GODMODE
+    {
+      char yxx[6];
+      sprintf_irc(yxx, "%s%s", NumNick(c2ptr));
+      assert(c2ptr == findNUser(yxx));
+      sprintf_irc(buf + strlen(buf), "(%s) ", yxx);
+      idx += 6;
+    }
+#endif
+#ifdef GODMODE
+    if (mlen + idx + NICKLEN + 9 > BUFSIZE)
+#else
+    if (mlen + idx + NICKLEN + 3 > BUFSIZE)     /* space, \r\n\0 */
+#endif
+    {
+      sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+      strcpy(buf, "* * :");
+      idx = 5;
+      flag = 0;
+    }
+  }
+  if (flag)
+    sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+  sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
+  return 1;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_nick.c b/ircd/m_nick.c
new file mode 100644 (file)
index 0000000..875a8a1
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_nick.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "IPcheck.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_nick - message handler for local clients
+ * parv[0] = sender prefix
+ * parv[1] = nickname
+ */
+int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char           nick[NICKLEN + 2];
+  char*          arg;
+  char*          s;
+  const char*    client_name;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  /*
+   * parv[0] will be empty for clients connecting for the first time
+   */
+  client_name = (*sptr->name) ? sptr->name : "*";
+
+  if (parc < 2) {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, client_name);
+    return 0;
+  }
+  /*
+   * Don't let them send make us send back a really long string of
+   * garbage
+   */
+  arg = parv[1];
+  if (strlen(arg) > NICKLEN)
+    arg[NICKLEN] = '\0';
+
+  if ((s = strchr(arg, '~')))
+    *s = '\0';
+
+  strcpy(nick, arg);
+
+  /*
+   * If do_nick_name() returns a null name OR if the server sent a nick
+   * name and do_nick_name() changed it in some way (due to rules of nick
+   * creation) then reject it. If from a server and we reject it,
+   * and KILL it. -avalon 4/4/92
+   */
+  if (0 == do_nick_name(nick)) {
+    sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, client_name, arg);
+    return 0;
+  }
+
+  /* 
+   * Check if this is a LOCAL user trying to use a reserved (Juped)
+   * nick, if so tell him that it's a nick in use...
+   */
+  if (isNickJuped(nick)) {
+    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, client_name, nick);
+    return 0;                        /* NICK message ignored */
+  }
+
+  if (!(acptr = FindClient(nick))) {
+    /*
+     * No collisions, all clear...
+     */
+    return set_nick_name(cptr, sptr, nick, parc, parv);
+  }
+  if (IsServer(acptr)) {
+    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, client_name, nick);
+    return 0;                        /* NICK message ignored */
+  }
+  /*
+   * If acptr == sptr, then we have a client doing a nick
+   * change between *equivalent* nicknames as far as server
+   * is concerned (user is changing the case of his/her
+   * nickname or somesuch)
+   */
+  if (acptr == sptr) {
+    /*
+     * If acptr == sptr, then we have a client doing a nick
+     * change between *equivalent* nicknames as far as server
+     * is concerned (user is changing the case of his/her
+     * nickname or somesuch)
+     */
+    if (0 != strcmp(acptr->name, nick)) {
+      /*
+       * Allows change of case in his/her nick
+       */
+      return set_nick_name(cptr, sptr, nick, parc, parv);
+    }
+    /*
+     * This is just ':old NICK old' type thing.
+     * Just forget the whole thing here. There is
+     * no point forwarding it to anywhere,
+     * especially since servers prior to this
+     * version would treat it as nick collision.
+     */
+    return 0;
+  }
+  /*
+   * Note: From this point forward it can be assumed that
+   * acptr != sptr (point to different client structures).
+   */
+  assert(acptr != sptr);
+  /*
+   * If the older one is "non-person", the new entry is just
+   * allowed to overwrite it. Just silently drop non-person,
+   * and proceed with the nick. This should take care of the
+   * "dormant nick" way of generating collisions...
+   *
+   * XXX - hmmm can this happen after one is registered?
+   */
+  if (IsUnknown(acptr) && MyConnect(acptr)) {
+    ++ServerStats->is_ref;
+    IPcheck_connect_fail(acptr->ip);
+    exit_client(cptr, acptr, &me, "Overridden by other sign on");
+    return set_nick_name(cptr, sptr, nick, parc, parv);
+  }
+  /*
+   * NICK is coming from local client connection. Just
+   * send error reply and ignore the command.
+   */
+  sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, client_name, nick);
+  return 0;                        /* NICK message ignored */
+}
+
+
+/*
+ * ms_nick - server message handler for nicks
+ * parv[0] = sender prefix
+ * parv[1] = nickname
+ *
+ * If from server, source is client:
+ *   parv[2] = timestamp
+ *
+ * Source is server:
+ *   parv[2] = hopcount
+ *   parv[3] = timestamp
+ *   parv[4] = username
+ *   parv[5] = hostname
+ *   parv[6] = umode (optional)
+ *   parv[parc-3] = IP#                 <- Only Protocol >= 10
+ *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
+ *   parv[parc-1] = info
+ *   parv[0] = server
+ */
+int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char           nick[NICKLEN + 2];
+  time_t         lastnick = 0;
+  int            differ = 1;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if ((IsServer(sptr) && parc < 8) || parc < 3) {
+    sendto_ops("bad NICK param count for %s from %s", parv[1], cptr->name);
+    return need_more_params(sptr, "NICK");
+  }
+
+  ircd_strncpy(nick, parv[1], NICKLEN);
+  nick[NICKLEN] = '\0';
+
+  if (IsServer(sptr)) {
+    lastnick = atoi(parv[3]);
+    if (lastnick > OLDEST_TS) 
+      sptr->serv->lag = TStime() - lastnick;
+  }
+  else {
+    lastnick = atoi(parv[2]); 
+    if (lastnick > OLDEST_TS)
+      sptr->user->server->serv->lag = TStime() - lastnick;
+  }
+  /*
+   * If do_nick_name() returns a null name OR if the server sent a nick
+   * name and do_nick_name() changed it in some way (due to rules of nick
+   * creation) then reject it. If from a server and we reject it,
+   * and KILL it. -avalon 4/4/92
+   */
+  if (0 == do_nick_name(nick) || 0 != strcmp(nick, parv[1])) {
+    sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1]);
+
+    ++ServerStats->is_kill;
+    sendto_ops("Bad Nick: %s From: %s %s", parv[1], parv[0], cptr->name);
+    sendto_one(cptr, "%s " TOK_KILL " %s :%s (%s <- %s[%s])",
+               NumServ(&me), IsServer(sptr) ? parv[parc - 2] : parv[0], me.name,
+               parv[1], nick, cptr->name);
+    if (!IsServer(sptr)) {
+      /*
+       * bad nick _change_
+       */
+      sendto_highprot_butone(cptr, 10, "%s " TOK_KILL " %s :%s (%s <- %s!%s@%s)",
+                             NumServ(&me), parv[0], me.name, cptr->name,
+                             parv[0], sptr->user ? sptr->username : "",
+                             sptr->user ? sptr->user->server->name : cptr->name);
+    }
+    return 0;
+  }
+  /*
+   * Check against nick name collisions.
+   *
+   * Put this 'if' here so that the nesting goes nicely on the screen :)
+   * We check against server name list before determining if the nickname
+   * is present in the nicklist (due to the way the below for loop is
+   * constructed). -avalon
+   */
+  if (!(acptr = FindClient(nick))) {
+    /*
+     * No collisions, all clear...
+     */
+    return set_nick_name(cptr, sptr, nick, parc, parv);
+  }
+  assert(0 != acptr);
+
+  if (IsServer(acptr)) {
+    /*
+     * We have a nickname trying to use the same name as
+     * a server. Send out a nick collision KILL to remove
+     * the nickname. As long as only a KILL is sent out,
+     * there is no danger of the server being disconnected.
+     * Ultimate way to jupiter a nick ? >;-). -avalon
+     */
+    sendto_ops("Nick collision on %s(%s <- %s)", sptr->name, acptr->from->name, cptr->name);
+    ++ServerStats->is_kill;
+
+    sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (%s <- %s)",
+               NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
+               cptr->name);
+
+    sptr->flags |= FLAGS_KILLED;
+    /*
+     * if sptr is a server it is exited here, nothing else to do
+     */
+    return exit_client(cptr, sptr, &me, "Nick/Server collision");
+  }
+
+  /*
+   * If acptr == sptr, then we have a client doing a nick
+   * change between *equivalent* nicknames as far as server
+   * is concerned (user is changing the case of his/her
+   * nickname or somesuch)
+   */
+  if (acptr == sptr) {
+    if (strcmp(acptr->name, nick) != 0)
+      /*
+       * Allows change of case in his/her nick
+       */
+      return set_nick_name(cptr, sptr, nick, parc, parv);
+    else
+      /*
+       * This is just ':old NICK old' type thing.
+       * Just forget the whole thing here. There is
+       * no point forwarding it to anywhere,
+       * especially since servers prior to this
+       * version would treat it as nick collision.
+       */
+      return 0;                        /* NICK Message ignored */
+  }
+
+  /*
+   * Note: From this point forward it can be assumed that
+   * acptr != sptr (point to different client structures).
+   */
+  assert(acptr != sptr);
+  /*
+   * If the older one is "non-person", the new entry is just
+   * allowed to overwrite it. Just silently drop non-person,
+   * and proceed with the nick. This should take care of the
+   * "dormant nick" way of generating collisions...
+   */
+  if (IsUnknown(acptr) && MyConnect(acptr)) {
+    ++ServerStats->is_ref;
+    IPcheck_connect_fail(acptr->ip);
+    exit_client(cptr, acptr, &me, "Overridden by other sign on");
+    return set_nick_name(cptr, sptr, nick, parc, parv);
+  }
+  /*
+   * Decide, we really have a nick collision and deal with it
+   */
+  /*
+   * NICK was coming from a server connection.
+   * This means we have a race condition (two users signing on
+   * at the same time), or two net fragments reconnecting with the same nick.
+   * The latter can happen because two different users connected
+   * or because one and the same user switched server during a net break.
+   * If the TimeStamps are equal, we kill both (or only 'new'
+   * if it was a ":server NICK new ...").
+   * Otherwise we kill the youngest when user@host differ,
+   * or the oldest when they are the same.
+   * We treat user and ~user as different, because if it wasn't
+   * a faked ~user the AUTH wouldn't have added the '~'.
+   * --Run
+   *
+   */
+  if (IsServer(sptr)) {
+    /*
+     * A new NICK being introduced by a neighbouring
+     * server (e.g. message type ":server NICK new ..." received)
+     *
+     * compare IP address and username
+     */
+    differ =  (acptr->ip.s_addr != htonl(base64toint(parv[parc - 3]))) ||
+              (0 != ircd_strcmp(acptr->user->username, parv[4]));
+    sendto_ops("Nick collision on %s (%s " TIME_T_FMT " <- %s " TIME_T_FMT
+               " (%s user@host))", acptr->name, acptr->from->name, acptr->lastnick,
+               cptr->name, lastnick, differ ? "Different" : "Same");
+  }
+  else {
+    /*
+     * A NICK change has collided (e.g. message type ":old NICK new").
+     *
+     * compare IP address and username
+     */
+    differ =  (acptr->ip.s_addr != sptr->ip.s_addr) ||
+              (0 != ircd_strcmp(acptr->user->username, sptr->user->username));              
+    sendto_ops("Nick change collision from %s to %s (%s " TIME_T_FMT " <- %s "
+               TIME_T_FMT ")", sptr->name, acptr->name, acptr->from->name,
+               acptr->lastnick, cptr->name, lastnick);
+  }
+  /*
+   * Now remove (kill) the nick on our side if it is the youngest.
+   * If no timestamp was received, we ignore the incoming nick
+   * (and expect a KILL for our legit nick soon ):
+   * When the timestamps are equal we kill both nicks. --Run
+   * acptr->from != cptr should *always* be true (?).
+   *
+   * This exits the client sending the NICK message
+   */
+  if (acptr->from != cptr) {
+    if ((differ && lastnick >= acptr->lastnick) || (!differ && lastnick <= acptr->lastnick)) {
+      if (!IsServer(sptr)) {
+        ++ServerStats->is_kill;
+        sendto_highprot_butone(cptr, 10,        /* Kill old from outgoing servers */
+                              "%s " TOK_KILL " %s%s :%s (%s <- %s (Nick collision))",
+                              NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
+                              cptr->name);
+        assert(!MyConnect(sptr));
+#if 0
+        /*
+         * XXX - impossible
+         */
+        if (MyConnect(sptr))
+          sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (Ghost 2)",
+                     NumServ(&me), NumNick(sptr), me.name);
+#endif
+        sptr->flags |= FLAGS_KILLED;
+        exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
+        /*
+         * we have killed sptr off, zero out it's pointer so if it's used
+         * again we'll know about it --Bleep
+         */
+        sptr = 0;
+      }
+      if (lastnick != acptr->lastnick)
+        return 0;                /* Ignore the NICK */
+    }
+    sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, nick);
+  }
+
+  ++ServerStats->is_kill;
+  acptr->flags |= FLAGS_KILLED;
+  /*
+   * This exits the client we had before getting the NICK message
+   */
+  if (differ) {
+    sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */
+                           "%s " TOK_KILL " %s%s :%s (%s <- %s (older nick overruled))",
+                           NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
+                           cptr->name);
+    if (MyConnect(acptr))
+      sendto_one(cptr, "%s%s " TOK_QUIT " :Local kill by %s (Ghost)",
+                 NumNick(acptr), me.name);
+    exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
+  }
+  else {
+    sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */
+                          "%s " TOK_KILL " %s%s :%s (%s <- %s (nick collision from same user@host))",
+                          NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
+                          cptr->name);
+    if (MyConnect(acptr))
+      sendto_one(cptr,
+                 "%s%s " TOK_QUIT " :Local kill by %s (Ghost: switched servers too fast)",
+                  NumNick(acptr), me.name);
+    exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
+  }
+  if (lastnick == acptr->lastnick)
+    return 0;
+
+  assert(0 != sptr);
+  return set_nick_name(cptr, sptr, nick, parc, parv);
+}
+
+#if 0
+/*
+ * m_nick
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname
+ *
+ * If from server, source is client:
+ *   parv[2] = timestamp
+ *
+ * Source is server:
+ *   parv[2] = hopcount
+ *   parv[3] = timestamp
+ *   parv[4] = username
+ *   parv[5] = hostname
+ *   parv[6] = umode (optional)
+ *   parv[parc-3] = IP#                 <- Only Protocol >= 10
+ *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
+ *   parv[parc-1] = info
+ *   parv[0] = server
+ */
+int m_nick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client* acptr;
+  char           nick[NICKLEN + 2];
+  char*          s;
+  time_t         lastnick = 0;
+  int            differ = 1;
+
+  if (parc < 2) {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+  else if ((IsServer(sptr) && parc < 8) || (IsServer(cptr) && parc < 3))
+  {
+    need_more_params(sptr, "NICK");
+    sendto_ops("bad NICK param count for %s from %s", parv[1], cptr->name);
+    return 0;
+  }
+  if (MyConnect(sptr) && (s = strchr(parv[1], '~')))
+    *s = '\0';
+  ircd_strncpy(nick, parv[1], NICKLEN);
+  nick[NICKLEN] = '\0';
+  if (IsServer(cptr)) {
+    if (IsServer(sptr)) {
+      lastnick = atoi(parv[3]);
+      if (lastnick > OLDEST_TS) 
+       sptr->serv->lag = TStime() - lastnick;
+    } else {
+      lastnick = atoi(parv[2]); 
+      if (lastnick > OLDEST_TS)
+       sptr->user->server->serv->lag = TStime() - lastnick;
+    }
+  }
+  /*
+   * If do_nick_name() returns a null name OR if the server sent a nick
+   * name and do_nick_name() changed it in some way (due to rules of nick
+   * creation) then reject it. If from a server and we reject it,
+   * and KILL it. -avalon 4/4/92
+   */
+  if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1])))
+  {
+    sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1]);
+
+    if (IsServer(cptr))
+    {
+      ServerStats->is_kill++;
+      sendto_ops("Bad Nick: %s From: %s %s",
+          parv[1], parv[0], cptr->name);
+      sendto_one(cptr, "%s " TOK_KILL " %s :%s (%s <- %s[%s])",
+            NumServ(&me), IsServer(sptr) ? parv[parc - 2] : parv[0], me.name,
+            parv[1], nick, cptr->name);
+      if (!IsServer(sptr))        /* bad nick _change_ */
+      {
+        sendto_highprot_butone(cptr, 10, "%s " TOK_KILL " %s :%s (%s <- %s!%s@%s)",
+            NumServ(&me), parv[0], me.name, cptr->name,
+            parv[0], sptr->user ? sptr->username : "",
+            sptr->user ? sptr->user->server->name : cptr->name);
+      }
+    }
+    return 0;
+  }
+
+  /* 
+   * Check if this is a LOCAL user trying to use a reserved (Juped)
+   * nick, if so tell him that it's a nick in use...
+   */
+  if ((!IsServer(cptr)) && isNickJuped(nick))
+  {
+    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
+        /* parv[0] is empty when connecting */
+        EmptyString(parv[0]) ? "*" : parv[0], nick);
+    return 0;                        /* NICK message ignored */
+  }
+
+  /*
+   * Check against nick name collisions.
+   *
+   * Put this 'if' here so that the nesting goes nicely on the screen :)
+   * We check against server name list before determining if the nickname
+   * is present in the nicklist (due to the way the below for loop is
+   * constructed). -avalon
+   */
+  if ((acptr = FindServer(nick))) {
+    if (MyConnect(sptr))
+    {
+      sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
+          EmptyString(parv[0]) ? "*" : parv[0], nick);
+      return 0;                        /* NICK message ignored */
+    }
+    /*
+     * We have a nickname trying to use the same name as
+     * a server. Send out a nick collision KILL to remove
+     * the nickname. As long as only a KILL is sent out,
+     * there is no danger of the server being disconnected.
+     * Ultimate way to jupiter a nick ? >;-). -avalon
+     */
+    sendto_ops("Nick collision on %s(%s <- %s)",
+               sptr->name, acptr->from->name, cptr->name);
+    ServerStats->is_kill++;
+    sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (%s <- %s)",
+               NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
+               cptr->name);
+    sptr->flags |= FLAGS_KILLED;
+    return exit_client(cptr, sptr, &me, "Nick/Server collision");
+  }
+
+  if (!(acptr = FindClient(nick)))
+    return set_nick_name(cptr, sptr, nick, parc, parv);  /* No collisions, all clear... */
+  /*
+   * If acptr == sptr, then we have a client doing a nick
+   * change between *equivalent* nicknames as far as server
+   * is concerned (user is changing the case of his/her
+   * nickname or somesuch)
+   */
+  if (acptr == sptr)
+  {
+    if (strcmp(acptr->name, nick) != 0)
+      /*
+       * Allows change of case in his/her nick
+       */
+      return set_nick_name(cptr, sptr, nick, parc, parv);
+    else
+      /*
+       * This is just ':old NICK old' type thing.
+       * Just forget the whole thing here. There is
+       * no point forwarding it to anywhere,
+       * especially since servers prior to this
+       * version would treat it as nick collision.
+       */
+      return 0;                        /* NICK Message ignored */
+  }
+
+  /*
+   * Note: From this point forward it can be assumed that
+   * acptr != sptr (point to different client structures).
+   */
+  /*
+   * If the older one is "non-person", the new entry is just
+   * allowed to overwrite it. Just silently drop non-person,
+   * and proceed with the nick. This should take care of the
+   * "dormant nick" way of generating collisions...
+   */
+  if (IsUnknown(acptr) && MyConnect(acptr))
+  {
+    ++ServerStats->is_ref;
+    IPcheck_connect_fail(acptr->ip);
+    exit_client(cptr, acptr, &me, "Overridden by other sign on");
+    return set_nick_name(cptr, sptr, nick, parc, parv);
+  }
+  /*
+   * Decide, we really have a nick collision and deal with it
+   */
+  if (!IsServer(cptr))
+  {
+    /*
+     * NICK is coming from local client connection. Just
+     * send error reply and ignore the command.
+     */
+    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
+        /* parv[0] is empty when connecting */
+        EmptyString(parv[0]) ? "*" : parv[0], nick);
+    return 0;                        /* NICK message ignored */
+  }
+  /*
+   * NICK was coming from a server connection.
+   * This means we have a race condition (two users signing on
+   * at the same time), or two net fragments reconnecting with the same nick.
+   * The latter can happen because two different users connected
+   * or because one and the same user switched server during a net break.
+   * If the TimeStamps are equal, we kill both (or only 'new'
+   * if it was a ":server NICK new ...").
+   * Otherwise we kill the youngest when user@host differ,
+   * or the oldest when they are the same.
+   * We treat user and ~user as different, because if it wasn't
+   * a faked ~user the AUTH wouldn't have added the '~'.
+   * --Run
+   *
+   */
+  if (IsServer(sptr))
+  {
+    /*
+     * A new NICK being introduced by a neighbouring
+     * server (e.g. message type ":server NICK new ..." received)
+     */
+    differ =  (acptr->ip.s_addr != htonl(base64toint(parv[parc - 3]))) ||
+            (0 != ircd_strcmp(acptr->user->username, parv[4]));
+    sendto_ops("Nick collision on %s (%s " TIME_T_FMT " <- %s " TIME_T_FMT
+               " (%s user@host))", acptr->name, acptr->from->name, acptr->lastnick,
+               cptr->name, lastnick, differ ? "Different" : "Same");
+  }
+  else
+  {
+    /*
+     * A NICK change has collided (e.g. message type ":old NICK new").
+     */
+    lastnick = atoi(parv[2]);
+    differ =  (acptr->ip.s_addr != sptr->ip.s_addr) ||
+            (0 != ircd_strcmp(acptr->user->username, sptr->user->username));              
+    sendto_ops("Nick change collision from %s to %s (%s " TIME_T_FMT " <- %s "
+               TIME_T_FMT ")", sptr->name, acptr->name, acptr->from->name,
+               acptr->lastnick, cptr->name, lastnick);
+  }
+  /*
+   * Now remove (kill) the nick on our side if it is the youngest.
+   * If no timestamp was received, we ignore the incoming nick
+   * (and expect a KILL for our legit nick soon ):
+   * When the timestamps are equal we kill both nicks. --Run
+   * acptr->from != cptr should *always* be true (?).
+   */
+  if (acptr->from != cptr)
+  {
+    if ((differ && lastnick >= acptr->lastnick) ||
+        (!differ && lastnick <= acptr->lastnick))
+    {
+      if (!IsServer(sptr))
+      {
+        ServerStats->is_kill++;
+        sendto_highprot_butone(cptr, 10,        /* Kill old from outgoing servers */
+                               "%s " TOK_KILL " %s%s :%s (%s <- %s (Nick collision))",
+                               NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
+                               cptr->name);
+        if (MyConnect(sptr) && IsServer(cptr) && Protocol(cptr) > 9)
+          sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (Ghost2)",
+                     NumServ(&me), NumNick(sptr), me.name);
+        sptr->flags |= FLAGS_KILLED;
+        exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
+      }
+      if (lastnick != acptr->lastnick)
+        return 0;                /* Ignore the NICK */
+    }
+    sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, nick);
+  }
+  ServerStats->is_kill++;
+  acptr->flags |= FLAGS_KILLED;
+  if (differ)
+  {
+    sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */
+                           "%s " TOK_KILL " %s%s :%s (%s <- %s (older nick overruled))",
+                           NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
+                           cptr->name);
+    if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
+      sendto_one(cptr, "%s%s " TOK_QUIT " :Local kill by %s (Ghost)",
+          NumNick(acptr), me.name);
+    exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
+  }
+  else
+  {
+    sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */
+                           "%s " TOK_KILL " %s%s :%s (%s <- %s (nick collision from same user@host))",
+                           NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
+                           cptr->name);
+    if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
+      sendto_one(cptr,
+          "%s%s " TOK_QUIT " :Local kill by %s (Ghost: switched servers too fast)",
+          NumNick(acptr), me.name);
+    exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
+  }
+  if (lastnick == acptr->lastnick)
+    return 0;
+
+  return set_nick_name(cptr, sptr, nick, parc, parv);
+}
+
+#endif /* 0 */
diff --git a/ircd/m_notice.c b/ircd/m_notice.c
new file mode 100644 (file)
index 0000000..27b0982
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_notice.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_chattr.h"
+#include "ircd_relay.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+
+#include <assert.h>
+#include <string.h>
+
+#if !defined(XXX_BOGUS_TEMP_HACK)
+#include "handlers.h"
+#endif
+
+/*
+ * m_notice - generic message handler
+ */
+int m_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, MSG_NOTICE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+  if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) {
+    parv[1]++;                        /* Get rid of '@' */
+    return m_wallchops(cptr, sptr, parc, parv);
+  }
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name)) {
+      relay_channel_notice(sptr, name, parv[parc - 1]);
+    }
+    /*
+     * we have to check for the '@' at least once no matter what we do
+     * handle it first so we don't have to do it twice
+     */
+    else if ((server = strchr(name, '@')))
+      relay_directed_notice(sptr, name, server, parv[parc - 1]);
+    else 
+      relay_private_notice(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+/*
+ * ms_notice - server message handler template
+ */
+int ms_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* name;
+  char* server;
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 3) {
+    /*
+     * we can't deliver it, sending an error back is pointless
+     */
+    return 0;
+  }
+  name = parv[1];
+  /*
+   * channel msg?
+   */
+  if (IsChannelPrefix(*name)) {
+    server_relay_channel_notice(sptr, name, parv[parc - 1]);
+  }
+  /*
+   * coming from another server, we have to check this here
+   */
+  else if ('$' == *name && IsOper(sptr)) {
+    server_relay_masked_notice(sptr, name, parv[parc - 1]);
+  }
+  else if ((server = strchr(name, '@'))) {
+    /*
+     * XXX - can't get away with not doing everything
+     * relay_directed_notice has to do
+     */
+    relay_directed_notice(sptr, name, server, parv[parc - 1]);
+  }
+  else {
+    server_relay_private_notice(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+/*
+ * mo_notice - oper message handler
+ */
+int mo_notice(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, MSG_NOTICE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+  if (parv[1][0] == '@' && IsChannelPrefix(parv[1][1])) {
+    parv[1]++;                        /* Get rid of '@' */
+    return m_wallchops(cptr, sptr, parc, parv);
+  }
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name))
+      relay_channel_notice(sptr, name, parv[parc - 1]);
+
+    else if (*name == '$')
+      relay_masked_notice(sptr, name, parv[parc - 1]);
+
+    else if ((server = strchr(name, '@')))
+      relay_directed_notice(sptr, name, server, parv[parc - 1]);
+
+    else 
+      relay_private_notice(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_message (used in m_private() and m_notice())
+ *
+ * The general function to deliver MSG's between users/channels
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[parc-1] = message text
+ *
+ * massive cleanup
+ * rev argv 6/91
+ */
+static int m_message(struct Client *cptr, struct Client *sptr,
+    int parc, char *parv[], int notice)
+{
+  struct Client*  acptr;
+  char*           s;
+  struct Channel* chptr;
+  char*           nick;
+  char*           server;
+  char*           cmd;
+  char*           host;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, cmd);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+
+#if 0
+  if (MyUser(sptr))
+    parv[1] = canonize(parv[1]);
+  for (p = 0, nick = ircd_strtok(&p, parv[1], ","); nick;
+      nick = ircd_strtok(&p, 0, ","))
+#endif
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+  for (i = 0; i < count; ++i) {
+    nick = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelName(nick))
+    {
+      if ((chptr = FindChannel(nick)))
+      {
+        /* This first: Almost never a server/service */
+        if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr))
+        {
+          if (MyUser(sptr) && (chptr->mode.mode & MODE_NOPRIVMSGS) &&
+              check_target_limit(sptr, chptr, chptr->chname, 0))
+            continue;
+          sendmsgto_channel_butone(cptr, sptr, chptr,
+              parv[0], (notice ? TOK_NOTICE : TOK_PRIVATE), 
+              chptr->chname, parv[parc - 1]);
+        }
+        else if (!notice)
+          sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
+              me.name, parv[0], chptr->chname);
+        continue;
+      }
+    }
+    else if (*nick != '$' && !strchr(nick, '@'))
+    {
+      /*
+       * nickname addressed?
+       */
+      if (MyUser(sptr))
+        acptr = FindUser(nick);
+      else if ((acptr = findNUser(nick)) && !IsUser(acptr))
+        acptr = 0;
+      if (acptr)
+      {
+        if (MyUser(sptr) && check_target_limit(sptr, acptr, acptr->name, 0))
+          continue;
+        if (!is_silenced(sptr, acptr))
+        {
+          if (!notice && MyConnect(sptr) && acptr->user && acptr->user->away)
+            sendto_one(sptr, rpl_str(RPL_AWAY),
+                me.name, parv[0], acptr->name, acptr->user->away);
+          if (MyUser(acptr))
+          {
+            add_target(acptr, sptr);
+            sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                parv[0], cmd, acptr->name, parv[parc - 1]);
+          }
+          else
+            sendto_prefix_one(acptr, sptr, ":%s %s %s%s :%s",
+                parv[0], (notice ? TOK_NOTICE : TOK_PRIVATE),
+                NumNick(acptr), parv[parc - 1]);
+        }
+      }
+      else if (MyUser(sptr))
+        sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+      else
+        sendto_one(sptr,
+            ":%s %d %s * :Target left UnderNet. Failed to deliver: [%.50s]",
+            me.name, ERR_NOSUCHNICK, sptr->name, parv[parc - 1]);
+      continue;
+    }
+    /*
+     * The following two cases allow masks in NOTICEs
+     * (for OPERs only)
+     *
+     * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
+     */
+    if ((*nick == '$' || *nick == '#') && IsAnOper(sptr))
+    {
+      if (MyConnect(sptr))
+      {
+        if (!(s = strrchr(nick, '.')))
+        {
+          sendto_one(sptr, err_str(ERR_NOTOPLEVEL), me.name, parv[0], nick);
+          continue;
+        }
+        while (*++s)
+          if (*s == '.' || *s == '*' || *s == '?')
+            break;
+        if (*s == '*' || *s == '?')
+        {
+          sendto_one(sptr, err_str(ERR_WILDTOPLEVEL), me.name, parv[0], nick);
+          continue;
+        }
+      }
+      sendto_match_butone(IsServer(cptr) ? cptr : 0,
+          sptr, nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
+          ":%s %s %s :%s", parv[0], cmd, nick, parv[parc - 1]);
+      continue;
+    }
+    else if ((server = strchr(nick, '@')) && (acptr = FindServer(server + 1)))
+    {
+      /*
+       * NICK[%host]@server addressed? See if <server> is me first
+       */
+      if (!IsMe(acptr))
+      {
+        sendto_one(acptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[parc - 1]);
+        continue;
+      }
+
+      /* Look for an user whose NICK is equal to <nick> and then
+       * check if it's hostname matches <host> and if it's a local
+       * user. */
+      *server = '\0';
+      if ((host = strchr(nick, '%')))
+        *host++ = '\0';
+
+      if ((!(acptr = FindUser(nick))) ||
+          (!(MyUser(acptr))) ||
+          ((!(EmptyString(host))) && match(host, acptr->user->host)))
+        acptr = 0;
+
+      *server = '@';
+      if (host)
+        *--host = '%';
+
+      if (acptr)
+      {
+        if (!(is_silenced(sptr, acptr)))
+          sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+              parv[0], cmd, nick, parv[parc - 1]);
+        continue;
+      }
+    }
+    if (IsChannelName(nick))
+      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], nick);
+    else
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+  }
+  return 0;
+}
+
+/*
+ * m_private
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[parc-1] = message text
+ */
+int m_private(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  return m_message(cptr, sptr, parc, parv, 0);
+}
+
+/*
+ * m_notice
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[parc-1] = notice text
+ */
+int m_notice(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  if (MyUser(sptr) && parv[1] && parv[1][0] == '@' &&
+      IsChannelName(&parv[1][1]))
+  {
+    parv[1]++;                        /* Get rid of '@' */
+    return m_wallchops(cptr, sptr, parc, parv);
+  }
+  return m_message(cptr, sptr, parc, parv, 1);
+}
+
+#endif
diff --git a/ircd/m_oper.c b/ircd/m_oper.c
new file mode 100644 (file)
index 0000000..12ebde2
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_oper.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_xopen.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef CRYPT_OPER_PASSWORD
+int oper_password_match(const char* to_match, const char* passwd)
+{
+  /*
+   * use first two chars of the password they send in as salt
+   *
+   * passwd may be NULL. Head it off at the pass...
+   */
+  if (to_match && passwd) {
+    char salt[3];
+    const char* encr;
+    salt[0] = passwd[0];
+    salt[1] = passwd[1];
+    salt[2] = '\0';
+    encr = ircd_crypt(to_match, salt);
+    return (0 == strcmp(encr, passwd));
+  }
+  return 0;
+}
+#else
+int oper_password_match(const char* to_match, const char* passwd)
+{
+  return (to_match && passwd) ? (0 == strcmp(to_match, passwd)) : 0;
+}
+#endif
+
+/*
+ * m_oper - generic message handler
+ */
+int m_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct ConfItem* aconf;
+  char*            name;
+  char*            password;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  name     = parc > 1 ? parv[1] : 0;
+  password = parc > 2 ? parv[2] : 0;
+
+  if (EmptyString(name) || EmptyString(password))
+    return need_more_params(sptr, "OPER");
+
+  aconf = find_conf_exact(name, sptr->username, sptr->sockhost, CONF_OPS);
+  if (!aconf) 
+    aconf = find_conf_exact(name, sptr->username,
+                            ircd_ntoa((const char*) &cptr->ip), CONF_OPS);
+
+  if (!aconf || IsIllegal(aconf)) {
+    send_error_to_client(sptr, ERR_NOOPERHOST);
+    sendto_realops("Failed OPER attempt by %s (%s@%s)",
+                   parv[0], sptr->user->username, sptr->sockhost);
+    return 0;
+  }
+  assert(0 != (aconf->status & CONF_OPS));
+
+  if (oper_password_match(password, aconf->passwd)) {
+    unsigned int old_mode = (sptr->flags & ALL_UMODES);
+
+    if (ACR_OK != attach_conf(sptr, aconf)) {
+      send_error_to_client(sptr, ERR_NOOPERHOST);
+      sendto_realops("Failed OPER attempt by %s (%s@%s)",
+                     parv[0], sptr->user->username, sptr->sockhost);
+      return 0;
+    }
+    if (CONF_LOCOP == aconf->status) {
+      ClearOper(sptr);
+      SetLocOp(sptr);
+    }
+    else {
+      /*
+       * prevent someone from being both oper and local oper
+       */
+      ClearLocOp(sptr);
+      SetOper(sptr);
+      ++UserStats.opers;
+    }
+    cptr->handler = OPER_HANDLER;
+
+    
+    sptr->flags |= (FLAGS_WALLOP | FLAGS_SERVNOTICE | FLAGS_DEBUG);
+
+    set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
+    send_umode_out(cptr, sptr, old_mode);
+    sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+
+    sendto_ops("%s (%s@%s) is now operator (%c)", parv[0],
+               sptr->user->username, sptr->sockhost,
+               IsOper(sptr) ? 'O' : 'o');
+
+    ircd_log(L_INFO, "OPER (%s) by (%s!%s@%s)",
+             name, parv[0], sptr->user->username, sptr->sockhost);
+#ifdef FNAME_OPERLOG
+    if (IsUser(sptr))
+      write_log(FNAME_OPERLOG,
+                "%s OPER (%s) by (%s!%s@%s)\n", myctime(CurrentTime),
+                name, parv[0], sptr->user->username, sptr->sockhost);
+#endif
+  }
+  else {
+    sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+    sendto_realops("Failed OPER attempt by %s (%s@%s)",
+                   parv[0], sptr->user->username, sptr->sockhost);
+  }
+  return 0;
+}
+
+/*
+ * ms_oper - server message handler
+ */
+int ms_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(IsServer(cptr));
+  /*
+   * if message arrived from server, trust it, and set to oper
+   */
+  if (!IsServer(sptr) && !IsOper(sptr)) {
+    ++UserStats.opers;
+    sptr->flags |= FLAGS_OPER;
+    sendto_serv_butone(cptr, "%s%s " TOK_MODE " %s :+o", NumNick(sptr), parv[0]);
+  }
+  return 0;
+}
+
+/*
+ * mo_oper - oper message handler
+ */
+int mo_oper(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+  return 0;
+}
+#if 0
+/*
+ *  m_oper
+ *    parv[0] = sender prefix
+ *    parv[1] = oper name
+ *    parv[2] = oper password
+ */
+int m_oper(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct ConfItem* aconf;
+  char*            name;
+  char*            password;
+  const char*      encr;
+#ifdef CRYPT_OPER_PASSWORD
+  char             salt[3];
+#endif /* CRYPT_OPER_PASSWORD */
+
+  name = parc > 1 ? parv[1] : 0;
+  password = parc > 2 ? parv[2] : 0;
+
+  if (!IsServer(cptr) && (EmptyString(name) || EmptyString(password)))
+    return need_more_params(sptr, "OPER");
+
+  /* if message arrived from server, trust it, and set to oper */
+
+  if (IsServer(cptr) && !IsOper(sptr)) {
+    ++UserStats.opers;
+    sptr->flags |= FLAGS_OPER;
+    sendto_serv_butone(cptr, "%s%s " TOK_MODE " %s :+o", NumNick(sptr), parv[0]);
+    return 0;
+  }
+  else if (IsAnOper(sptr)) {
+    if (MyConnect(sptr))
+      sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+    return 0;
+  }
+  assert(cptr == sptr);
+  aconf = find_conf_exact(name, sptr->username, sptr->sockhost, CONF_OPS);
+  if (!aconf) 
+    aconf = find_conf_exact(name, sptr->username,
+                            ircd_ntoa((const char*) &cptr->ip), CONF_OPS);
+
+  if (!aconf || IsIllegal(aconf)) {
+    sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
+    sendto_realops("Failed OPER attempt by %s (%s@%s)",
+                   parv[0], sptr->user->username, sptr->sockhost);
+    return 0;
+  }
+  assert(0 != (aconf->status & CONF_OPS));
+
+#ifdef CRYPT_OPER_PASSWORD
+  /* use first two chars of the password they send in as salt */
+
+  /* passwd may be NULL. Head it off at the pass... */
+  salt[0] = '\0';
+  if (password && aconf->passwd)
+  {
+    salt[0] = aconf->passwd[0];
+    salt[1] = aconf->passwd[1];
+    salt[2] = '\0';
+    encr = ircd_crypt(password, salt);
+  }
+  else
+    encr = "";
+#else
+  encr = password;
+#endif /* CRYPT_OPER_PASSWORD */
+
+  if (0 == strcmp(encr, aconf->passwd)) {
+    int old = (sptr->flags & ALL_UMODES);
+
+    if (ACR_OK != attach_conf(sptr, aconf)) {
+      sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
+      sendto_realops("Failed OPER attempt by %s (%s@%s)",
+                     parv[0], sptr->user->username, sptr->sockhost);
+      return 0;
+    }
+#ifdef        OPER_REMOTE
+    if (aconf->status == CONF_LOCOP) {
+#else
+    if (!IsLocal(sptr)) || aconf->status == CONF_LOCOP) {
+#endif
+      ClearOper(sptr);
+      SetLocOp(sptr);
+    }
+    else {
+      /* prevent someone from being both oper and local oper */
+      ClearLocOp(sptr);
+      SetOper(sptr);
+      ++UserStats.opers;
+    }
+    cptr->handler = OPER_HANDLER;
+    sendto_ops("%s (%s@%s) is now operator (%c)", parv[0],
+        sptr->user->username, sptr->sockhost, IsOper(sptr) ? 'O' : 'o');
+
+    sptr->flags |= (FLAGS_WALLOP | FLAGS_SERVNOTICE | FLAGS_DEBUG);
+    set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
+    send_umode_out(cptr, sptr, old);
+    sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+
+    ircd_log(L_INFO, "OPER (%s) by (%s!%s@%s)",
+             name, parv[0], sptr->user->username, sptr->sockhost);
+#ifdef FNAME_OPERLOG
+    if (IsUser(sptr))
+      write_log(FNAME_OPERLOG,
+          "%s OPER (%s) by (%s!%s@%s)\n", myctime(CurrentTime),
+          name, parv[0], sptr->user->username, sptr->sockhost);
+#endif
+  }
+  else {
+    sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+    sendto_realops("Failed OPER attempt by %s (%s@%s)",
+                   parv[0], sptr->user->username, sptr->sockhost);
+  }
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_part.c b/ircd/m_part.c
new file mode 100644 (file)
index 0000000..d4de9b3
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_part.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * m_part - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[parc - 1] = comment
+ */
+int m_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel* chptr;
+  struct Membership* member;
+  char*           p = 0;
+  char*           name;
+  char            pbuf[BUFSIZE];
+  char*           comment = (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0;
+
+  *pbuf = '\0';                 /* Initialize the part buffer... -Kev */
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || parv[1][0] == '\0')
+    return need_more_params(sptr, "PART");
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = get_channel(sptr, name, CGT_NO_CREATE);
+    if (!chptr) {
+      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+      continue;
+    }
+    if (*name == '&' && !MyUser(sptr))
+      continue;
+    /*
+     * Do not use find_channel_member here: zombies must be able to part too
+     */
+    if (!(member = find_member_link(chptr, sptr)))
+    {
+      /* Normal to get when our client did a kick
+       * for a remote client (who sends back a PART),
+       * so check for remote client or not --Run
+       */
+      if (MyUser(sptr))
+        sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+            chptr->chname);
+      continue;
+    }
+    /* Recreate the /part list for sending to servers */
+    if (*name != '&')
+    {
+      if (*pbuf)
+        strcat(pbuf, ",");
+      strcat(pbuf, name);
+    }
+    if (IsZombie(member)
+        || !member_can_send_to_channel(member))  /* Returns 1 if we CAN send */
+      comment = 0;
+    /* Send part to all clients */
+    if (!IsZombie(member))
+    {
+      if (comment)
+        sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
+                               comment);
+      else
+        sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
+    }
+    else if (MyUser(sptr))
+    {
+      if (comment)
+        sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
+      else
+        sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
+    }
+    remove_user_from_channel(sptr, chptr);
+  }
+  /* Send out the parts to all servers... -Kev */
+  if (*pbuf)
+  {
+    if (comment)
+      sendto_serv_butone(cptr, PartFmt2serv, NumNick(sptr), pbuf, comment);
+    else
+      sendto_serv_butone(cptr, PartFmt1serv, NumNick(sptr), pbuf);
+  }
+  return 0;
+}
+
+/*
+ * ms_part - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[parc - 1] = comment
+ */
+int ms_part(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel* chptr;
+  struct Membership* member;
+  char*           p = 0;
+  char*           name;
+  char            pbuf[BUFSIZE];
+  char*           comment = (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0;
+
+  *pbuf = '\0';                 /* Initialize the part buffer... -Kev */
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || parv[1][0] == '\0')
+    return need_more_params(sptr, "PART");
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = get_channel(sptr, name, CGT_NO_CREATE);
+    if (!chptr) {
+      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+      continue;
+    }
+    if (*name == '&' && !MyUser(sptr))
+      continue;
+    /*
+     * Do not use find_channel_member here: zombies must be able to part too
+     */
+    if (!(member = find_member_link(chptr, sptr)))
+    {
+      /* Normal to get when our client did a kick
+       * for a remote client (who sends back a PART),
+       * so check for remote client or not --Run
+       */
+      if (MyUser(sptr))
+        sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+            chptr->chname);
+      continue;
+    }
+    /* Recreate the /part list for sending to servers */
+    if (*name != '&')
+    {
+      if (*pbuf)
+        strcat(pbuf, ",");
+      strcat(pbuf, name);
+    }
+    if (IsZombie(member)
+        || !member_can_send_to_channel(member))  /* Returns 1 if we CAN send */
+      comment = 0;
+    /* Send part to all clients */
+    if (!IsZombie(member))
+    {
+      if (comment)
+        sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
+                               comment);
+      else
+        sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
+    }
+    else if (MyUser(sptr))
+    {
+      if (comment)
+        sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
+      else
+        sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
+    }
+    remove_user_from_channel(sptr, chptr);
+  }
+  /* Send out the parts to all servers... -Kev */
+  if (*pbuf)
+  {
+    if (comment)
+      sendto_serv_butone(cptr, PartFmt2serv, NumNick(sptr), pbuf, comment);
+    else
+      sendto_serv_butone(cptr, PartFmt1serv, NumNick(sptr), pbuf);
+  }
+  return 0;
+}
+
+#if 0
+/*
+ * m_part
+ *
+ * parv[0] = sender prefix
+ * parv[1] = channel
+ * parv[parc - 1] = comment
+ */
+int m_part(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel* chptr;
+  struct Membership* member;
+  char*           p = 0;
+  char*           name;
+  char            pbuf[BUFSIZE];
+  char*           comment = (parc > 2 && !EmptyString(parv[parc - 1])) ? parv[parc - 1] : 0;
+
+  *pbuf = '\0';                 /* Initialize the part buffer... -Kev */
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || parv[1][0] == '\0')
+    return need_more_params(sptr, "PART");
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = get_channel(sptr, name, CGT_NO_CREATE);
+    if (!chptr) {
+      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], name);
+      continue;
+    }
+    if (*name == '&' && !MyUser(sptr))
+      continue;
+    /*
+     * Do not use find_channel_member here: zombies must be able to part too
+     */
+    if (!(member = find_member_link(chptr, sptr)))
+    {
+      /* Normal to get when our client did a kick
+       * for a remote client (who sends back a PART),
+       * so check for remote client or not --Run
+       */
+      if (MyUser(sptr))
+        sendto_one(sptr, err_str(ERR_NOTONCHANNEL), me.name, parv[0],
+            chptr->chname);
+      continue;
+    }
+    /* Recreate the /part list for sending to servers */
+    if (*name != '&')
+    {
+      if (*pbuf)
+        strcat(pbuf, ",");
+      strcat(pbuf, name);
+    }
+    if (IsZombie(member)
+        || !member_can_send_to_channel(member))  /* Returns 1 if we CAN send */
+      comment = 0;
+    /* Send part to all clients */
+    if (!IsZombie(member))
+    {
+      if (comment)
+        sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], chptr->chname,
+                               comment);
+      else
+        sendto_channel_butserv(chptr, sptr, PartFmt1, parv[0], chptr->chname);
+    }
+    else if (MyUser(sptr))
+    {
+      if (comment)
+        sendto_one(sptr, PartFmt2, parv[0], chptr->chname, comment);
+      else
+        sendto_one(sptr, PartFmt1, parv[0], chptr->chname);
+    }
+    remove_user_from_channel(sptr, chptr);
+  }
+  /* Send out the parts to all servers... -Kev */
+  if (*pbuf)
+  {
+    if (comment)
+      sendto_serv_butone(cptr, PartFmt2serv, NumNick(sptr), pbuf, comment);
+    else
+      sendto_serv_butone(cptr, PartFmt1serv, NumNick(sptr), pbuf);
+  }
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_pass.c b/ircd/m_pass.c
new file mode 100644 (file)
index 0000000..50870b2
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_pass.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mr_pass - registration message handler
+ */
+int m_pass(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char* password = parc > 1 ? parv[1] : 0;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(!IsRegistered(sptr));
+
+  if (EmptyString(password))
+    return need_more_params(cptr, "PASS");
+
+  ircd_strncpy(cptr->passwd, password, PASSWDLEN);
+  return 0;
+}
+
+#if 0
+/*
+ * m_pass
+ *
+ * parv[0] = sender prefix
+ * parv[1] = password
+ */
+int m_pass(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *password = parc > 1 ? parv[1] : 0;
+
+  if (EmptyString(password))
+    return need_more_params(cptr, "PASS");
+
+  if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
+  {
+    sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
+    return 0;
+  }
+  ircd_strncpy(cptr->passwd, password, PASSWDLEN);
+  return 0;
+}
+#endif
+
diff --git a/ircd/m_ping.c b/ircd/m_ping.c
new file mode 100644 (file)
index 0000000..751c174
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_ping.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * Stupid ircd Tricks
+ * Excerpt from conversation on #coder-com:
+ *  > the number horks it
+ *  <Gte-> yea
+ *  > thinks it's a numeric?
+ *  > no
+ *  <Gte-> hm
+ *  > why would the number hork it
+ *  <Gte-> why is it even looking up servers in a client ping :)
+ *  > it's a server ping
+ *  <Gte-> true
+ *  > oh
+ *  > I know why :)
+ *  >   origin = parv[1];
+ *  >   destination = parv[2];
+ *  >   acptr = FindClient(origin);
+ *  >   if (acptr && acptr != sptr)
+ *  >     origin = cptr->name;
+ *  > heh, that's a bug :)
+ *  <Gte-> yea, client/server handling in the same function sucks :P
+ *  > blindly pass a bogus origin around, and where do you send the reply to?
+ *  <Gte-> I tried /quote ping 12345 uworld.blah.net locally, and uworld
+ *  +recieved -> ":Gte- PING N :Uworld.blah.net"
+ *  <Gte-> oh no, sorry, I did ping N :)
+ *  > right, it's broken
+ *  <Gte-> good thing it doesn't have a fit replying to it
+ *  > hmm
+ *  *** plano.tx.us.undernet.org: PONG received from plano.tx.us.undernet.org
+ *  > you can send a number for the first ping .. but if you ping a remote server
+ *  +it goes to the remote end where it's received as a unsolicited pong by the
+ *  +server closest to the target
+ *  > hahaha
+ *  <Gte-> cool
+ *  <Gte-> Parsing: :Gte PING 12345 :widnes.uk.eu.blah.net
+ *  <Gte-> Sending [:widnes.uk.eu.blah.net PONG widnes.uk.eu.blah.net
+ *  +:12345] to alphatest.blah.net
+ *  <Gte-> Parsing: :alphatest.blah.net 402 widnes.uk.eu.blah.net
+ *  +12345 :No such server
+ *  > oh even better, the pongee sends no such server :)
+ *  > bwhahahah
+ *  <Gte-> for a second, I thought you could trigger a loop, which would be
+ *  +hideously nasty, but it doesn't look like
+ *  > it goes a ------ > b ------- > c ------- > d then c <------- d then c -----
+ *  +> d :)
+ *  <Gte-> weeee
+ *  <Gte-> [04:15] -> Server: ping Gte- Dallas-R.Tx.US.Undernet.org
+ *  <Gte-> *** PONG from Dallas-R.Tx.US.Undernet.org: Gte-
+ *  <Gte-> there we go
+ *  <Gte-> I can get a ping reply from a server I'm not on :)
+ */
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_ping - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int m_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char*          destination;
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NOORIGIN);
+
+  destination = parv[2];        /* Will get NULL or pointer (parc >= 2!!) */
+
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, me.name)) {
+    if ((acptr = FindServer(destination)))
+      /*
+       * NOTE: can't send the origin string to servers, since this is a client,
+       * we could get garbage, and the link between us and the pingee wouldn't
+       * know who to send it to.
+       * sendto_one(acptr, "%s%s PING %s :%s", NumNick(sptr), parv[1], destination);
+       */
+      sendto_one(acptr, "%s%s " TOK_PING " %s :%s", NumNick(sptr), sptr->name, destination);
+    else
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, sptr->name, destination);
+  }
+  else {
+    /*
+     * NOTE: clients rely on this to return the origin string.
+     * it's pointless to send more than 64 bytes back tho'
+     */
+    char* origin = parv[1];
+    
+    /* Is this supposed to be here? */
+    acptr = FindClient(origin);
+    if (acptr && acptr != sptr)
+      origin = cptr->name;
+    
+    if (strlen(origin) > 64)
+      origin[64] = '\0';
+    sendto_one(sptr, ":%s PONG %s :%s", me.name, me.name, origin);
+  }
+  return 0;
+}
+
+/*
+ * Extension notes
+ *
+ * <Vek> bleep:  here's the change you make to PING:
+ * <Vek> F TOK_PING F G 7777777777.7777777
+ * <Vek> then optional parameter for further enhancement
+ * <Vek> G TOK_PONG G F 7777777777.7777777 0.1734637
+ */
+
+/*
+ * ms_ping - server message handler template
+ */
+int ms_ping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+  char*          origin;
+  char*          destination;
+
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if (parc < 2 || EmptyString(parv[1])) {
+    /*
+     * don't bother sending the error back
+     */
+#if 0
+    sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
+#endif
+    return 0;
+  }
+  origin      = parv[1];
+  destination = parv[2];        /* Will get NULL or pointer (parc >= 2!!) */
+
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, me.name)) {
+    if ((acptr = FindServer(destination))) {
+      /*
+       * Servers can just forward the origin
+       */
+      if (IsServer(sptr))
+        /*
+         * servers don't normally send pings to remote servers
+         */
+        sendto_one(acptr, "%s " TOK_PING " %s :%s", NumServ(sptr), origin, destination);
+      else
+        sendto_one(acptr, "%s%s " TOK_PING " %s :%s", NumNick(sptr), origin, destination);
+    }
+    else {
+      /*
+       * this can happen if server split before the ping got here
+       */
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, sptr->name, destination);
+    }
+  }
+  else {
+    /*
+     * send pong back
+     * NOTE:  sptr is never local so if pong handles numerics everywhere we
+     * could send a numeric here.
+     */
+    sendto_one(sptr, "%s " TOK_PONG " %s :%s", NumServ(&me), me.name, origin);
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_ping
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int m_ping(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+  char *origin, *destination;
+
+  if (parc < 2 || *parv[1] == '\0')
+  {
+    sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
+    return 0;
+  }
+  origin = parv[1];
+  destination = parv[2];        /* Will get NULL or pointer (parc >= 2!!) */
+
+  acptr = FindClient(origin);
+  if (acptr && acptr != sptr)
+    origin = cptr->name;
+
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, me.name) != 0)
+  {
+    if ((acptr = FindServer(destination)))
+      sendto_one(acptr, ":%s PING %s :%s", parv[0], origin, destination);
+    else
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
+          me.name, parv[0], destination);
+      return 0;
+    }
+  }
+  else
+    sendto_one(sptr, ":%s PONG %s :%s", me.name, me.name, origin);
+  return 0;
+}
+#endif
+
diff --git a/ircd/m_pong.c b/ircd/m_pong.c
new file mode 100644 (file)
index 0000000..d5fee34
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_pong.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+/*
+ * ms_pong - server message handler template
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int ms_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*          origin;
+  char*          destination;
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(IsServer(cptr));
+
+  if (parc < 2 || EmptyString(parv[1])) {
+#if 0
+    /*
+     * ignore there is nothing the server sending it can do about it
+     */
+    sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
+#endif
+    return 0;
+  }
+  origin      = parv[1];
+  destination = parv[2];
+  cptr->flags &= ~FLAGS_PINGSENT;
+  sptr->flags &= ~FLAGS_PINGSENT;
+
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, me.name)) {
+    struct Client* acptr;
+    if ((acptr = FindClient(destination))) {
+      if (MyUser(acptr))
+        sendto_one(acptr, ":%s PONG %s %s", sptr->name, origin, destination);
+      else
+        sendto_one(acptr, "%s " TOK_PONG " %s %s", NumServ(sptr), origin, destination);
+    }
+  }
+  return 0;
+}
+
+/*
+ * mr_pong - registration message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = pong response echo
+ * NOTE: cptr is always unregistered here
+ */
+int mr_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(!IsRegistered(sptr));
+
+  cptr->flags &= ~FLAGS_PINGSENT;
+  /*
+   * Check to see if this is a PONG :cookie reply from an
+   * unregistered user.  If so, process it. -record
+   */
+  if (0 != sptr->cookie && COOKIE_VERIFIED != sptr->cookie) {
+    if (parc > 1 && sptr->cookie == atol(parv[parc - 1])) {
+      sptr->cookie = COOKIE_VERIFIED;
+      if (sptr->user && *sptr->user->host && sptr->name[0])
+        /*
+         * NICK and USER OK
+         */
+        return register_user(cptr, sptr, sptr->name, sptr->user->username);
+    }
+    else  
+      sendto_one(sptr, ":%s %d %s :To connect, type /QUOTE PONG %u",
+                 me.name, ERR_BADPING, (sptr->name) ? sptr->name : "*",
+                 sptr->cookie);
+  }
+  return 0;
+}
+
+/*
+ * m_pong - normal message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int m_pong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  cptr->flags &= ~FLAGS_PINGSENT;
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_pong
+ *
+ * parv[0] = sender prefix
+ * parv[1] = origin
+ * parv[2] = destination
+ */
+int m_pong(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+  char *origin, *destination;
+
+  if (MyUser(sptr))
+    return 0;
+
+  /* Check to see if this is a PONG :cookie reply from an
+   * unregistered user.  If so, process it. -record       */
+
+  if ((!IsRegistered(sptr)) && (sptr->cookie != 0) &&
+      (sptr->cookie != COOKIE_VERIFIED) && (parc > 1))
+  {
+    if (atol(parv[parc - 1]) == (long)sptr->cookie)
+    {
+      sptr->cookie = COOKIE_VERIFIED;
+      if (sptr->user && *sptr->user->host && sptr->name[0])        /* NICK and
+                                                                   USER OK */
+        return register_user(cptr, sptr, sptr->name, sptr->user->username);
+    }
+    else
+      sendto_one(sptr, ":%s %d %s :To connect, type /QUOTE PONG %u",
+          me.name, ERR_BADPING, sptr->name, sptr->cookie);
+
+    return 0;
+  }
+
+  if (parc < 2 || *parv[1] == '\0')
+  {
+    sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
+    return 0;
+  }
+
+  origin = parv[1];
+  destination = parv[2];
+  cptr->flags &= ~FLAGS_PINGSENT;
+  sptr->flags &= ~FLAGS_PINGSENT;
+
+  if (!EmptyString(destination) && 0 != ircd_strcmp(destination, me.name))
+  {
+    if ((acptr = FindClient(destination)))
+      sendto_one(acptr, ":%s PONG %s %s", parv[0], origin, destination);
+    else
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
+          me.name, parv[0], destination);
+      return 0;
+    }
+  }
+#ifdef        DEBUGMODE
+  else
+    Debug((DEBUG_NOTICE, "PONG: %s %s",
+        origin, destination ? destination : "*"));
+#endif
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_privmsg.c b/ircd/m_privmsg.c
new file mode 100644 (file)
index 0000000..3a6f059
--- /dev/null
@@ -0,0 +1,459 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_privmsg.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_relay.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "send.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * m_privmsg - generic message handler
+ */
+int m_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(0 != sptr->user);
+
+  sptr->flags &= ~FLAGS_TS8;
+
+#ifdef IDLE_FROM_MSG
+  sptr->user->last = CurrentTime;
+#endif
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, MSG_PRIVATE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name)) {
+      relay_channel_message(sptr, name, parv[parc - 1]);
+    }
+    /*
+     * we have to check for the '@' at least once no matter what we do
+     * handle it first so we don't have to do it twice
+     */
+    else if ((server = strchr(name, '@')))
+      relay_directed_message(sptr, name, server, parv[parc - 1]);
+    else 
+      relay_private_message(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+/*
+ * ms_privmsg - server message handler template
+ */
+int ms_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* name;
+  char* server;
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 3) {
+    /*
+     * we can't deliver it, sending an error back is pointless
+     */
+    return 0;
+  }
+  name = parv[1];
+  /*
+   * channel msg?
+   */
+  if (IsChannelPrefix(*name)) {
+    server_relay_channel_message(sptr, name, parv[parc - 1]);
+  }
+  /*
+   * coming from another server, we have to check this here
+   */
+  else if ('$' == *name && IsOper(sptr)) {
+    server_relay_masked_message(sptr, name, parv[parc - 1]);
+  }
+  else if ((server = strchr(name, '@'))) {
+    /*
+     * XXX - can't get away with not doing everything
+     * relay_directed_message has to do
+     */
+    relay_directed_message(sptr, name, server, parv[parc - 1]);
+  }
+  else {
+    server_relay_private_message(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+
+/*
+ * mo_privmsg - oper message handler
+ */
+int mo_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*           name;
+  char*           server;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+  assert(0 != cptr);
+  assert(cptr == sptr);
+  assert(0 != sptr->user);
+
+  sptr->flags &= ~FLAGS_TS8;
+
+#ifdef IDLE_FROM_MSG
+  sptr->user->last = CurrentTime;
+#endif
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, MSG_PRIVATE);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+
+  for (i = 0; i < count; ++i) {
+    name = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelPrefix(*name))
+      relay_channel_message(sptr, name, parv[parc - 1]);
+
+    else if (*name == '$')
+      relay_masked_message(sptr, name, parv[parc - 1]);
+
+    else if ((server = strchr(name, '@')))
+      relay_directed_message(sptr, name, server, parv[parc - 1]);
+
+    else 
+      relay_private_message(sptr, name, parv[parc - 1]);
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_message (used in m_private() and m_notice())
+ *
+ * The general function to deliver MSG's between users/channels
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[parc-1] = message text
+ *
+ * massive cleanup
+ * rev argv 6/91
+ */
+static int m_message(struct Client *cptr, struct Client *sptr,
+    int parc, char *parv[], int notice)
+{
+  struct Client*  acptr;
+  char*           s;
+  struct Channel* chptr;
+  char*           nick;
+  char*           server;
+  char*           cmd;
+  char*           host;
+  int             i;
+  int             count;
+  char*           vector[MAXTARGETS];
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, cmd);
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+
+#if 0
+  if (MyUser(sptr))
+    parv[1] = canonize(parv[1]);
+  for (p = 0, nick = ircd_strtok(&p, parv[1], ","); nick;
+      nick = ircd_strtok(&p, 0, ","))
+#endif
+
+  count = unique_name_vector(parv[1], ',', vector, MAXTARGETS);
+  for (i = 0; i < count; ++i) {
+    nick = vector[i];
+    /*
+     * channel msg?
+     */
+    if (IsChannelName(nick))
+    {
+      if ((chptr = FindChannel(nick)))
+      {
+        /* This first: Almost never a server/service */
+        if (client_can_send_to_channel(sptr, chptr) || IsChannelService(sptr))
+        {
+          if (MyUser(sptr) && (chptr->mode.mode & MODE_NOPRIVMSGS) &&
+              check_target_limit(sptr, chptr, chptr->chname, 0))
+            continue;
+          sendmsgto_channel_butone(cptr, sptr, chptr,
+              parv[0], (notice ? TOK_NOTICE : TOK_PRIVATE), 
+              chptr->chname, parv[parc - 1]);
+        }
+        else if (!notice)
+          sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
+              me.name, parv[0], chptr->chname);
+        continue;
+      }
+    }
+    else if (*nick != '$' && !strchr(nick, '@'))
+    {
+      /*
+       * nickname addressed?
+       */
+      if (MyUser(sptr))
+        acptr = FindUser(nick);
+      else if ((acptr = findNUser(nick)) && !IsUser(acptr))
+        acptr = 0;
+      if (acptr)
+      {
+        if (MyUser(sptr) && check_target_limit(sptr, acptr, acptr->name, 0))
+          continue;
+        if (!is_silenced(sptr, acptr))
+        {
+          if (!notice && MyConnect(sptr) && acptr->user && acptr->user->away)
+            sendto_one(sptr, rpl_str(RPL_AWAY),
+                me.name, parv[0], acptr->name, acptr->user->away);
+          if (MyUser(acptr))
+          {
+            add_target(acptr, sptr);
+            sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                parv[0], cmd, acptr->name, parv[parc - 1]);
+          }
+          else
+            sendto_prefix_one(acptr, sptr, ":%s %s %s%s :%s",
+                parv[0], (notice ? TOK_NOTICE : TOK_PRIVATE),
+                NumNick(acptr), parv[parc - 1]);
+        }
+      }
+      else if (MyUser(sptr))
+        sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+      else
+        sendto_one(sptr,
+            ":%s %d %s * :Target left UnderNet. Failed to deliver: [%.50s]",
+            me.name, ERR_NOSUCHNICK, sptr->name, parv[parc - 1]);
+      continue;
+    }
+    /*
+     * The following two cases allow masks in NOTICEs
+     * (for OPERs only)
+     *
+     * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
+     */
+    if ((*nick == '$' || *nick == '#') && IsAnOper(sptr))
+    {
+      if (MyConnect(sptr))
+      {
+        if (!(s = strrchr(nick, '.')))
+        {
+          sendto_one(sptr, err_str(ERR_NOTOPLEVEL), me.name, parv[0], nick);
+          continue;
+        }
+        while (*++s)
+          if (*s == '.' || *s == '*' || *s == '?')
+            break;
+        if (*s == '*' || *s == '?')
+        {
+          sendto_one(sptr, err_str(ERR_WILDTOPLEVEL), me.name, parv[0], nick);
+          continue;
+        }
+      }
+      sendto_match_butone(IsServer(cptr) ? cptr : 0,
+          sptr, nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
+          ":%s %s %s :%s", parv[0], cmd, nick, parv[parc - 1]);
+      continue;
+    }
+    else if ((server = strchr(nick, '@')) && (acptr = FindServer(server + 1)))
+    {
+      /*
+       * NICK[%host]@server addressed? See if <server> is me first
+       */
+      if (!IsMe(acptr))
+      {
+        sendto_one(acptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[parc - 1]);
+        continue;
+      }
+
+      /* Look for an user whose NICK is equal to <nick> and then
+       * check if it's hostname matches <host> and if it's a local
+       * user. */
+      *server = '\0';
+      if ((host = strchr(nick, '%')))
+        *host++ = '\0';
+
+      if ((!(acptr = FindUser(nick))) ||
+          (!(MyUser(acptr))) ||
+          ((!(EmptyString(host))) && match(host, acptr->user->host)))
+        acptr = 0;
+
+      *server = '@';
+      if (host)
+        *--host = '%';
+
+      if (acptr)
+      {
+        if (!(is_silenced(sptr, acptr)))
+          sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+              parv[0], cmd, nick, parv[parc - 1]);
+        continue;
+      }
+    }
+    if (IsChannelName(nick))
+      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], nick);
+    else
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+  }
+  return 0;
+}
+
+/*
+ * m_private
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[parc-1] = message text
+ */
+int m_private(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  return m_message(cptr, sptr, parc, parv, 0);
+}
+
+#if !defined(XXX_BOGUS_TEMP_HACK)
+#include "handlers.h"
+#endif
+/*
+ * m_notice
+ *
+ * parv[0] = sender prefix
+ * parv[1] = receiver list
+ * parv[parc-1] = notice text
+ */
+int m_notice(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  if (MyUser(sptr) && parv[1] && parv[1][0] == '@' &&
+      IsChannelName(&parv[1][1]))
+  {
+    parv[1]++;                        /* Get rid of '@' */
+    return m_wallchops(cptr, sptr, parc, parv);
+  }
+  return m_message(cptr, sptr, parc, parv, 1);
+}
+
+#endif
diff --git a/ircd/m_proto.c b/ircd/m_proto.c
new file mode 100644 (file)
index 0000000..9abd3d1
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_proto.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "supported.h"
+#include "version.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+
+static const char* const PROTO_REQ = "REQ";
+static const char* const PROTO_ACK = "ACK";
+
+int proto_handle_ack(struct Client* cptr, const char* msg)
+{
+  /*
+   * handle ack here, if option and args supported
+   * start option
+   */ 
+  return 0;
+}
+
+int proto_handle_req(struct Client* cptr, const char* msg)
+{
+  /*
+   * handle request here if not supported args send
+   * option info. otherwise send ack
+   */
+  return 0;
+}
+
+int proto_send_supported(struct Client* cptr)
+{
+  /*
+   * sendto_one(cptr, RPL_PROTOLIST, me.name, cptr->name, "stuff");
+   */
+  return 0;
+}
+
+int m_proto(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (0 == parc)
+    return proto_send_supported(cptr);
+
+  if (parc < 3) 
+    return need_more_params(sptr, "PROTO");
+
+  if (0 == ircd_strcmp(PROTO_REQ, parv[1]))
+    return proto_handle_req(cptr, parv[2]);
+
+  else if (0 == ircd_strcmp(PROTO_ACK, parv[1]))
+    return proto_handle_ack(cptr, parv[2]);
+
+  return 0;
+}
+
+  
diff --git a/ircd/m_quit.c b/ircd/m_quit.c
new file mode 100644 (file)
index 0000000..4d352d3
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_quit.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "ircd_string.h"
+#include "struct.h"
+#include "s_misc.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * m_quit - client message handler 
+ *
+ * parv[0]        = sender prefix
+ * parv[parc - 1] = comment
+ */
+int m_quit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char* comment;
+  assert(0 != cptr);
+  assert(0 != sptr);
+  assert(cptr == sptr);
+
+  if (sptr->user) {
+    struct Membership* chan;
+    for (chan = sptr->user->channel; chan; chan = chan->next_channel) {
+      if (!IsZombie(chan) && !member_can_send_to_channel(chan))
+        return exit_client(cptr, sptr, sptr, "Signed off");
+    }
+  }
+  comment = cptr->name;
+
+  if (parc > 1) {
+    comment = parv[parc - 1];
+
+    if (0 == strncmp("Local kill", comment, 10) || 0 == strncmp(comment, "Killed", 6))
+       comment = cptr->name;
+    else if (strlen(comment) > TOPICLEN)
+      comment[TOPICLEN] = '\0';
+  }
+  return exit_client(cptr, sptr, sptr, comment);
+}
+
+
+/*
+ * ms_quit - server message handler template
+ *
+ * parv[0] = sender prefix
+ * parv[parc - 1] = comment
+ */
+int ms_quit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != sptr);
+  assert(parc > 0);
+  /*
+   * ignore quit from servers
+   */
+  return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, parv[parc - 1]);
+}
+
+#if 0
+/*
+ * m_quit
+ *
+ * parv[0] = sender prefix
+ * parv[parc-1] = comment
+ */
+int m_quit(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *comment = (parc > 1 && parv[parc - 1]) ? parv[parc - 1] : cptr->name;
+
+  if (MyUser(sptr))
+  {
+    if (!strncmp("Local Kill", comment, 10) || !strncmp(comment, "Killed", 6))
+      comment = parv[0];
+    if (sptr->user)
+    {
+      struct Membership* chan;
+      for (chan = sptr->user->channel; chan; chan = chan->next_channel)
+        if (!IsZombie(chan) && !member_can_send_to_channel(chan))
+          return exit_client(cptr, sptr, sptr, "Signed off");
+    }
+  }
+  if (strlen(comment) > (size_t)TOPICLEN)
+    comment[TOPICLEN] = '\0';
+  return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, comment);
+}
+
+#endif /* 0 */
diff --git a/ircd/m_rehash.c b/ircd/m_rehash.c
new file mode 100644 (file)
index 0000000..000f94b
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_rehash.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "s_conf.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mo_rehash - oper message handler
+ */
+int mo_rehash(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
+#ifndef LOCOP_REHASH
+  if (!MyUser(sptr) || !IsOper(sptr))
+#else
+#ifdef  OPER_REHASH
+  if (!MyUser(sptr) || !IsAnOper(sptr))
+#else
+  if (!MyUser(sptr) || !IsLocOp(sptr))
+#endif
+#endif
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
+  sendto_ops("%s is rehashing Server config file", parv[0]);
+  ircd_log(L_INFO, "REHASH From %s\n", get_client_name(sptr, HIDE_IP));
+  return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
+#endif /* defined(OPER_REHASH) || defined(LOCOP_REHASH) */
+  return 0;
+}
+
+#if 0
+#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
+/*
+ * m_rehash
+ */
+int m_rehash(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+#ifndef LOCOP_REHASH
+  if (!MyUser(sptr) || !IsOper(sptr))
+#else
+#ifdef  OPER_REHASH
+  if (!MyUser(sptr) || !IsAnOper(sptr))
+#else
+  if (!MyUser(sptr) || !IsLocOp(sptr))
+#endif
+#endif
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
+  sendto_ops("%s is rehashing Server config file", parv[0]);
+  ircd_log(L_INFO, "REHASH From %s\n", get_client_name(sptr, HIDE_IP));
+  return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
+}
+#endif
+#endif /* 0 */
+
diff --git a/ircd/m_restart.c b/ircd/m_restart.c
new file mode 100644 (file)
index 0000000..290dc98
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_restart.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * mo_restart - oper message handler
+ */
+int mo_restart(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
+#ifndef LOCOP_RESTART
+  if (!MyUser(sptr) || !IsOper(sptr))
+#else
+#ifdef  OPER_RESTART
+  if (!MyUser(sptr) || !IsAnOper(sptr))
+#else
+  if (!MyUser(sptr) || !IsLocOp(sptr))
+#endif
+#endif
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  ircd_log(L_NOTICE, "Server RESTART by %s\n", get_client_name(sptr, HIDE_IP));
+  server_restart("received RESTART");
+
+#endif /* defined(OPER_RESTART) || defined(LOCOP_RESTART) */
+  return 0;
+}
+
+
+#if 0
+#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
+/*
+ * m_restart
+ */
+int m_restart(struct Client *cptr, struct Client *sptr, int parc,
+    char *parv[])
+{
+#ifndef LOCOP_RESTART
+  if (!MyUser(sptr) || !IsOper(sptr))
+#else
+#ifdef  OPER_RESTART
+  if (!MyUser(sptr) || !IsAnOper(sptr))
+#else
+  if (!MyUser(sptr) || !IsLocOp(sptr))
+#endif
+#endif
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  ircd_log(L_NOTICE, "Server RESTART by %s\n", get_client_name(sptr, HIDE_IP));
+  server_restart("received RESTART");
+  return 0;
+}
+#endif
+#endif /* 0 */
diff --git a/ircd/m_rping.c b/ircd/m_rping.c
new file mode 100644 (file)
index 0000000..5cdaae9
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_rping.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * ms_rping - server message handler
+ * -- by Run
+ *
+ *    parv[0] = sender (sptr->name thus)
+ * if sender is a person: (traveling towards start server)
+ *    parv[1] = pinged server[mask]
+ *    parv[2] = start server (current target)
+ *    parv[3] = optional remark
+ * if sender is a server: (traveling towards pinged server)
+ *    parv[1] = pinged server (current target)
+ *    parv[2] = original sender (person)
+ *    parv[3] = start time in s
+ *    parv[4] = start time in us
+ *    parv[5] = the optional remark
+ */
+int ms_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (parc < (IsAnOper(sptr) ? (MyConnect(sptr) ? 2 : 3) : 6))
+  {
+    return need_more_params(sptr, "RPING");
+    return 0;
+  }
+  if (MyUser(sptr))
+  {
+    if (parc == 2)
+      parv[parc++] = me.name;
+    else if (!(acptr = find_match_server(parv[2])))
+    {
+      parv[3] = parv[2];
+      parv[2] = me.name;
+      parc++;
+    }
+    else
+      parv[2] = acptr->name;
+    if (parc == 3)
+      parv[parc++] = "<No client start time>";
+  }
+
+  if (IsAnOper(sptr))
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_RPING " %s %s :%s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    if (!(acptr = find_match_server(parv[1])) || !IsServer(acptr))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
+      return 0;
+    }
+    sendto_one(acptr, ":%s RPING %s %s %s :%s",
+         me.name, NumServ(acptr), sptr->name, militime(0, 0), parv[3]);
+  }
+  else
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_RPING " %s %s %s %s :%s", 1, parc, parv)
+        != HUNTED_ISME)
+      return 0;
+    sendto_one(cptr, ":%s RPONG %s %s %s %s :%s", me.name, parv[0],
+        parv[2], parv[3], parv[4], parv[5]);
+  }
+  return 0;
+}
+
+/*
+ * mo_rping - oper message handler
+ * -- by Run
+ *
+ *    parv[0] = sender (sptr->name thus)
+ * if sender is a person: (traveling towards start server)
+ *    parv[1] = pinged server[mask]
+ *    parv[2] = start server (current target)
+ *    parv[3] = optional remark
+ * if sender is a server: (traveling towards pinged server)
+ *    parv[1] = pinged server (current target)
+ *    parv[2] = original sender (person)
+ *    parv[3] = start time in s
+ *    parv[4] = start time in us
+ *    parv[5] = the optional remark
+ */
+int mo_rping(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (parc < (IsAnOper(sptr) ? (MyConnect(sptr) ? 2 : 3) : 6))
+  {
+    return need_more_params(sptr, "RPING");
+    return 0;
+  }
+  if (MyUser(sptr))
+  {
+    if (parc == 2)
+      parv[parc++] = me.name;
+    else if (!(acptr = find_match_server(parv[2])))
+    {
+      parv[3] = parv[2];
+      parv[2] = me.name;
+      parc++;
+    }
+    else
+      parv[2] = acptr->name;
+    if (parc == 3)
+      parv[parc++] = "<No client start time>";
+  }
+
+  if (IsAnOper(sptr))
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_RPING " %s %s :%s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    if (!(acptr = find_match_server(parv[1])) || !IsServer(acptr))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
+      return 0;
+    }
+    sendto_one(acptr, ":%s RPING %s %s %s :%s",
+         me.name, NumServ(acptr), sptr->name, militime(0, 0), parv[3]);
+  }
+  else
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_RPING " %s %s %s %s :%s", 1, parc, parv)
+        != HUNTED_ISME)
+      return 0;
+    sendto_one(cptr, ":%s RPONG %s %s %s %s :%s", me.name, parv[0],
+        parv[2], parv[3], parv[4], parv[5]);
+  }
+  return 0;
+}
+
+#if 0
+/*
+ * m_rping  -- by Run
+ *
+ *    parv[0] = sender (sptr->name thus)
+ * if sender is a person: (traveling towards start server)
+ *    parv[1] = pinged server[mask]
+ *    parv[2] = start server (current target)
+ *    parv[3] = optional remark
+ * if sender is a server: (traveling towards pinged server)
+ *    parv[1] = pinged server (current target)
+ *    parv[2] = original sender (person)
+ *    parv[3] = start time in s
+ *    parv[4] = start time in us
+ *    parv[5] = the optional remark
+ */
+int m_rping(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (parc < (IsAnOper(sptr) ? (MyConnect(sptr) ? 2 : 3) : 6))
+  {
+    return need_more_params(sptr, "RPING");
+    return 0;
+  }
+  if (MyUser(sptr))
+  {
+    if (parc == 2)
+      parv[parc++] = me.name;
+    else if (!(acptr = find_match_server(parv[2])))
+    {
+      parv[3] = parv[2];
+      parv[2] = me.name;
+      parc++;
+    }
+    else
+      parv[2] = acptr->name;
+    if (parc == 3)
+      parv[parc++] = "<No client start time>";
+  }
+
+  if (IsAnOper(sptr))
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_RPING " %s %s :%s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    if (!(acptr = find_match_server(parv[1])) || !IsServer(acptr))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
+      return 0;
+    }
+    sendto_one(acptr, ":%s RPING %s %s %s :%s",
+         me.name, NumServ(acptr), sptr->name, militime(0, 0), parv[3]);
+  }
+  else
+  {
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_RPING " %s %s %s %s :%s", 1, parc, parv)
+        != HUNTED_ISME)
+      return 0;
+    sendto_one(cptr, ":%s RPONG %s %s %s %s :%s", me.name, parv[0],
+        parv[2], parv[3], parv[4], parv[5]);
+  }
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_rpong.c b/ircd/m_rpong.c
new file mode 100644 (file)
index 0000000..ce0278a
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_rpong.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * ms_rpong - server message handler
+ * -- by Run too :)
+ *
+ * parv[0] = sender prefix
+ * parv[1] = from pinged server: start server; from start server: sender
+ * parv[2] = from pinged server: sender; from start server: pinged server
+ * parv[3] = pingtime in ms
+ * parv[4] = client info (for instance start time)
+ */
+int ms_rpong(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (!IsServer(sptr))
+    return 0;
+
+  if (parc < 5)
+    return need_more_params(sptr, "RPING");
+
+  if (!(acptr = FindClient(parv[1])))
+    return 0;
+
+  if (!IsMe(acptr))
+  {
+    if (IsServer(acptr) && parc > 5)
+    {
+      sendto_one(acptr, ":%s RPONG %s %s %s %s :%s",
+          parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
+      return 0;
+    }
+  }
+  else
+  {
+    parv[1] = parv[2];
+    parv[2] = sptr->name;
+    parv[0] = me.name;
+    parv[3] = militime(parv[3], parv[4]);
+    parv[4] = parv[5];
+    if (!(acptr = FindUser(parv[1])))
+      return 0;                 /* No bouncing between servers ! */
+  }
+
+  sendto_one(acptr, ":%s RPONG %s %s %s :%s",
+      parv[0], parv[1], parv[2], parv[3], parv[4]);
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_rpong  -- by Run too :)
+ *
+ * parv[0] = sender prefix
+ * parv[1] = from pinged server: start server; from start server: sender
+ * parv[2] = from pinged server: sender; from start server: pinged server
+ * parv[3] = pingtime in ms
+ * parv[4] = client info (for instance start time)
+ */
+int m_rpong(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+
+  if (!IsServer(sptr))
+    return 0;
+
+  if (parc < 5)
+    return need_more_params(sptr, "RPING");
+
+  if (!(acptr = FindClient(parv[1])))
+    return 0;
+
+  if (!IsMe(acptr))
+  {
+    if (IsServer(acptr) && parc > 5)
+    {
+      sendto_one(acptr, ":%s RPONG %s %s %s %s :%s",
+          parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
+      return 0;
+    }
+  }
+  else
+  {
+    parv[1] = parv[2];
+    parv[2] = sptr->name;
+    parv[0] = me.name;
+    parv[3] = militime(parv[3], parv[4]);
+    parv[4] = parv[5];
+    if (!(acptr = FindUser(parv[1])))
+      return 0;                 /* No bouncing between servers ! */
+  }
+
+  sendto_one(acptr, ":%s RPONG %s %s %s :%s",
+      parv[0], parv[1], parv[2], parv[3], parv[4]);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_server.c b/ircd/m_server.c
new file mode 100644 (file)
index 0000000..baaaf58
--- /dev/null
@@ -0,0 +1,2098 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_server.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "crule.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_serv.h"
+#include "send.h"
+#include "userload.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * mr_server - registration message handler
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = hopcount
+ *    parv[3] = start timestamp
+ *    parv[4] = link timestamp
+ *    parv[5] = major protocol version: P09/P10
+ *    parv[parc-1] = serverinfo
+ *  If cptr is P10:
+ *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
+ *              numeric nick mask of this server.
+ *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
+ */
+int mr_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*            ch;
+  int              i;
+  char             info[REALLEN + 1];
+  char*            host;
+  struct Client*   acptr;
+  struct Client*   bcptr;
+  struct Client*   LHcptr = 0;
+  struct ConfItem* aconf = 0;
+  struct ConfItem* cconf;
+  struct ConfItem* lhconf = 0;
+  int              hop;
+  int              ret;
+  int              active_lh_line = 0;
+  unsigned short   prot;
+  time_t           start_timestamp;
+  time_t           timestamp = 0;
+  time_t           recv_time;
+  time_t           ghost = 0;
+
+  if (IsUser(cptr))
+  {
+    sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
+    return 0;
+  }
+
+  if (IsUserPort(cptr))
+    return exit_client_msg(cptr, cptr, &me, 
+                           "Cannot connect a server to a user port");
+
+  recv_time = TStime();
+  info[0] = '\0';
+
+  if (parc < 7)
+  {
+    return need_more_params(sptr, "SERVER");
+    return exit_client(cptr, cptr, &me, "Need more parameters");
+  }
+  ircd_log(L_NOTICE, "SERVER: %s %s[%s]", parv[1], cptr->sockhost, cptr->sock_ip);
+  host = parv[1];
+  /*
+   * Detect protocol
+   */
+  if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
+    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
+
+  if (!IsServer(cptr))          /* Don't allow silently connecting a server */
+    *parv[5] = 'J';
+
+  prot = atoi(parv[5] + 1);
+  if (prot > atoi(MAJOR_PROTOCOL))
+    prot = atoi(MAJOR_PROTOCOL);
+  /*
+   * Because the previous test is only in 2.10, the following is needed
+   * till all servers are 2.10:
+   */
+  if (IsServer(cptr) && prot > Protocol(cptr))
+    prot = Protocol(cptr);
+  hop = atoi(parv[2]);
+  start_timestamp = atoi(parv[3]);
+  timestamp = atoi(parv[4]);
+  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
+        TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
+
+  if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
+  {
+    return exit_client_msg(cptr, sptr, &me,
+        "Bogus timestamps (%s %s)", parv[3], parv[4]);
+  }
+  ircd_strncpy(info, parv[parc - 1], REALLEN);
+  info[REALLEN] = '\0';
+  if (prot < atoi(MINOR_PROTOCOL)) {
+    sendto_ops("Got incompatible protocol version (%s) from %s",
+               parv[5], cptr->name);
+    return exit_new_server(cptr, sptr, host, timestamp,
+                           "Incompatible protocol: %s", parv[5]);
+  }
+  /*
+   * Check for "FRENCH " infection ;-) (actually this should
+   * be replaced with routine to check the hostname syntax in
+   * general). [ This check is still needed, even after the parse
+   * is fixed, because someone can send "SERVER :foo bar " ].
+   * Also, changed to check other "difficult" characters, now
+   * that parse lets all through... --msa
+   */
+  if (strlen(host) > HOSTLEN)
+    host[HOSTLEN] = '\0';
+
+  for (ch = host; *ch; ch++) {
+    if (*ch <= ' ' || *ch > '~')
+      break;
+  }
+  if (*ch || !strchr(host, '.')) {
+    sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
+    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
+  }
+
+  if (IsServer(cptr))
+  {
+    /*
+     * A local server introduces a new server behind this link.
+     * Check if this is allowed according L:, H: and Q: lines.
+     */
+    if (info[0] == '\0')
+      return exit_client_msg(cptr, cptr, &me,
+                             "No server info specified for %s", host);
+    /*
+     * See if the newly found server is behind a guaranteed
+     * leaf (L-line). If so, close the link.
+     */
+    if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
+        (!lhconf->port || (hop > lhconf->port)))
+    {
+      /*
+       * L: lines normally come in pairs, here we try to
+       * make sure that the oldest link is squitted, not
+       * both.
+       */
+      active_lh_line = 1;
+      if (timestamp <= cptr->serv->timestamp)
+        LHcptr = 0;          /* Kill incoming server */
+      else
+        LHcptr = cptr;          /* Squit ourselfs */
+    }
+    else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
+             (lhconf->port && (hop > lhconf->port)))
+    {
+      struct Client *ac3ptr;
+      active_lh_line = 2;
+      /* Look for net junction causing this: */
+      LHcptr = 0;            /* incoming server */
+      if (*parv[5] != 'J') {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
+          if (IsJunction(ac3ptr)) {
+            LHcptr = ac3ptr;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  if (IsUnknown(cptr) || IsHandshake(cptr))
+  {
+    const char* encr;
+
+    /*
+     * A local link that is still in undefined state wants
+     * to be a SERVER. Check if this is allowed and change
+     * status accordingly...
+     */
+    /*
+     * If there is more then one server on the same machine
+     * that we try to connect to, it could be that the /CONNECT
+     * <mask> caused this connect to be put at the wrong place
+     * in the hashtable.        --Run
+     * Same thing for Unknown connections that first send NICK.
+     *                          --Xorath
+     * Better check if the two strings are (caseless) identical 
+     * and not mess with hash internals. 
+     *                          --Nemesi
+     */
+    if (!EmptyString(cptr->name) && 
+        (IsUnknown(cptr) || IsHandshake(cptr)) &&
+        0 != ircd_strcmp(cptr->name, host))
+      hChangeClient(cptr, host);
+    ircd_strncpy(cptr->name, host, HOSTLEN);
+    ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
+    cptr->hopcount = hop;
+
+    /* check connection rules */
+    for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
+      if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
+        if (crule_eval(cconf->passwd)) {
+          ServerStats->is_ref++;
+          sendto_ops("Refused connection from %s.", cptr->name);
+          return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
+        }
+      }
+    }
+    if (conf_check_server(cptr)) {
+      ++ServerStats->is_ref;
+      sendto_ops("Received unauthorized connection from %s.", cptr->name);
+      return exit_client(cptr, cptr, &me, "No C:line");
+    }
+
+    host = cptr->name;
+
+    update_load();
+
+    if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
+      ++ServerStats->is_ref;
+#ifndef GODMODE
+      sendto_ops("Access denied. No conf line for server %s", cptr->name);
+      return exit_client_msg(cptr, cptr, &me,
+          "Access denied. No conf line for server %s", cptr->name);
+#else /* GODMODE */
+      sendto_ops("General C: line active: No line for server %s", cptr->name);
+      aconf = find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
+      if (!aconf) {
+        sendto_ops("Neither C lines for server %s nor "
+            "\"general.undernet.org\"", cptr->name);
+        return exit_client_msg(cptr, cptr, &me, "No C lines for server %s", cptr->name);
+      }
+#endif /* GODMODE */
+    }
+#ifdef CRYPT_LINK_PASSWORD
+    /* passwd may be NULL. Head it off at the pass... */
+    if (*cptr->passwd) {
+      char salt[3];
+
+      salt[0] = aconf->passwd[0];
+      salt[1] = aconf->passwd[1];
+      salt[2] = '\0';
+      encr = ircd_crypt(cptr->passwd, salt);
+    }
+    else
+      encr = "";
+#else
+    encr = cptr->passwd;
+#endif /* CRYPT_LINK_PASSWORD */
+#ifndef GODMODE
+    if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
+      ++ServerStats->is_ref;
+      sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
+      return exit_client_msg(cptr, cptr, &me,
+          "No Access (passwd mismatch) %s", cptr->name);
+    }
+#endif /* not GODMODE */
+    memset(cptr->passwd, 0, sizeof(cptr->passwd));
+
+#ifndef HUB
+    for (i = 0; i <= HighestFd; i++)
+      if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
+        active_lh_line = 3;
+        LHcptr = 0;
+        break;
+      }
+#endif
+  }
+
+  /*
+   *  We want to find IsConnecting() and IsHandshake() too,
+   *  use FindClient().
+   *  The second finds collisions with numeric representation of existing
+   *  servers - these shouldn't happen anymore when all upgraded to 2.10.
+   *  -- Run
+   */
+  while ((acptr = FindClient(host)) || 
+         (parc > 7 && (acptr = FindNServer(parv[6]))))
+  {
+    /*
+     *  This link is trying feed me a server that I already have
+     *  access through another path
+     *
+     *  Do not allow Uworld to do this.
+     *  Do not allow servers that are juped.
+     *  Do not allow servers that have older link timestamps
+     *    then this try.
+     *  Do not allow servers that use the same numeric as an existing
+     *    server, but have a different name.
+     *
+     *  If my ircd.conf sucks, I can try to connect to myself:
+     */
+    if (acptr == &me)
+      return exit_client_msg(cptr, cptr, &me, "nick collision with me (%s)", host);
+    /*
+     * Detect wrong numeric.
+     */
+    if (0 != ircd_strcmp(acptr->name, host)) {
+      sendto_serv_butone(cptr,
+          ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
+          me.name, acptr->name, host);
+      return exit_client_msg(cptr, cptr, &me,
+          "NUMERIC collision between %s and %s."
+          " Is your server numeric correct ?", host, acptr->name);
+    }
+    /*
+     *  Kill our try, if we had one.
+     */
+    if (IsConnecting(acptr))
+    {
+      if (!active_lh_line && exit_client(cptr, acptr, &me,
+          "Just connected via another link") == CPTR_KILLED)
+        return CPTR_KILLED;
+      /*
+       * We can have only ONE 'IsConnecting', 'IsHandshake' or
+       * 'IsServer', because new 'IsConnecting's are refused to
+       * the same server if we already had it.
+       */
+      break;
+    }
+    /*
+     * Avoid other nick collisions...
+     * This is a doubtfull test though, what else would it be
+     * when it has a server.name ?
+     */
+    else if (!IsServer(acptr) && !IsHandshake(acptr))
+      return exit_client_msg(cptr, cptr, &me,
+                             "Nickname %s already exists!", host);
+    /*
+     * Our new server might be a juped server,
+     * or someone trying abuse a second Uworld:
+     */
+    else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
+        find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
+    {
+      if (!IsServer(sptr))
+        return exit_client(cptr, sptr, &me, acptr->info);
+      sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
+          me.name, parv[0], parv[1], cptr->name);
+      return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
+    }
+    /*
+     * Of course we find the handshake this link was before :)
+     */
+    else if (IsHandshake(acptr) && acptr == cptr)
+      break;
+    /*
+     * Here we have a server nick collision...
+     * We don't want to kill the link that was last /connected,
+     * but we neither want to kill a good (old) link.
+     * Therefor we kill the second youngest link.
+     */
+    if (1)
+    {
+      struct Client* c2ptr = 0;
+      struct Client* c3ptr = acptr;
+      struct Client* ac2ptr;
+      struct Client* ac3ptr;
+
+      /* Search youngest link: */
+      for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
+        if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
+          c3ptr = ac3ptr;
+      if (IsServer(sptr))
+      {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
+          if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
+            c3ptr = ac3ptr;
+      }
+      if (timestamp > c3ptr->serv->timestamp)
+      {
+        c3ptr = 0;
+        c2ptr = acptr;          /* Make sure they differ */
+      }
+      /* Search second youngest link: */
+      for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
+        if (ac2ptr != c3ptr &&
+            ac2ptr->serv->timestamp >
+            (c2ptr ? c2ptr->serv->timestamp : timestamp))
+          c2ptr = ac2ptr;
+      if (IsServer(sptr))
+      {
+        for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
+          if (ac2ptr != c3ptr &&
+              ac2ptr->serv->timestamp >
+              (c2ptr ? c2ptr->serv->timestamp : timestamp))
+            c2ptr = ac2ptr;
+      }
+      if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
+        c2ptr = 0;
+      /* If timestamps are equal, decide which link to break
+       *  by name.
+       */
+      if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
+          (c3ptr ? c3ptr->serv->timestamp : timestamp))
+      {
+        char* n2;
+        char* n2up;
+        char* n3;
+        char* n3up;
+        if (c2ptr)
+        {
+          n2 = c2ptr->name;
+          n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
+        }
+        else
+        {
+          n2 = host;
+          n2up = IsServer(sptr) ? sptr->name : me.name;
+        }
+        if (c3ptr)
+        {
+          n3 = c3ptr->name;
+          n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
+        }
+        else
+        {
+          n3 = host;
+          n3up = IsServer(sptr) ? sptr->name : me.name;
+        }
+        if (strcmp(n2, n2up) > 0)
+          n2 = n2up;
+        if (strcmp(n3, n3up) > 0)
+          n3 = n3up;
+        if (strcmp(n3, n2) > 0)
+        {
+          ac2ptr = c2ptr;
+          c2ptr = c3ptr;
+          c3ptr = ac2ptr;
+        }
+      }
+      /* Now squit the second youngest link: */
+      if (!c2ptr)
+        return exit_new_server(cptr, sptr, host, timestamp,
+                               "server %s already exists and is %ld seconds younger.",
+                               host, (long)acptr->serv->timestamp - (long)timestamp);
+      else if (c2ptr->from == cptr || IsServer(sptr))
+      {
+        struct Client *killedptrfrom = c2ptr->from;
+        if (active_lh_line)
+        {
+          /*
+           * If the L: or H: line also gets rid of this link,
+           * we sent just one squit.
+           */
+          if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
+            break;
+          /*
+           * If breaking the loop here solves the L: or H:
+           * line problem, we don't squit that.
+           */
+          if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            /*
+             * If we still have a L: or H: line problem,
+             * we prefer to squit the new server, solving
+             * loop and L:/H: line problem with only one squit.
+             */
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * If the new server was introduced by a server that caused a
+         * Ghost less then 20 seconds ago, this is probably also
+         * a Ghost... (20 seconds is more then enough because all
+         * SERVER messages are at the beginning of a net.burst). --Run
+         */
+        if (CurrentTime - cptr->serv->ghost < 20)
+        {
+          killedptrfrom = acptr->from;
+          if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
+            return CPTR_KILLED;
+        }
+        else if (exit_client_msg(cptr, c2ptr, &me,
+            "Loop <-- %s (new link is %ld seconds younger)", host,
+            (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
+            (long)c2ptr->serv->timestamp) == CPTR_KILLED)
+          return CPTR_KILLED;
+        /*
+         * Did we kill the incoming server off already ?
+         */
+        if (killedptrfrom == cptr)
+          return 0;
+      }
+      else
+      {
+        if (active_lh_line)
+        {
+          if (LHcptr && a_kills_b_too(LHcptr, acptr))
+            break;
+          if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * We can't believe it is a lagged server message
+         * when it directly connects to us...
+         * kill the older link at the ghost, rather then
+         * at the second youngest link, assuming it isn't
+         * a REAL loop.
+         */
+        ghost = CurrentTime;            /* Mark that it caused a ghost */
+        if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
+          return CPTR_KILLED;
+        break;
+      }
+    }
+  }
+
+  if (active_lh_line)
+  {
+    if (LHcptr == 0) {
+      return exit_new_server(cptr, sptr, host, timestamp,
+          (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
+          cptr->name, host, 
+          lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
+    }
+    else
+    {
+      int killed = a_kills_b_too(LHcptr, sptr);
+      if (active_lh_line < 3)
+      {
+        if (exit_client_msg(cptr, LHcptr, &me,
+            (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
+            cptr->name, host,
+            lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
+          return CPTR_KILLED;
+      }
+      else
+      {
+        ServerStats->is_ref++;
+        if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
+          return CPTR_KILLED;
+      }
+      /*
+       * Did we kill the incoming server off already ?
+       */
+      if (killed)
+        return 0;
+    }
+  }
+
+  if (IsServer(cptr))
+  {
+    /*
+     * Server is informing about a new server behind
+     * this link. Create REMOTE server structure,
+     * add it to list and propagate word to my other
+     * server links...
+     */
+
+    acptr = make_client(cptr, STAT_SERVER);
+    make_server(acptr);
+    acptr->serv->prot = prot;
+    acptr->serv->timestamp = timestamp;
+    acptr->hopcount = hop;
+    ircd_strncpy(acptr->name, host, HOSTLEN);
+    ircd_strncpy(acptr->info, info, REALLEN);
+    acptr->serv->up = sptr;
+    acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
+    /* Use cptr, because we do protocol 9 -> 10 translation
+       for numeric nicks ! */
+    SetServerYXX(cptr, acptr, parv[6]);
+
+    Count_newremoteserver(UserStats);
+    if (Protocol(acptr) < 10)
+      acptr->flags |= FLAGS_TS8;
+    add_client_to_list(acptr);
+    hAddClient(acptr);
+    if (*parv[5] == 'J')
+    {
+      SetBurst(acptr);
+      sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
+          sptr->name, acptr->name);
+      SetJunction(acptr);
+    }
+    /*
+     * Old sendto_serv_but_one() call removed because we now need to send
+     * different names to different servers (domain name matching).
+     */
+    for (i = 0; i <= HighestFd; i++)
+    {
+      if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
+          bcptr == cptr || IsMe(bcptr))
+        continue;
+      if (0 == match(me.name, acptr->name))
+        continue;
+        sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
+            NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
+            NumServCap(acptr), acptr->info);
+    }
+    return 0;
+  }
+
+  if (IsUnknown(cptr) || IsHandshake(cptr))
+  {
+    make_server(cptr);
+    cptr->serv->timestamp = timestamp;
+    cptr->serv->prot = prot;
+    cptr->serv->ghost = ghost;
+    SetServerYXX(cptr, cptr, parv[6]);
+    if (start_timestamp > OLDEST_TS)
+    {
+#ifndef RELIABLE_CLOCK
+#ifdef TESTNET
+      sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
+          TIME_T_FMT, me.serv->timestamp, start_timestamp);
+      sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
+          TIME_T_FMT " ; difference %ld",
+          recv_time, timestamp, timestamp - recv_time);
+#endif
+      if (start_timestamp < me.serv->timestamp)
+      {
+        sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
+            start_timestamp, me.serv->timestamp);
+        me.serv->timestamp = start_timestamp;
+        TSoffset += timestamp - recv_time;
+        sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
+      }
+      else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
+        cptr->serv->timestamp = TStime();
+
+      else if (timestamp != recv_time)
+      {
+        /*
+         * Equal start times, we have a collision.  Let the connected-to server
+         * decide. This assumes leafs issue more than half of the connection
+         * attempts.
+         */
+        if (IsUnknown(cptr))
+          cptr->serv->timestamp = TStime();
+        else if (IsHandshake(cptr))
+        {
+          sendto_ops("clock adjusted by adding %d",
+              (int)(timestamp - recv_time));
+          TSoffset += timestamp - recv_time;
+        }
+      }
+#else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
+      if (start_timestamp < me.serv->timestamp)
+        me.serv->timestamp = start_timestamp;
+      if (IsUnknown(cptr))
+        cptr->serv->timestamp = TStime();
+#endif
+    }
+
+    ret = server_estab(cptr, aconf);
+  }
+  else
+    ret = 0;
+#ifdef RELIABLE_CLOCK
+  if (abs(cptr->serv->timestamp - recv_time) > 30)
+  {
+    sendto_ops("Connected to a net with a timestamp-clock"
+        " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
+        " this.", timestamp - recv_time);
+    sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
+        me.name, TStime(), me.name);
+  }
+#endif
+
+  return ret;
+}
+
+/*
+ * ms_server - server message handler
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = hopcount
+ *    parv[3] = start timestamp
+ *    parv[4] = link timestamp
+ *    parv[5] = major protocol version: P09/P10
+ *    parv[parc-1] = serverinfo
+ *  If cptr is P10:
+ *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
+ *              numeric nick mask of this server.
+ *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
+ */
+int ms_server(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char*            ch;
+  int              i;
+  char             info[REALLEN + 1];
+  char*            host;
+  struct Client*   acptr;
+  struct Client*   bcptr;
+  struct Client*   LHcptr = 0;
+  struct ConfItem* aconf = 0;
+  struct ConfItem* cconf;
+  struct ConfItem* lhconf = 0;
+  int              hop;
+  int              ret;
+  int              active_lh_line = 0;
+  unsigned short   prot;
+  time_t           start_timestamp;
+  time_t           timestamp = 0;
+  time_t           recv_time;
+  time_t           ghost = 0;
+
+  if (IsUser(cptr))
+  {
+    sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
+    return 0;
+  }
+
+  if (IsUserPort(cptr))
+    return exit_client_msg(cptr, cptr, &me,
+                           "Cannot connect a server to a user port");
+
+  recv_time = TStime();
+  info[0] = '\0';
+  if (parc < 7)
+  {
+    return need_more_params(sptr, "SERVER");
+    return exit_client(cptr, cptr, &me, "Need more parameters");
+  }
+  host = parv[1];
+  /*
+   * Detect protocol
+   */
+  if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
+    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
+
+  if (!IsServer(cptr))          /* Don't allow silently connecting a server */
+    *parv[5] = 'J';
+
+  prot = atoi(parv[5] + 1);
+  if (prot > atoi(MAJOR_PROTOCOL))
+    prot = atoi(MAJOR_PROTOCOL);
+  /*
+   * Because the previous test is only in 2.10, the following is needed
+   * till all servers are 2.10:
+   */
+  if (IsServer(cptr) && prot > Protocol(cptr))
+    prot = Protocol(cptr);
+  hop = atoi(parv[2]);
+  start_timestamp = atoi(parv[3]);
+  timestamp = atoi(parv[4]);
+  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
+      TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
+  if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
+  {
+    return exit_client_msg(cptr, sptr, &me,
+        "Bogus timestamps (%s %s)", parv[3], parv[4]);
+  }
+  ircd_strncpy(info, parv[parc - 1], REALLEN);
+  info[REALLEN] = '\0';
+  if (prot < atoi(MINOR_PROTOCOL)) {
+    sendto_ops("Got incompatible protocol version (%s) from %s",
+               parv[5], cptr->name);
+    return exit_new_server(cptr, sptr, host, timestamp,
+                           "Incompatible protocol: %s", parv[5]);
+  }
+  /*
+   * Check for "FRENCH " infection ;-) (actually this should
+   * be replaced with routine to check the hostname syntax in
+   * general). [ This check is still needed, even after the parse
+   * is fixed, because someone can send "SERVER :foo bar " ].
+   * Also, changed to check other "difficult" characters, now
+   * that parse lets all through... --msa
+   */
+  if (strlen(host) > HOSTLEN)
+    host[HOSTLEN] = '\0';
+  for (ch = host; *ch; ch++)
+    if (*ch <= ' ' || *ch > '~')
+      break;
+  if (*ch || !strchr(host, '.')) {
+    sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
+    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
+  }
+
+  if (IsServer(cptr))
+  {
+    /*
+     * A local server introduces a new server behind this link.
+     * Check if this is allowed according L:, H: and Q: lines.
+     */
+    if (info[0] == '\0')
+      return exit_client_msg(cptr, cptr, &me,
+          "No server info specified for %s", host);
+    /*
+     * See if the newly found server is behind a guaranteed
+     * leaf (L-line). If so, close the link.
+     */
+    if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
+        (!lhconf->port || (hop > lhconf->port)))
+    {
+      /*
+       * L: lines normally come in pairs, here we try to
+       * make sure that the oldest link is squitted, not
+       * both.
+       */
+      active_lh_line = 1;
+      if (timestamp <= cptr->serv->timestamp)
+        LHcptr = 0;          /* Kill incoming server */
+      else
+        LHcptr = cptr;          /* Squit ourselfs */
+    }
+    else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
+             (lhconf->port && (hop > lhconf->port)))
+    {
+      struct Client *ac3ptr;
+      active_lh_line = 2;
+      /* Look for net junction causing this: */
+      LHcptr = 0;            /* incoming server */
+      if (*parv[5] != 'J') {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
+          if (IsJunction(ac3ptr)) {
+            LHcptr = ac3ptr;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  if (IsUnknown(cptr) || IsHandshake(cptr))
+  {
+    const char* encr;
+
+    /*
+     * A local link that is still in undefined state wants
+     * to be a SERVER. Check if this is allowed and change
+     * status accordingly...
+     */
+    /*
+     * If there is more then one server on the same machine
+     * that we try to connect to, it could be that the /CONNECT
+     * <mask> caused this connect to be put at the wrong place
+     * in the hashtable.        --Run
+     * Same thing for Unknown connections that first send NICK.
+     *                          --Xorath
+     * Better check if the two strings are (caseless) identical 
+     * and not mess with hash internals. 
+     *                          --Nemesi
+     */
+    if ((!(EmptyString(cptr->name)))
+        && (IsUnknown(cptr) || IsHandshake(cptr))
+        && 0 != ircd_strcmp(cptr->name, host))
+      hChangeClient(cptr, host);
+    ircd_strncpy(cptr->name, host, HOSTLEN);
+    ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
+    cptr->hopcount = hop;
+
+    /* check connection rules */
+    for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
+      if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
+        if (crule_eval(cconf->passwd))
+        {
+          ServerStats->is_ref++;
+          sendto_ops("Refused connection from %s.", cptr->name);
+          return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
+        }
+      }
+    }
+    if (conf_check_server(cptr)) {
+      ++ServerStats->is_ref;
+      sendto_ops("Received unauthorized connection from %s.", cptr->name);
+      return exit_client(cptr, cptr, &me, "No C conf lines");
+    }
+
+    host = cptr->name;
+
+    update_load();
+
+    if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
+      ++ServerStats->is_ref;
+#ifndef GODMODE
+      sendto_ops("Access denied. No conf line for server %s", cptr->name);
+      return exit_client_msg(cptr, cptr, &me,
+                             "Access denied. No conf line for server %s", cptr->name);
+#else /* GODMODE */
+      sendto_ops("General C line active: No line for server %s", cptr->name);
+      aconf =
+          find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
+      if (!aconf) {
+        sendto_ops("Neither C lines for server %s nor "
+            "\"general.undernet.org\"", cptr->name);
+        return exit_client_msg(cptr, cptr, &me,
+            "No C lines for server %s", cptr->name);
+      }
+#endif /* GODMODE */
+    }
+#ifdef CRYPT_LINK_PASSWORD
+    /* passwd may be NULL. Head it off at the pass... */
+    if (*cptr->passwd)
+    {
+      char salt[3];
+
+      salt[0] = aconf->passwd[0];
+      salt[1] = aconf->passwd[1];
+      salt[2] = '\0';
+      encr = ircd_crypt(cptr->passwd, salt);
+    }
+    else
+      encr = "";
+#else
+    encr = cptr->passwd;
+#endif /* CRYPT_LINK_PASSWORD */
+#ifndef GODMODE
+    if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
+      ++ServerStats->is_ref;
+      sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
+      return exit_client_msg(cptr, cptr, &me,
+                             "No Access (passwd mismatch) %s", cptr->name);
+    }
+#endif /* not GODMODE */
+    memset(cptr->passwd, 0, sizeof(cptr->passwd));
+
+#ifndef HUB
+    for (i = 0; i <= HighestFd; i++)
+      if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
+        active_lh_line = 3;
+        LHcptr = 0;
+        break;
+      }
+#endif
+  }
+
+  /*
+   *  We want to find IsConnecting() and IsHandshake() too,
+   *  use FindClient().
+   *  The second finds collisions with numeric representation of existing
+   *  servers - these shouldn't happen anymore when all upgraded to 2.10.
+   *  -- Run
+   */
+  while ((acptr = FindClient(host)) || 
+         (parc > 7 && (acptr = FindNServer(parv[6]))))
+  {
+    /*
+     *  This link is trying feed me a server that I already have
+     *  access through another path
+     *
+     *  Do not allow Uworld to do this.
+     *  Do not allow servers that are juped.
+     *  Do not allow servers that have older link timestamps
+     *    then this try.
+     *  Do not allow servers that use the same numeric as an existing
+     *    server, but have a different name.
+     *
+     *  If my ircd.conf sucks, I can try to connect to myself:
+     */
+    if (acptr == &me)
+      return exit_client_msg(cptr, cptr, &me,
+          "nick collision with me (%s)", host);
+    /*
+     * Detect wrong numeric.
+     */
+    if (0 != ircd_strcmp(acptr->name, host))
+    {
+      sendto_serv_butone(cptr,
+          ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
+          me.name, acptr->name, host);
+      return exit_client_msg(cptr, cptr, &me,
+          "NUMERIC collision between %s and %s."
+          " Is your server numeric correct ?", host, acptr->name);
+    }
+    /*
+     *  Kill our try, if we had one.
+     */
+    if (IsConnecting(acptr))
+    {
+      if (!active_lh_line && exit_client(cptr, acptr, &me,
+          "Just connected via another link") == CPTR_KILLED)
+        return CPTR_KILLED;
+      /*
+       * We can have only ONE 'IsConnecting', 'IsHandshake' or
+       * 'IsServer', because new 'IsConnecting's are refused to
+       * the same server if we already had it.
+       */
+      break;
+    }
+    /*
+     * Avoid other nick collisions...
+     * This is a doubtfull test though, what else would it be
+     * when it has a server.name ?
+     */
+    else if (!IsServer(acptr) && !IsHandshake(acptr))
+      return exit_client_msg(cptr, cptr, &me,
+          "Nickname %s already exists!", host);
+    /*
+     * Our new server might be a juped server,
+     * or someone trying abuse a second Uworld:
+     */
+    else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
+        find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
+    {
+      if (!IsServer(sptr))
+        return exit_client(cptr, sptr, &me, acptr->info);
+      sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
+          me.name, parv[0], parv[1], cptr->name);
+      return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
+    }
+    /*
+     * Of course we find the handshake this link was before :)
+     */
+    else if (IsHandshake(acptr) && acptr == cptr)
+      break;
+    /*
+     * Here we have a server nick collision...
+     * We don't want to kill the link that was last /connected,
+     * but we neither want to kill a good (old) link.
+     * Therefor we kill the second youngest link.
+     */
+    if (1)
+    {
+      struct Client* c2ptr = 0;
+      struct Client* c3ptr = acptr;
+      struct Client* ac2ptr;
+      struct Client* ac3ptr;
+
+      /* Search youngest link: */
+      for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
+        if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
+          c3ptr = ac3ptr;
+      if (IsServer(sptr))
+      {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
+          if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
+            c3ptr = ac3ptr;
+      }
+      if (timestamp > c3ptr->serv->timestamp)
+      {
+        c3ptr = 0;
+        c2ptr = acptr;          /* Make sure they differ */
+      }
+      /* Search second youngest link: */
+      for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
+        if (ac2ptr != c3ptr &&
+            ac2ptr->serv->timestamp >
+            (c2ptr ? c2ptr->serv->timestamp : timestamp))
+          c2ptr = ac2ptr;
+      if (IsServer(sptr))
+      {
+        for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
+          if (ac2ptr != c3ptr &&
+              ac2ptr->serv->timestamp >
+              (c2ptr ? c2ptr->serv->timestamp : timestamp))
+            c2ptr = ac2ptr;
+      }
+      if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
+        c2ptr = 0;
+      /* If timestamps are equal, decide which link to break
+       *  by name.
+       */
+      if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
+          (c3ptr ? c3ptr->serv->timestamp : timestamp))
+      {
+        char* n2;
+        char* n2up;
+        char* n3;
+        char* n3up;
+        if (c2ptr)
+        {
+          n2 = c2ptr->name;
+          n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
+        }
+        else
+        {
+          n2 = host;
+          n2up = IsServer(sptr) ? sptr->name : me.name;
+        }
+        if (c3ptr)
+        {
+          n3 = c3ptr->name;
+          n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
+        }
+        else
+        {
+          n3 = host;
+          n3up = IsServer(sptr) ? sptr->name : me.name;
+        }
+        if (strcmp(n2, n2up) > 0)
+          n2 = n2up;
+        if (strcmp(n3, n3up) > 0)
+          n3 = n3up;
+        if (strcmp(n3, n2) > 0)
+        {
+          ac2ptr = c2ptr;
+          c2ptr = c3ptr;
+          c3ptr = ac2ptr;
+        }
+      }
+      /* Now squit the second youngest link: */
+      if (!c2ptr)
+        return exit_new_server(cptr, sptr, host, timestamp,
+            "server %s already exists and is %ld seconds younger.",
+            host, (long)acptr->serv->timestamp - (long)timestamp);
+      else if (c2ptr->from == cptr || IsServer(sptr))
+      {
+        struct Client *killedptrfrom = c2ptr->from;
+        if (active_lh_line)
+        {
+          /*
+           * If the L: or H: line also gets rid of this link,
+           * we sent just one squit.
+           */
+          if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
+            break;
+          /*
+           * If breaking the loop here solves the L: or H:
+           * line problem, we don't squit that.
+           */
+          if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            /*
+             * If we still have a L: or H: line problem,
+             * we prefer to squit the new server, solving
+             * loop and L:/H: line problem with only one squit.
+             */
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * If the new server was introduced by a server that caused a
+         * Ghost less then 20 seconds ago, this is probably also
+         * a Ghost... (20 seconds is more then enough because all
+         * SERVER messages are at the beginning of a net.burst). --Run
+         */
+        if (CurrentTime - cptr->serv->ghost < 20)
+        {
+          killedptrfrom = acptr->from;
+          if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
+            return CPTR_KILLED;
+        }
+        else if (exit_client_msg(cptr, c2ptr, &me,
+            "Loop <-- %s (new link is %ld seconds younger)", host,
+            (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
+            (long)c2ptr->serv->timestamp) == CPTR_KILLED)
+          return CPTR_KILLED;
+        /*
+         * Did we kill the incoming server off already ?
+         */
+        if (killedptrfrom == cptr)
+          return 0;
+      }
+      else
+      {
+        if (active_lh_line)
+        {
+          if (LHcptr && a_kills_b_too(LHcptr, acptr))
+            break;
+          if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * We can't believe it is a lagged server message
+         * when it directly connects to us...
+         * kill the older link at the ghost, rather then
+         * at the second youngest link, assuming it isn't
+         * a REAL loop.
+         */
+        ghost = CurrentTime;            /* Mark that it caused a ghost */
+        if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
+          return CPTR_KILLED;
+        break;
+      }
+    }
+  }
+
+  if (active_lh_line)
+  {
+    if (LHcptr == 0) {
+      return exit_new_server(cptr, sptr, host, timestamp,
+          (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
+          cptr->name, host,
+          lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
+    }
+    else
+    {
+      int killed = a_kills_b_too(LHcptr, sptr);
+      if (active_lh_line < 3)
+      {
+        if (exit_client_msg(cptr, LHcptr, &me,
+            (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
+            cptr->name, host,
+            lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
+          return CPTR_KILLED;
+      }
+      else
+      {
+        ServerStats->is_ref++;
+        if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
+          return CPTR_KILLED;
+      }
+      /*
+       * Did we kill the incoming server off already ?
+       */
+      if (killed)
+        return 0;
+    }
+  }
+
+  if (IsServer(cptr))
+  {
+    /*
+     * Server is informing about a new server behind
+     * this link. Create REMOTE server structure,
+     * add it to list and propagate word to my other
+     * server links...
+     */
+
+    acptr = make_client(cptr, STAT_SERVER);
+    make_server(acptr);
+    acptr->serv->prot = prot;
+    acptr->serv->timestamp = timestamp;
+    acptr->hopcount = hop;
+    ircd_strncpy(acptr->name, host, HOSTLEN);
+    ircd_strncpy(acptr->info, info, REALLEN);
+    acptr->serv->up = sptr;
+    acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
+    /* Use cptr, because we do protocol 9 -> 10 translation
+       for numeric nicks ! */
+    SetServerYXX(cptr, acptr, parv[6]);
+
+    Count_newremoteserver(UserStats);
+    if (Protocol(acptr) < 10)
+      acptr->flags |= FLAGS_TS8;
+    add_client_to_list(acptr);
+    hAddClient(acptr);
+    if (*parv[5] == 'J')
+    {
+      SetBurst(acptr);
+      sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
+          sptr->name, acptr->name);
+      SetJunction(acptr);
+    }
+    /*
+     * Old sendto_serv_but_one() call removed because we now need to send
+     * different names to different servers (domain name matching).
+     */
+    for (i = 0; i <= HighestFd; i++)
+    {
+      if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
+          bcptr == cptr || IsMe(bcptr))
+        continue;
+      if (0 == match(me.name, acptr->name))
+        continue;
+        sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
+            NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
+            NumServCap(acptr), acptr->info);
+    }
+    return 0;
+  }
+
+  if (IsUnknown(cptr) || IsHandshake(cptr))
+  {
+    make_server(cptr);
+    cptr->serv->timestamp = timestamp;
+    cptr->serv->prot = prot;
+    cptr->serv->ghost = ghost;
+    SetServerYXX(cptr, cptr, parv[6]);
+    if (start_timestamp > OLDEST_TS)
+    {
+#ifndef RELIABLE_CLOCK
+#ifdef TESTNET
+      sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
+          TIME_T_FMT, me.serv->timestamp, start_timestamp);
+      sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
+          TIME_T_FMT " ; difference %ld",
+          recv_time, timestamp, timestamp - recv_time);
+#endif
+      if (start_timestamp < me.serv->timestamp)
+      {
+        sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
+            start_timestamp, me.serv->timestamp);
+        me.serv->timestamp = start_timestamp;
+        TSoffset += timestamp - recv_time;
+        sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
+      }
+      else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
+        cptr->serv->timestamp = TStime();
+
+      else if (timestamp != recv_time)
+      {
+        /*
+         * Equal start times, we have a collision.  Let the connected-to server
+         * decide. This assumes leafs issue more than half of the connection
+         * attempts.
+         */
+        if (IsUnknown(cptr))
+          cptr->serv->timestamp = TStime();
+        else if (IsHandshake(cptr))
+        {
+          sendto_ops("clock adjusted by adding %d",
+              (int)(timestamp - recv_time));
+          TSoffset += timestamp - recv_time;
+        }
+      }
+#else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
+      if (start_timestamp < me.serv->timestamp)
+        me.serv->timestamp = start_timestamp;
+      if (IsUnknown(cptr))
+        cptr->serv->timestamp = TStime();
+#endif
+    }
+
+    ret = server_estab(cptr, aconf);
+  }
+  else
+    ret = 0;
+#ifdef RELIABLE_CLOCK
+  if (abs(cptr->serv->timestamp - recv_time) > 30)
+  {
+    sendto_ops("Connected to a net with a timestamp-clock"
+        " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
+        " this.", timestamp - recv_time);
+    sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
+        me.name, TStime(), me.name);
+  }
+#endif
+
+  return ret;
+}
+
+
+#if 0
+/*
+ *  m_server
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = servername
+ *    parv[2] = hopcount
+ *    parv[3] = start timestamp
+ *    parv[4] = link timestamp
+ *    parv[5] = major protocol version: P09/P10
+ *    parv[parc-1] = serverinfo
+ *  If cptr is P10:
+ *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
+ *              numeric nick mask of this server.
+ *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
+ */
+int m_server(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char*            ch;
+  int              i;
+  char             info[REALLEN + 1];
+  char*            host;
+  struct Client*   acptr;
+  struct Client*   bcptr;
+  struct Client*   LHcptr = 0;
+  struct ConfItem* aconf = 0;
+  struct ConfItem* cconf;
+  struct ConfItem* lhconf = 0;
+  int              hop;
+  int              ret;
+  int              active_lh_line = 0;
+  unsigned short   prot;
+  time_t           start_timestamp;
+  time_t           timestamp = 0;
+  time_t           recv_time;
+  time_t           ghost = 0;
+
+  if (IsUser(cptr))
+  {
+    sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
+    return 0;
+  }
+
+  if (IsUserPort(cptr))
+    return exit_client_msg(cptr, cptr, &me,
+        "You cannot connect a server to a user port; connect to %s port %u",
+        me.name, server_port);
+
+  recv_time = TStime();
+  info[0] = '\0';
+  if (parc < 7)
+  {
+    return need_more_params(sptr, "SERVER");
+    return exit_client(cptr, cptr, &me, "Need more parameters");
+  }
+  host = parv[1];
+  /*
+   * Detect protocol
+   */
+  if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
+    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
+
+  if (!IsServer(cptr))          /* Don't allow silently connecting a server */
+    *parv[5] = 'J';
+
+  prot = atoi(parv[5] + 1);
+  if (prot > atoi(MAJOR_PROTOCOL))
+    prot = atoi(MAJOR_PROTOCOL);
+  /*
+   * Because the previous test is only in 2.10, the following is needed
+   * till all servers are 2.10:
+   */
+  if (IsServer(cptr) && prot > Protocol(cptr))
+    prot = Protocol(cptr);
+  hop = atoi(parv[2]);
+  start_timestamp = atoi(parv[3]);
+  timestamp = atoi(parv[4]);
+  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
+      TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
+  if ((timestamp < OLDEST_TS || (hop == 1 && start_timestamp < OLDEST_TS)))
+  {
+    return exit_client_msg(cptr, sptr, &me,
+        "Bogus timestamps (%s %s)", parv[3], parv[4]);
+  }
+  ircd_strncpy(info, parv[parc - 1], REALLEN);
+  info[REALLEN] = '\0';
+  if (prot < atoi(MINOR_PROTOCOL)) {
+    sendto_ops("Got incompatible protocol version (%s) from %s",
+               parv[5], cptr->name);
+    return exit_new_server(cptr, sptr, host, timestamp,
+        "Incompatible protocol: %s", parv[5]);
+  }
+  /*
+   * Check for "FRENCH " infection ;-) (actually this should
+   * be replaced with routine to check the hostname syntax in
+   * general). [ This check is still needed, even after the parse
+   * is fixed, because someone can send "SERVER :foo bar " ].
+   * Also, changed to check other "difficult" characters, now
+   * that parse lets all through... --msa
+   */
+  if (strlen(host) > HOSTLEN)
+    host[HOSTLEN] = '\0';
+  for (ch = host; *ch; ch++)
+    if (*ch <= ' ' || *ch > '~')
+      break;
+  if (*ch || !strchr(host, '.'))
+  {
+    sendto_ops("Bogus server name (%s) from %s", host, cptr->name);
+    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
+  }
+
+  if (IsServer(cptr))
+  {
+    /*
+     * A local server introduces a new server behind this link.
+     * Check if this is allowed according L:, H: and Q: lines.
+     */
+    if (info[0] == '\0')
+      return exit_client_msg(cptr, cptr, &me,
+          "No server info specified for %s", host);
+    /*
+     * See if the newly found server is behind a guaranteed
+     * leaf (L-line). If so, close the link.
+     */
+    if ((lhconf = find_conf_byhost(cptr->confs, cptr->name, CONF_LEAF)) &&
+        (!lhconf->port || (hop > lhconf->port)))
+    {
+      /*
+       * L: lines normally come in pairs, here we try to
+       * make sure that the oldest link is squitted, not
+       * both.
+       */
+      active_lh_line = 1;
+      if (timestamp <= cptr->serv->timestamp)
+        LHcptr = 0;          /* Kill incoming server */
+      else
+        LHcptr = cptr;          /* Squit ourselfs */
+    }
+    else if (!(lhconf = find_conf_byname(cptr->confs, cptr->name, CONF_HUB)) ||
+             (lhconf->port && (hop > lhconf->port)))
+    {
+      struct Client *ac3ptr;
+      active_lh_line = 2;
+      /* Look for net junction causing this: */
+      LHcptr = 0;            /* incoming server */
+      if (*parv[5] != 'J') {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up) {
+          if (IsJunction(ac3ptr)) {
+            LHcptr = ac3ptr;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  if (IsUnknown(cptr) || IsHandshake(cptr))
+  {
+    const char* encr;
+
+    /*
+     * A local link that is still in undefined state wants
+     * to be a SERVER. Check if this is allowed and change
+     * status accordingly...
+     */
+    /*
+     * If there is more then one server on the same machine
+     * that we try to connect to, it could be that the /CONNECT
+     * <mask> caused this connect to be put at the wrong place
+     * in the hashtable.        --Run
+     * Same thing for Unknown connections that first send NICK.
+     *                          --Xorath
+     * Better check if the two strings are (caseless) identical 
+     * and not mess with hash internals. 
+     *                          --Nemesi
+     */
+    if ((!(EmptyString(cptr->name)))
+        && (IsUnknown(cptr) || IsHandshake(cptr))
+        && 0 != ircd_strcmp(cptr->name, host))
+      hChangeClient(cptr, host);
+    ircd_strncpy(cptr->name, host, HOSTLEN);
+    ircd_strncpy(cptr->info, info[0] ? info : me.name, REALLEN);
+    cptr->hopcount = hop;
+
+    /* check connection rules */
+    for (cconf = GlobalConfList; cconf; cconf = cconf->next) {
+      if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0)) {
+        if (crule_eval(cconf->passwd))
+        {
+          ServerStats->is_ref++;
+          sendto_ops("Refused connection from %s.", cptr->name);
+          return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
+        }
+      }
+    }
+    if (conf_check_server(cptr)) {
+      ++ServerStats->is_ref;
+      sendto_ops("Received unauthorized connection from %s.", cptr->name);
+      return exit_client(cptr, cptr, &me, "No C/N conf lines");
+    }
+
+    host = cptr->name;
+
+    update_load();
+
+    if (!(aconf = find_conf_byname(cptr->confs, host, CONF_SERVER))) {
+      ++ServerStats->is_ref;
+#ifndef GODMODE
+      sendto_ops("Access denied. No conf line for server %s", cptr->name);
+      return exit_client_msg(cptr, cptr, &me,
+          "Access denied. No conf line for server %s", cptr->name);
+#else /* GODMODE */
+      sendto_ops("General C/N: line active: No line for server %s", cptr->name);
+      aconf =
+          find_conf_byname(cptr->confs, "general.undernet.org", CONF_SERVER);
+      if (!aconf) {
+        sendto_ops("Neither C/N lines for server %s nor "
+            "\"general.undernet.org\"", cptr->name);
+        return exit_client_msg(cptr, cptr, &me,
+            "No C/N lines for server %s", cptr->name);
+      }
+#endif /* GODMODE */
+    }
+#ifdef CRYPT_LINK_PASSWORD
+    /* passwd may be NULL. Head it off at the pass... */
+    if (*cptr->passwd)
+    {
+      char salt[3];
+
+      salt[0] = aconf->passwd[0];
+      salt[1] = aconf->passwd[1];
+      salt[2] = '\0';
+      encr = ircd_crypt(cptr->passwd, salt);
+    }
+    else
+      encr = "";
+#else
+    encr = cptr->passwd;
+#endif /* CRYPT_LINK_PASSWORD */
+#ifndef GODMODE
+    if (*aconf->passwd && !!strcmp(aconf->passwd, encr)) {
+      ++ServerStats->is_ref;
+      sendto_ops("Access denied (passwd mismatch) %s", cptr->name);
+      return exit_client_msg(cptr, cptr, &me,
+          "No Access (passwd mismatch) %s", cptr->name);
+    }
+#endif /* not GODMODE */
+    memset(cptr->passwd, 0, sizeof(cptr->passwd));
+
+#ifndef HUB
+    for (i = 0; i <= HighestFd; i++)
+      if (LocalClientArray[i] && IsServer(LocalClientArray[i])) {
+        active_lh_line = 3;
+        LHcptr = 0;
+        break;
+      }
+#endif
+  }
+
+  /*
+   *  We want to find IsConnecting() and IsHandshake() too,
+   *  use FindClient().
+   *  The second finds collisions with numeric representation of existing
+   *  servers - these shouldn't happen anymore when all upgraded to 2.10.
+   *  -- Run
+   */
+  while ((acptr = FindClient(host)) || 
+         (parc > 7 && (acptr = FindNServer(parv[6]))))
+  {
+    /*
+     *  This link is trying feed me a server that I already have
+     *  access through another path
+     *
+     *  Do not allow Uworld to do this.
+     *  Do not allow servers that are juped.
+     *  Do not allow servers that have older link timestamps
+     *    then this try.
+     *  Do not allow servers that use the same numeric as an existing
+     *    server, but have a different name.
+     *
+     *  If my ircd.conf sucks, I can try to connect to myself:
+     */
+    if (acptr == &me)
+      return exit_client_msg(cptr, cptr, &me,
+          "nick collision with me (%s)", host);
+    /*
+     * Detect wrong numeric.
+     */
+    if (0 != ircd_strcmp(acptr->name, host))
+    {
+      sendto_serv_butone(cptr,
+          ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
+          me.name, acptr->name, host);
+      return exit_client_msg(cptr, cptr, &me,
+          "NUMERIC collision between %s and %s."
+          " Is your server numeric correct ?", host, acptr->name);
+    }
+    /*
+     *  Kill our try, if we had one.
+     */
+    if (IsConnecting(acptr))
+    {
+      if (!active_lh_line && exit_client(cptr, acptr, &me,
+          "Just connected via another link") == CPTR_KILLED)
+        return CPTR_KILLED;
+      /*
+       * We can have only ONE 'IsConnecting', 'IsHandshake' or
+       * 'IsServer', because new 'IsConnecting's are refused to
+       * the same server if we already had it.
+       */
+      break;
+    }
+    /*
+     * Avoid other nick collisions...
+     * This is a doubtfull test though, what else would it be
+     * when it has a server.name ?
+     */
+    else if (!IsServer(acptr) && !IsHandshake(acptr))
+      return exit_client_msg(cptr, cptr, &me,
+          "Nickname %s already exists!", host);
+    /*
+     * Our new server might be a juped server,
+     * or someone trying abuse a second Uworld:
+     */
+    else if (IsServer(acptr) && (0 == ircd_strncmp(acptr->info, "JUPE", 4) ||
+        find_conf_byhost(cptr->confs, acptr->name, CONF_UWORLD)))
+    {
+      if (!IsServer(sptr))
+        return exit_client(cptr, sptr, &me, acptr->info);
+      sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
+          me.name, parv[0], parv[1], cptr->name);
+      return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
+    }
+    /*
+     * Of course we find the handshake this link was before :)
+     */
+    else if (IsHandshake(acptr) && acptr == cptr)
+      break;
+    /*
+     * Here we have a server nick collision...
+     * We don't want to kill the link that was last /connected,
+     * but we neither want to kill a good (old) link.
+     * Therefor we kill the second youngest link.
+     */
+    if (1)
+    {
+      struct Client* c2ptr = 0;
+      struct Client* c3ptr = acptr;
+      struct Client* ac2ptr;
+      struct Client* ac3ptr;
+
+      /* Search youngest link: */
+      for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
+        if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
+          c3ptr = ac3ptr;
+      if (IsServer(sptr))
+      {
+        for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
+          if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
+            c3ptr = ac3ptr;
+      }
+      if (timestamp > c3ptr->serv->timestamp)
+      {
+        c3ptr = 0;
+        c2ptr = acptr;          /* Make sure they differ */
+      }
+      /* Search second youngest link: */
+      for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
+        if (ac2ptr != c3ptr &&
+            ac2ptr->serv->timestamp >
+            (c2ptr ? c2ptr->serv->timestamp : timestamp))
+          c2ptr = ac2ptr;
+      if (IsServer(sptr))
+      {
+        for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
+          if (ac2ptr != c3ptr &&
+              ac2ptr->serv->timestamp >
+              (c2ptr ? c2ptr->serv->timestamp : timestamp))
+            c2ptr = ac2ptr;
+      }
+      if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
+        c2ptr = 0;
+      /* If timestamps are equal, decide which link to break
+       *  by name.
+       */
+      if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
+          (c3ptr ? c3ptr->serv->timestamp : timestamp))
+      {
+        char* n2;
+        char* n2up;
+        char* n3;
+        char* n3up;
+        if (c2ptr)
+        {
+          n2 = c2ptr->name;
+          n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
+        }
+        else
+        {
+          n2 = host;
+          n2up = IsServer(sptr) ? sptr->name : me.name;
+        }
+        if (c3ptr)
+        {
+          n3 = c3ptr->name;
+          n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
+        }
+        else
+        {
+          n3 = host;
+          n3up = IsServer(sptr) ? sptr->name : me.name;
+        }
+        if (strcmp(n2, n2up) > 0)
+          n2 = n2up;
+        if (strcmp(n3, n3up) > 0)
+          n3 = n3up;
+        if (strcmp(n3, n2) > 0)
+        {
+          ac2ptr = c2ptr;
+          c2ptr = c3ptr;
+          c3ptr = ac2ptr;
+        }
+      }
+      /* Now squit the second youngest link: */
+      if (!c2ptr)
+        return exit_new_server(cptr, sptr, host, timestamp,
+            "server %s already exists and is %ld seconds younger.",
+            host, (long)acptr->serv->timestamp - (long)timestamp);
+      else if (c2ptr->from == cptr || IsServer(sptr))
+      {
+        struct Client *killedptrfrom = c2ptr->from;
+        if (active_lh_line)
+        {
+          /*
+           * If the L: or H: line also gets rid of this link,
+           * we sent just one squit.
+           */
+          if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
+            break;
+          /*
+           * If breaking the loop here solves the L: or H:
+           * line problem, we don't squit that.
+           */
+          if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            /*
+             * If we still have a L: or H: line problem,
+             * we prefer to squit the new server, solving
+             * loop and L:/H: line problem with only one squit.
+             */
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * If the new server was introduced by a server that caused a
+         * Ghost less then 20 seconds ago, this is probably also
+         * a Ghost... (20 seconds is more then enough because all
+         * SERVER messages are at the beginning of a net.burst). --Run
+         */
+        if (CurrentTime - cptr->serv->ghost < 20)
+        {
+          killedptrfrom = acptr->from;
+          if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
+            return CPTR_KILLED;
+        }
+        else if (exit_client_msg(cptr, c2ptr, &me,
+            "Loop <-- %s (new link is %ld seconds younger)", host,
+            (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
+            (long)c2ptr->serv->timestamp) == CPTR_KILLED)
+          return CPTR_KILLED;
+        /*
+         * Did we kill the incoming server off already ?
+         */
+        if (killedptrfrom == cptr)
+          return 0;
+      }
+      else
+      {
+        if (active_lh_line)
+        {
+          if (LHcptr && a_kills_b_too(LHcptr, acptr))
+            break;
+          if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
+            active_lh_line = 0;
+          else
+          {
+            LHcptr = 0;
+            break;
+          }
+        }
+        /*
+         * We can't believe it is a lagged server message
+         * when it directly connects to us...
+         * kill the older link at the ghost, rather then
+         * at the second youngest link, assuming it isn't
+         * a REAL loop.
+         */
+        ghost = CurrentTime;            /* Mark that it caused a ghost */
+        if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
+          return CPTR_KILLED;
+        break;
+      }
+    }
+  }
+
+  if (active_lh_line)
+  {
+    if (LHcptr == 0) {
+      return exit_new_server(cptr, sptr, host, timestamp,
+          (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
+          cptr->name, host,
+          lhconf ? (lhconf->name ? lhconf->name : "*") : "!");
+    }
+    else
+    {
+      int killed = a_kills_b_too(LHcptr, sptr);
+      if (active_lh_line < 3)
+      {
+        if (exit_client_msg(cptr, LHcptr, &me,
+            (active_lh_line == 2) ?  "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
+            cptr->name, host,
+            lhconf ? (lhconf->name ? lhconf->name : "*") : "!") == CPTR_KILLED)
+          return CPTR_KILLED;
+      }
+      else
+      {
+        ServerStats->is_ref++;
+        if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
+          return CPTR_KILLED;
+      }
+      /*
+       * Did we kill the incoming server off already ?
+       */
+      if (killed)
+        return 0;
+    }
+  }
+
+  if (IsServer(cptr))
+  {
+    /*
+     * Server is informing about a new server behind
+     * this link. Create REMOTE server structure,
+     * add it to list and propagate word to my other
+     * server links...
+     */
+
+    acptr = make_client(cptr, STAT_SERVER);
+    make_server(acptr);
+    acptr->serv->prot = prot;
+    acptr->serv->timestamp = timestamp;
+    acptr->hopcount = hop;
+    ircd_strncpy(acptr->name, host, HOSTLEN);
+    ircd_strncpy(acptr->info, info, REALLEN);
+    acptr->serv->up = sptr;
+    acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
+    /* Use cptr, because we do protocol 9 -> 10 translation
+       for numeric nicks ! */
+    SetServerYXX(cptr, acptr, parv[6]);
+
+    Count_newremoteserver(UserStats);
+    if (Protocol(acptr) < 10)
+      acptr->flags |= FLAGS_TS8;
+    add_client_to_list(acptr);
+    hAddClient(acptr);
+    if (*parv[5] == 'J')
+    {
+      SetBurst(acptr);
+      sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
+          sptr->name, acptr->name);
+      SetJunction(acptr);
+    }
+    /*
+     * Old sendto_serv_but_one() call removed because we now need to send
+     * different names to different servers (domain name matching).
+     */
+    for (i = 0; i <= HighestFd; i++)
+    {
+      if (!(bcptr = LocalClientArray[i]) || !IsServer(bcptr) ||
+          bcptr == cptr || IsMe(bcptr))
+        continue;
+      if (0 == match(me.name, acptr->name))
+        continue;
+        sendto_one(bcptr, "%s " TOK_SERVER " %s %d 0 %s %s %s%s 0 :%s",
+            NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
+            NumServCap(acptr), acptr->info);
+    }
+    return 0;
+  }
+
+  if (IsUnknown(cptr) || IsHandshake(cptr))
+  {
+    make_server(cptr);
+    cptr->serv->timestamp = timestamp;
+    cptr->serv->prot = prot;
+    cptr->serv->ghost = ghost;
+    SetServerYXX(cptr, cptr, parv[6]);
+    if (start_timestamp > OLDEST_TS)
+    {
+#ifndef RELIABLE_CLOCK
+#ifdef TESTNET
+      sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
+          TIME_T_FMT, me.serv->timestamp, start_timestamp);
+      sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
+          TIME_T_FMT " ; difference %ld",
+          recv_time, timestamp, timestamp - recv_time);
+#endif
+      if (start_timestamp < me.serv->timestamp)
+      {
+        sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
+            start_timestamp, me.serv->timestamp);
+        me.serv->timestamp = start_timestamp;
+        TSoffset += timestamp - recv_time;
+        sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
+      }
+      else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
+        cptr->serv->timestamp = TStime();
+
+      else if (timestamp != recv_time)
+      {
+        /*
+         * Equal start times, we have a collision.  Let the connected-to server
+         * decide. This assumes leafs issue more than half of the connection
+         * attempts.
+         */
+        if (IsUnknown(cptr))
+          cptr->serv->timestamp = TStime();
+        else if (IsHandshake(cptr))
+        {
+          sendto_ops("clock adjusted by adding %d",
+              (int)(timestamp - recv_time));
+          TSoffset += timestamp - recv_time;
+        }
+      }
+#else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
+      if (start_timestamp < me.serv->timestamp)
+        me.serv->timestamp = start_timestamp;
+      if (IsUnknown(cptr))
+        cptr->serv->timestamp = TStime();
+#endif
+    }
+
+    ret = server_estab(cptr, aconf);
+  }
+  else
+    ret = 0;
+#ifdef RELIABLE_CLOCK
+  if (abs(cptr->serv->timestamp - recv_time) > 30)
+  {
+    sendto_ops("Connected to a net with a timestamp-clock"
+        " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
+        " this.", timestamp - recv_time);
+    sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
+        me.name, TStime(), me.name);
+  }
+#endif
+
+  return ret;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_settime.c b/ircd/m_settime.c
new file mode 100644 (file)
index 0000000..bc55865
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_settime.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * ms_settime - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = new time
+ * parv[2] = servername (Only used when sptr is an Oper).
+ */
+int ms_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t t;
+  long int dt;
+  static char tbuf[11];
+  struct DLink *lp;
+
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "SETTIME");
+
+  if (parc == 2 && MyUser(sptr))
+    parv[parc++] = me.name;
+
+  t = atoi(parv[1]);
+  dt = TStime() - t;
+
+  if (t < OLDEST_TS || dt < -9000000)
+  {
+    sendto_one(sptr, ":%s NOTICE %s :SETTIME: Bad value", me.name, parv[0]);
+    return 0;
+  }
+
+  if (IsServer(sptr))           /* send to unlagged servers */
+  {
+#ifdef RELIABLE_CLOCK
+    sprintf_irc(tbuf, TIME_T_FMT, TStime());
+    parv[1] = tbuf;
+#endif
+    for (lp = me.serv->down; lp; lp = lp->next)
+      if (cptr != lp->value.cptr && DBufLength(&lp->value.cptr->sendQ) < 8000)
+        sendto_one(lp->value.cptr, ":%s SETTIME %s", parv[0], parv[1]);
+  }
+  else
+  {
+    sprintf_irc(tbuf, TIME_T_FMT, TStime());
+    parv[1] = tbuf;
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_SETTIME " %s %s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+  }
+
+#ifdef RELIABLE_CLOCK
+  if ((dt > 600) || (dt < -600))
+    sendto_serv_butone(0, ":%s " TOK_WALLOPS " :Bad SETTIME from %s: " TIME_T_FMT,
+                       me.name, sptr->name, t);
+  if (IsUser(sptr))
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :clock is not set %ld seconds %s : "
+                 "RELIABLE_CLOCK is defined", me.name, parv[0],
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :clock is not set %ld seconds %s : "
+                 "RELIABLE_CLOCK is defined", NumServ(&me), NumNick(sptr),
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+  }
+#else
+  sendto_ops("SETTIME from %s, clock is set %ld seconds %s",
+             sptr->name, (dt < 0) ? -dt : dt,
+             (dt < 0) ? "forwards" : "backwards");
+  TSoffset -= dt;
+  if (IsUser(sptr))
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :clock is set %ld seconds %s", me.name,
+                 parv[0], (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :clock is set %ld seconds %s",
+                 NumServ(&me), NumNick(sptr),
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+  }
+#endif
+  return 0;
+}
+
+/*
+ * mo_settime - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = new time
+ * parv[2] = servername (Only used when sptr is an Oper).
+ */
+int mo_settime(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  time_t t;
+  long int dt;
+  static char tbuf[11];
+  struct DLink *lp;
+
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "SETTIME");
+
+  if (parc == 2 && MyUser(sptr))
+    parv[parc++] = me.name;
+
+  t = atoi(parv[1]);
+  dt = TStime() - t;
+
+  if (t < OLDEST_TS || dt < -9000000)
+  {
+    sendto_one(sptr, ":%s NOTICE %s :SETTIME: Bad value", me.name, parv[0]);
+    return 0;
+  }
+
+  if (IsServer(sptr))           /* send to unlagged servers */
+  {
+#ifdef RELIABLE_CLOCK
+    sprintf_irc(tbuf, TIME_T_FMT, TStime());
+    parv[1] = tbuf;
+#endif
+    for (lp = me.serv->down; lp; lp = lp->next)
+      if (cptr != lp->value.cptr && DBufLength(&lp->value.cptr->sendQ) < 8000)
+        sendto_one(lp->value.cptr, ":%s SETTIME %s", parv[0], parv[1]);
+  }
+  else
+  {
+    sprintf_irc(tbuf, TIME_T_FMT, TStime());
+    parv[1] = tbuf;
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_SETTIME " %s %s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+  }
+
+#ifdef RELIABLE_CLOCK
+  if ((dt > 600) || (dt < -600))
+    sendto_serv_butone(0, ":%s " TOK_WALLOPS " :Bad SETTIME from %s: " TIME_T_FMT,
+                       me.name, sptr->name, t);
+  if (IsUser(sptr))
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :clock is not set %ld seconds %s : "
+                 "RELIABLE_CLOCK is defined", me.name, parv[0],
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :clock is not set %ld seconds %s : "
+                 "RELIABLE_CLOCK is defined", NumServ(&me), NumNick(sptr),
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+  }
+#else
+  sendto_ops("SETTIME from %s, clock is set %ld seconds %s",
+             sptr->name, (dt < 0) ? -dt : dt,
+             (dt < 0) ? "forwards" : "backwards");
+  TSoffset -= dt;
+  if (IsUser(sptr))
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :clock is set %ld seconds %s", me.name,
+                 parv[0], (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :clock is set %ld seconds %s",
+                 NumServ(&me), NumNick(sptr),
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+  }
+#endif
+  return 0;
+}
+
+  
+#if 0
+/*
+ * m_settime
+ *
+ * parv[0] = sender prefix
+ * parv[1] = new time
+ * parv[2] = servername (Only used when sptr is an Oper).
+ */
+int m_settime(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  time_t t;
+  long int dt;
+  static char tbuf[11];
+  struct DLink *lp;
+
+  if (!IsPrivileged(sptr))
+    return 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "SETTIME");
+
+  if (parc == 2 && MyUser(sptr))
+    parv[parc++] = me.name;
+
+  t = atoi(parv[1]);
+  dt = TStime() - t;
+
+  if (t < OLDEST_TS || dt < -9000000)
+  {
+    sendto_one(sptr, ":%s NOTICE %s :SETTIME: Bad value", me.name, parv[0]);
+    return 0;
+  }
+
+  if (IsServer(sptr))           /* send to unlagged servers */
+  {
+#ifdef RELIABLE_CLOCK
+    sprintf_irc(tbuf, TIME_T_FMT, TStime());
+    parv[1] = tbuf;
+#endif
+    for (lp = me.serv->down; lp; lp = lp->next)
+      if (cptr != lp->value.cptr && DBufLength(&lp->value.cptr->sendQ) < 8000)
+        sendto_one(lp->value.cptr, ":%s SETTIME %s", parv[0], parv[1]);
+  }
+  else
+  {
+    sprintf_irc(tbuf, TIME_T_FMT, TStime());
+    parv[1] = tbuf;
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_SETTIME " %s %s", 2, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+  }
+
+#ifdef RELIABLE_CLOCK
+  if ((dt > 600) || (dt < -600))
+    sendto_serv_butone(0, ":%s " TOK_WALLOPS " :Bad SETTIME from %s: " TIME_T_FMT,
+                       me.name, sptr->name, t);
+  if (IsUser(sptr))
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :clock is not set %ld seconds %s : "
+                 "RELIABLE_CLOCK is defined", me.name, parv[0],
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :clock is not set %ld seconds %s : "
+                 "RELIABLE_CLOCK is defined", NumServ(&me), NumNick(sptr),
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+  }
+#else
+  sendto_ops("SETTIME from %s, clock is set %ld seconds %s",
+             sptr->name, (dt < 0) ? -dt : dt,
+             (dt < 0) ? "forwards" : "backwards");
+  TSoffset -= dt;
+  if (IsUser(sptr))
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :clock is set %ld seconds %s", me.name,
+                 parv[0], (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :clock is set %ld seconds %s",
+                 NumServ(&me), NumNick(sptr),
+                 (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
+  }
+#endif
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_silence.c b/ircd/m_silence.c
new file mode 100644 (file)
index 0000000..535c81b
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_silence.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_silence - generic message handler
+ *
+ *   parv[0] = sender prefix
+ * From local client:
+ *   parv[1] = mask (NULL sends the list)
+ * From remote client:
+ *   parv[1] = Numeric nick that must be silenced
+ *   parv[2] = mask
+ *
+ * XXX - ugh 
+ */
+int m_silence(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct SLink*  lp;
+  struct Client* acptr;
+  char           c;
+  char*          cp;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  acptr = sptr;
+
+  if (parc < 2 || EmptyString(parv[1]) || (acptr = FindUser(parv[1]))) {
+    if (!(acptr->user))
+      return 0;
+    for (lp = acptr->user->silence; lp; lp = lp->next)
+      sendto_one(sptr, rpl_str(RPL_SILELIST), me.name,
+                sptr->name, acptr->name, lp->value.cp);
+    sendto_one(sptr, rpl_str(RPL_ENDOFSILELIST), me.name, sptr->name,
+              acptr->name);
+    return 0;
+  }
+  cp = parv[1];
+  c = *cp;
+  if (c == '-' || c == '+')
+    cp++;
+  else if (!(strchr(cp, '@') || strchr(cp, '.') || strchr(cp, '!') || strchr(cp, '*'))) {
+    return send_error_to_client(sptr, ERR_NOSUCHNICK, parv[1]);
+  }
+  else
+    c = '+';
+  cp = pretty_mask(cp);
+  if ((c == '-' && !del_silence(sptr, cp)) || (c != '-' && !add_silence(sptr, cp))) {
+    sendto_prefix_one(sptr, sptr, ":%s " MSG_SILENCE " %c%s", parv[0], c, cp);
+    if (c == '-')
+      sendto_serv_butone(0, "%s%s " TOK_SILENCE " * -%s", NumNick(sptr), cp);
+  }
+  return 0;
+}
+
+/*
+ * ms_silence - server message handler
+ *
+ *   parv[0] = sender prefix
+ * From local client:
+ *   parv[1] = mask (NULL sends the list)
+ * From remote client:
+ *   parv[1] = Numeric nick that must be silenced
+ *   parv[2] = mask
+ */
+int ms_silence(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client* acptr;
+
+  if (IsServer(sptr)) {
+    /* PROTOCOL WARNING */
+    /* bail, don't core */
+    return 0;
+  }
+  if (parc < 3 || EmptyString(parv[2])) {
+    /* PROTOCOL WARNING */
+    return need_more_params(sptr, "SILENCE");
+  }
+
+  if (*parv[1])        /* can be a server */
+    acptr = findNUser(parv[1]);
+  else
+    acptr = FindNServer(parv[1]);
+
+  if (*parv[2] == '-') {
+    if (!del_silence(sptr, parv[2] + 1))
+      sendto_serv_butone(cptr, ":%s SILENCE * %s", parv[0], parv[2]);
+  }
+  else {
+    add_silence(sptr, parv[2]);
+    if (acptr && IsServer(acptr->from)) {
+      if (IsServer(acptr))
+       sendto_one(acptr, ":%s SILENCE %s %s",
+                  parv[0], NumServ(acptr), parv[2]);
+      else
+       sendto_one(acptr, ":%s SILENCE %s%s %s",
+                  parv[0], NumNick(acptr), parv[2]);
+    }
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_silence() - Added 19 May 1994 by Run.
+ *
+ *   parv[0] = sender prefix
+ * From local client:
+ *   parv[1] = mask (NULL sends the list)
+ * From remote client:
+ *   parv[1] = Numeric nick that must be silenced
+ *   parv[2] = mask
+ */
+int m_silence(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct SLink *lp;
+  struct Client *acptr;
+  char c, *cp;
+
+  if (MyUser(sptr))
+  {
+    acptr = sptr;
+    if (parc < 2 || *parv[1] == '\0' || (acptr = FindUser(parv[1])))
+    {
+      if (!(acptr->user))
+        return 0;
+      for (lp = acptr->user->silence; lp; lp = lp->next)
+        sendto_one(sptr, rpl_str(RPL_SILELIST), me.name,
+            sptr->name, acptr->name, lp->value.cp);
+      sendto_one(sptr, rpl_str(RPL_ENDOFSILELIST), me.name, sptr->name,
+          acptr->name);
+      return 0;
+    }
+    cp = parv[1];
+    c = *cp;
+    if (c == '-' || c == '+')
+      cp++;
+    else if (!(strchr(cp, '@') || strchr(cp, '.') ||
+        strchr(cp, '!') || strchr(cp, '*')))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+      return -1;
+    }
+    else
+      c = '+';
+    cp = pretty_mask(cp);
+    if ((c == '-' && !del_silence(sptr, cp)) ||
+        (c != '-' && !add_silence(sptr, cp)))
+    {
+      sendto_prefix_one(sptr, sptr, ":%s SILENCE %c%s", parv[0], c, cp);
+      if (c == '-')
+        sendto_serv_butone(0, ":%s SILENCE * -%s", sptr->name, cp);
+    }
+  }
+  else if (parc < 3 || *parv[2] == '\0')
+    return need_more_params(sptr, "SILENCE");
+
+  else
+  {
+    if (*parv[1])        /* can be a server */
+      acptr = findNUser(parv[1]);
+    else
+      acptr = FindNServer(parv[1]);
+
+    if (*parv[2] == '-')
+    {
+      if (!del_silence(sptr, parv[2] + 1))
+        sendto_serv_butone(cptr, ":%s SILENCE * %s", parv[0], parv[2]);
+    }
+    else
+    {
+      add_silence(sptr, parv[2]);
+      if (acptr && IsServer(acptr->from))
+      {
+        if (IsServer(acptr))
+          sendto_one(acptr, ":%s SILENCE %s %s",
+              parv[0], NumServ(acptr), parv[2]);
+        else
+          sendto_one(acptr, ":%s SILENCE %s%s %s",
+              parv[0], NumNick(acptr), parv[2]);
+      }
+    }
+  }
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_squit.c b/ircd/m_squit.c
new file mode 100644 (file)
index 0000000..b43bd22
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_squit.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "match.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ *  ms_squit (server)
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = server name
+ *    parv[2] = timestamp
+ *    parv[parc-1] = comment
+ *
+ * No longer supports wildcards from servers. 
+ * No longer squits a server that gave us an malformed squit message.
+ *    - Isomer 1999-12-18
+ * 
+ */
+int ms_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char* server = parv[1];
+  struct Client *acptr;
+  time_t timestamp;
+  char *comment = 0;
+  
+  if (parc < 2) 
+    return need_more_params(sptr, "SQUIT");
+
+  comment = parv[parc-1];
+  
+  if (BadPtr(parv[parc - 1]))
+       comment=sptr->name;
+       
+  acptr = FindServer(server);
+  
+  if (!acptr) {
+    Debug((DEBUG_NOTICE, "Ignoring SQUIT to an unknown server"));
+    return 0;
+  }
+  
+  /* If they are squitting me, we reverse it */
+  if (IsMe(acptr)) {
+       cptr = acptr;
+       acptr = &me;
+  }
+       
+  timestamp = atoi(parv[2]);
+
+  /* If atoi(parv[2]) == 0 we must indeed squit !
+   * It will be our neighbour.
+   */
+  if ( timestamp != 0 && timestamp != acptr->serv->timestamp) {
+    Debug((DEBUG_NOTICE, "Ignoring SQUIT with the wrong timestamp"));
+    return 0;
+  }
+  
+  return exit_client(cptr, acptr, sptr, comment);
+}
+
+/*
+ *  mo_squit (oper)
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = server name
+ *    parv[2] = comment (optional)
+ *
+ */
+int mo_squit(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  const char* server;
+  struct Client *acptr;
+  struct Client *acptr2;
+  char *comment;
+      
+  if (parc < 2) 
+    return need_more_params(sptr, "SQUIT");
+
+  if (parc < 3 || BadPtr(parv[2]))
+    comment = sptr->name;
+  else
+    comment = parv[2];
+
+  server = parv[1];
+  /*
+   * The following allows wild cards in SQUIT. Only usefull
+   * when the command is issued by an oper.
+   */
+  for (acptr = GlobalClientList; (acptr = next_client(acptr, server));
+      acptr = acptr->next) {
+    if (IsServer(acptr) || IsMe(acptr))
+      break;
+  }
+  
+  /* Not found? Bugger. */
+  if (!acptr || IsMe(acptr))
+    return send_error_to_client(sptr, ERR_NOSUCHSERVER, server);
+
+  /*
+   * Look for a matching server that is closer,
+   * that way we won't accidently squit two close
+   * servers like davis.* and davis-r.* when typing
+   * /SQUIT davis*
+   */
+  for (acptr2 = acptr->serv->up; acptr2 != &me;
+      acptr2 = acptr2->serv->up)
+    if (!match(server, acptr2->name))
+      acptr = acptr2;
+  
+  /* Disallow local opers to squit remote servers */
+  if (IsLocOp(sptr) && !MyConnect(acptr))
+    return send_error_to_client(sptr, ERR_NOPRIVILEGES);
+
+  return exit_client(cptr, acptr, sptr, comment);
+}
+
+
diff --git a/ircd/m_stats.c b/ircd/m_stats.c
new file mode 100644 (file)
index 0000000..9cc5616
--- /dev/null
@@ -0,0 +1,1625 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_stats.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+/*
+ * XXX - ack!!!
+ */
+#include "channel.h"
+#include "class.h"
+#include "client.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_serv.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "userload.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * m_stats - generic message handler
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = statistics selector (defaults to Message frequency)
+ *    parv[2] = target server (current server defaulted, if omitted)
+ * And 'stats l' and 'stats' L:
+ *    parv[3] = server mask ("*" defaulted, if omitted)
+ * Or for stats p,P:
+ *    parv[3] = port mask (returns p-lines when its port is matched by this)
+ * Or for stats k,K,i and I:
+ *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
+ *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
+ *              (defaults to old reply if ommitted, when local or Oper)
+ *              A remote mask (something containing wildcards) is only
+ *              allowed for IRC Operators.
+ * Or for stats M:
+ *    parv[3] = time param
+ *    parv[4] = time param 
+ *    (see report_memleak_stats() in runmalloc.c for details)
+ *
+ * This function is getting really ugly. -Ghostwolf
+ */
+int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
+      "RcveM RcveKBytes :Open since";
+  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
+  struct Message *mptr;
+  struct Client *acptr;
+  struct Gline* gline;
+  struct ConfItem *aconf;
+  char stat = parc > 1 ? parv[1][0] : '\0';
+  int i;
+
+/* m_stats is so obnoxiously full of special cases that the different
+ * hunt_server() possiblites were becoming very messy. It now uses a
+ * switch() so as to be easier to read and update as params change. 
+ * -Ghostwolf 
+ */
+  switch (stat)
+  {
+      /* open to all, standard # of params */
+    case 'U':
+    case 'u':
+    {
+      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* open to all, varying # of params */
+    case 'k':
+    case 'K':
+    case 'i':
+    case 'I':
+    case 'p':
+    case 'P':
+    {
+      if (parc > 3)
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      break;
+    }
+
+      /* oper only, varying # of params */
+    case 'l':
+    case 'L':
+    case 'M':
+    {
+      if (parc == 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else if (parc > 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
+            parv) != HUNTED_ISME)
+          return 0;
+      }
+      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* oper only, standard # of params */
+    default:
+    {
+      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+  }
+
+  switch (stat)
+  {
+    case 'L':
+    case 'l':
+    {
+      int doall = 0, wilds = 0;
+      char *name = "*";
+      if (parc > 3 && *parv[3])
+      {
+        char *p;
+        name = parv[3];
+        wilds = (*name == '*' || *name == '?');
+        for (p = name + 1; *p; ++p)
+          if ((*p == '*' || *p == '?') && p[-1] != '\\')
+          {
+            wilds = 1;
+            break;
+          }
+      }
+      else
+        doall = 1;
+      /*
+       * Send info about connections which match, or all if the
+       * mask matches me.name.  Only restrictions are on those who
+       * are invisible not being visible to 'foreigners' who use
+       * a wild card based search to list it.
+       */
+      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      for (i = 0; i <= HighestFd; i++)
+      {
+        if (!(acptr = LocalClientArray[i]))
+          continue;
+        /* Don't return clients when this is a request for `all' */
+        if (doall && IsUser(acptr))
+          continue;
+        /* Don't show invisible people to unauthorized people when using
+         * wildcards  -- Is this still needed now /stats is oper only ? */
+        if (IsInvisible(acptr) && (doall || wilds) &&
+            !(MyConnect(sptr) && IsOper(sptr)) &&
+            !IsAnOper(acptr) && (acptr != sptr))
+          continue;
+        /* Only show the ones that match the given mask - if any */
+        if (!doall && wilds && match(name, acptr->name))
+          continue;
+        /* Skip all that do not match the specific query */
+        if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
+          continue;
+        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
+                   acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
+                   (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
+                   CurrentTime - acptr->firsttime);
+      }
+      break;
+    }
+    case 'C':
+    case 'c':
+      report_configured_links(sptr, CONF_SERVER);
+      break;
+    case 'G':
+    case 'g': /* send glines */
+      gline_remove_expired(TStime());
+      for (gline = GlobalGlineList; gline; gline = gline->next) {
+        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
+                   sptr->name, 'G', gline->name, gline->host,
+                   gline->expire, gline->reason);
+      }
+      break;
+    case 'H':
+    case 'h':
+      break;
+    case 'I':
+    case 'i':
+    case 'K':
+    case 'k':                   /* display CONF_IPKILL as well
+                                   as CONF_KILL -Kev */
+    {
+      int wilds, count;
+      char *user, *host, *p;
+      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
+      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
+      {
+        report_configured_links(sptr, conf_status);
+        break;
+      }
+      if (parc < 4 || *parv[3] == '\0')
+        return need_more_params(sptr,
+                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
+
+      wilds = 0;
+      for (p = parv[3]; *p; p++)
+      {
+        if (*p == '\\')
+        {
+          if (!*++p)
+            break;
+          continue;
+        }
+        if (*p == '?' || *p == '*')
+        {
+          wilds = 1;
+          break;
+        }
+      }
+      if (!(MyConnect(sptr) || IsOper(sptr)))
+      {
+        wilds = 0;
+        count = 3;
+      }
+      else
+        count = 1000;
+
+      if (conf_status == CONF_CLIENT)
+      {
+        user = 0;            /* Not used, but to avoid compiler warning. */
+
+        host = parv[3];
+      }
+      else
+      {
+        if ((host = strchr(parv[3], '@')))
+        {
+          user = parv[3];
+          *host++ = 0;;
+        }
+        else
+        {
+          user = 0;
+          host = parv[3];
+        }
+      }
+      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+      {
+        if ((aconf->status & conf_status))
+        {
+          if (conf_status == CONF_KLINE)
+          {
+            if ((!wilds && ((user || aconf->host[1]) &&
+                !match(aconf->host, host) &&
+                (!user || !match(aconf->name, user)))) ||
+                (wilds && !mmatch(host, aconf->host) &&
+                (!user || !mmatch(user, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
+                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+          else if (conf_status == CONF_CLIENT)
+          {
+            if ((!wilds && (!match(aconf->host, host) ||
+                !match(aconf->name, host))) ||
+                (wilds && (!mmatch(host, aconf->host) ||
+                !mmatch(host, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
+                  sptr->name, 'I', aconf->host, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+        }
+      }
+      break;
+    }
+    case 'M':
+#if !defined(NDEBUG)
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+#endif
+
+#if 0
+#ifdef MEMSIZESTATS
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], get_mem_size(), get_alloc_cnt());
+#endif
+#ifdef MEMLEAKSTATS
+      report_memleak_stats(sptr, parc, parv);
+#endif
+#if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+          "is not enabled on this server", me.name, parv[0]);
+#endif
+#endif /* 0 */
+      break;
+    case 'm':
+      for (mptr = msgtab; mptr->cmd; mptr++)
+        if (mptr->count)
+          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
+              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+      break;
+    case 'o':
+    case 'O':
+      report_configured_links(sptr, CONF_OPS);
+      break;
+    case 'p':
+    case 'P':
+      /*
+       * show listener ports
+       * show hidden ports to opers, if there are more than 3 parameters,
+       * interpret the fourth parameter as the port number, limit non-local
+       * or non-oper results to 8 ports.
+       */ 
+      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
+                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      break;
+    case 'R':
+    case 'r':
+#ifdef DEBUGMODE
+      send_usage(sptr, parv[0]);
+#endif
+      break;
+    case 'D':
+      report_configured_links(sptr, CONF_CRULEALL);
+      break;
+    case 'd':
+      report_configured_links(sptr, CONF_CRULE);
+      break;
+    case 't':
+      tstats(sptr, parv[0]);
+      break;
+    case 'T':
+      report_configured_links(sptr, CONF_TLINES);
+      break;
+    case 'U':
+      report_configured_links(sptr, CONF_UWORLD);
+      break;
+    case 'u':
+    {
+      time_t nowr;
+
+      nowr = CurrentTime - me.since;
+      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
+          nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
+      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
+          max_connection_count, max_client_count);
+      break;
+    }
+    case 'W':
+    case 'w':
+      calc_load(sptr);
+      break;
+    case 'X':
+    case 'x':
+#ifdef  DEBUGMODE
+      send_listinfo(sptr, parv[0]);
+#endif
+      break;
+    case 'Y':
+    case 'y':
+      report_classes(sptr);
+      break;
+    case 'Z':
+    case 'z':
+      count_memory(sptr, parv[0]);
+      break;
+    default:
+      stat = '*';
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  return 0;
+}
+
+/*
+ * ms_stats - server message handler
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = statistics selector (defaults to Message frequency)
+ *    parv[2] = target server (current server defaulted, if omitted)
+ * And 'stats l' and 'stats' L:
+ *    parv[3] = server mask ("*" defaulted, if omitted)
+ * Or for stats p,P:
+ *    parv[3] = port mask (returns p-lines when its port is matched by this)
+ * Or for stats k,K,i and I:
+ *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
+ *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
+ *              (defaults to old reply if ommitted, when local or Oper)
+ *              A remote mask (something containing wildcards) is only
+ *              allowed for IRC Operators.
+ * Or for stats M:
+ *    parv[3] = time param
+ *    parv[4] = time param 
+ *    (see report_memleak_stats() in runmalloc.c for details)
+ *
+ * This function is getting really ugly. -Ghostwolf
+ */
+int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
+      "RcveM RcveKBytes :Open since";
+  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
+  struct Message *mptr;
+  struct Client *acptr;
+  struct Gline* gline;
+  struct ConfItem *aconf;
+  char stat = parc > 1 ? parv[1][0] : '\0';
+  int i;
+
+/* m_stats is so obnoxiously full of special cases that the different
+ * hunt_server() possiblites were becoming very messy. It now uses a
+ * switch() so as to be easier to read and update as params change. 
+ * -Ghostwolf 
+ */
+  switch (stat)
+  {
+      /* open to all, standard # of params */
+    case 'U':
+    case 'u':
+    {
+      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* open to all, varying # of params */
+    case 'k':
+    case 'K':
+    case 'i':
+    case 'I':
+    case 'p':
+    case 'P':
+    {
+      if (parc > 3)
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      break;
+    }
+
+      /* oper only, varying # of params */
+    case 'l':
+    case 'L':
+    case 'M':
+    {
+      if (parc == 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else if (parc > 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
+            parv) != HUNTED_ISME)
+          return 0;
+      }
+      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* oper only, standard # of params */
+    default:
+    {
+      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+  }
+
+  switch (stat)
+  {
+    case 'L':
+    case 'l':
+    {
+      int doall = 0, wilds = 0;
+      char *name = "*";
+      if (parc > 3 && *parv[3])
+      {
+        char *p;
+        name = parv[3];
+        wilds = (*name == '*' || *name == '?');
+        for (p = name + 1; *p; ++p)
+          if ((*p == '*' || *p == '?') && p[-1] != '\\')
+          {
+            wilds = 1;
+            break;
+          }
+      }
+      else
+        doall = 1;
+      /*
+       * Send info about connections which match, or all if the
+       * mask matches me.name.  Only restrictions are on those who
+       * are invisible not being visible to 'foreigners' who use
+       * a wild card based search to list it.
+       */
+      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      for (i = 0; i <= HighestFd; i++)
+      {
+        if (!(acptr = LocalClientArray[i]))
+          continue;
+        /* Don't return clients when this is a request for `all' */
+        if (doall && IsUser(acptr))
+          continue;
+        /* Don't show invisible people to unauthorized people when using
+         * wildcards  -- Is this still needed now /stats is oper only ? */
+        if (IsInvisible(acptr) && (doall || wilds) &&
+            !(MyConnect(sptr) && IsOper(sptr)) &&
+            !IsAnOper(acptr) && (acptr != sptr))
+          continue;
+        /* Only show the ones that match the given mask - if any */
+        if (!doall && wilds && match(name, acptr->name))
+          continue;
+        /* Skip all that do not match the specific query */
+        if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
+          continue;
+        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
+            acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
+            (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
+            CurrentTime - acptr->firsttime);
+      }
+      break;
+    }
+    case 'C':
+    case 'c':
+      if (IsAnOper(sptr))
+        report_configured_links(sptr, CONF_SERVER);
+      break;
+    case 'G':
+    case 'g': /* send glines */
+      gline_remove_expired(TStime());
+      for (gline = GlobalGlineList; gline; gline = gline->next) {
+        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
+                   sptr->name, 'G', gline->name, gline->host,
+                   gline->expire, gline->reason);
+      }
+      break;
+    case 'H':
+    case 'h':
+      report_configured_links(sptr, CONF_HUB | CONF_LEAF);
+      break;
+    case 'I':
+    case 'i':
+    case 'K':
+    case 'k':                   /* display CONF_IPKILL as well
+                                   as CONF_KILL -Kev */
+    {
+      int wilds, count;
+      char *user, *host, *p;
+      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
+      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
+      {
+        report_configured_links(sptr, conf_status);
+        break;
+      }
+      if (parc < 4 || *parv[3] == '\0')
+        return need_more_params(sptr,
+                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
+
+      wilds = 0;
+      for (p = parv[3]; *p; p++)
+      {
+        if (*p == '\\')
+        {
+          if (!*++p)
+            break;
+          continue;
+        }
+        if (*p == '?' || *p == '*')
+        {
+          wilds = 1;
+          break;
+        }
+      }
+      if (!(MyConnect(sptr) || IsOper(sptr)))
+      {
+        wilds = 0;
+        count = 3;
+      }
+      else
+        count = 1000;
+
+      if (conf_status == CONF_CLIENT)
+      {
+        user = 0;            /* Not used, but to avoid compiler warning. */
+
+        host = parv[3];
+      }
+      else
+      {
+        if ((host = strchr(parv[3], '@')))
+        {
+          user = parv[3];
+          *host++ = 0;;
+        }
+        else
+        {
+          user = 0;
+          host = parv[3];
+        }
+      }
+      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+      {
+        if ((aconf->status & conf_status))
+        {
+          if (conf_status == CONF_KLINE)
+          {
+            if ((!wilds && ((user || aconf->host[1]) &&
+                !match(aconf->host, host) &&
+                (!user || !match(aconf->name, user)))) ||
+                (wilds && !mmatch(host, aconf->host) &&
+                (!user || !mmatch(user, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
+                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+          else if (conf_status == CONF_CLIENT)
+          {
+            if ((!wilds && (!match(aconf->host, host) ||
+                !match(aconf->name, host))) ||
+                (wilds && (!mmatch(host, aconf->host) ||
+                !mmatch(host, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
+                  sptr->name, 'I', aconf->host, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+        }
+      }
+      break;
+    }
+    case 'M':
+#if !defined(NDEBUG)
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+#endif
+
+#if 0
+#ifdef MEMSIZESTATS
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], get_mem_size(), get_alloc_cnt());
+#endif
+#ifdef MEMLEAKSTATS
+      report_memleak_stats(sptr, parc, parv);
+#endif
+#if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+          "is not enabled on this server", me.name, parv[0]);
+#endif
+#endif /* 0 */
+      break;
+    case 'm':
+      for (mptr = msgtab; mptr->cmd; mptr++)
+        if (mptr->count)
+          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
+              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+      break;
+    case 'o':
+    case 'O':
+      report_configured_links(sptr, CONF_OPS);
+      break;
+    case 'p':
+    case 'P':
+      /*
+       * show listener ports
+       * show hidden ports to opers, if there are more than 3 parameters,
+       * interpret the fourth parameter as the port number, limit non-local
+       * or non-oper results to 8 ports.
+       */ 
+      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
+                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      break;
+    case 'R':
+    case 'r':
+#ifdef DEBUGMODE
+      send_usage(sptr, parv[0]);
+#endif
+      break;
+    case 'D':
+      report_configured_links(sptr, CONF_CRULEALL);
+      break;
+    case 'd':
+      report_configured_links(sptr, CONF_CRULE);
+      break;
+    case 't':
+      tstats(sptr, parv[0]);
+      break;
+    case 'T':
+      report_configured_links(sptr, CONF_TLINES);
+      break;
+    case 'U':
+      report_configured_links(sptr, CONF_UWORLD);
+      break;
+    case 'u':
+    {
+      time_t nowr;
+
+      nowr = CurrentTime - me.since;
+      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
+          nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
+      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
+          max_connection_count, max_client_count);
+      break;
+    }
+    case 'W':
+    case 'w':
+      calc_load(sptr);
+      break;
+    case 'X':
+    case 'x':
+#ifdef  DEBUGMODE
+      send_listinfo(sptr, parv[0]);
+#endif
+      break;
+    case 'Y':
+    case 'y':
+      report_classes(sptr);
+      break;
+    case 'Z':
+    case 'z':
+      count_memory(sptr, parv[0]);
+      break;
+    default:
+      stat = '*';
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  return 0;
+}
+
+/*
+ * mo_stats - oper message handler
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = statistics selector (defaults to Message frequency)
+ *    parv[2] = target server (current server defaulted, if omitted)
+ * And 'stats l' and 'stats' L:
+ *    parv[3] = server mask ("*" defaulted, if omitted)
+ * Or for stats p,P:
+ *    parv[3] = port mask (returns p-lines when its port is matched by this)
+ * Or for stats k,K,i and I:
+ *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
+ *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
+ *              (defaults to old reply if ommitted, when local or Oper)
+ *              A remote mask (something containing wildcards) is only
+ *              allowed for IRC Operators.
+ * Or for stats M:
+ *    parv[3] = time param
+ *    parv[4] = time param 
+ *    (see report_memleak_stats() in runmalloc.c for details)
+ *
+ * This function is getting really ugly. -Ghostwolf
+ */
+int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
+      "RcveM RcveKBytes :Open since";
+  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
+  struct Message *mptr;
+  struct Client *acptr;
+  struct Gline* gline;
+  struct ConfItem *aconf;
+  char stat = parc > 1 ? parv[1][0] : '\0';
+  int i;
+
+/* m_stats is so obnoxiously full of special cases that the different
+ * hunt_server() possiblites were becoming very messy. It now uses a
+ * switch() so as to be easier to read and update as params change. 
+ * -Ghostwolf 
+ */
+  switch (stat)
+  {
+      /* open to all, standard # of params */
+    case 'U':
+    case 'u':
+    {
+      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* open to all, varying # of params */
+    case 'k':
+    case 'K':
+    case 'i':
+    case 'I':
+    case 'p':
+    case 'P':
+    {
+      if (parc > 3)
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      break;
+    }
+
+      /* oper only, varying # of params */
+    case 'l':
+    case 'L':
+    case 'M':
+    {
+      if (parc == 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else if (parc > 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
+            parv) != HUNTED_ISME)
+          return 0;
+      }
+      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* oper only, standard # of params */
+    default:
+    {
+      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+  }
+
+  switch (stat)
+  {
+    case 'L':
+    case 'l':
+    {
+      int doall = 0, wilds = 0;
+      char *name = "*";
+      if (parc > 3 && *parv[3])
+      {
+        char *p;
+        name = parv[3];
+        wilds = (*name == '*' || *name == '?');
+        for (p = name + 1; *p; ++p)
+          if ((*p == '*' || *p == '?') && p[-1] != '\\')
+          {
+            wilds = 1;
+            break;
+          }
+      }
+      else
+        doall = 1;
+      /*
+       * Send info about connections which match, or all if the
+       * mask matches me.name.  Only restrictions are on those who
+       * are invisible not being visible to 'foreigners' who use
+       * a wild card based search to list it.
+       */
+      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      for (i = 0; i <= HighestFd; i++)
+      {
+        if (!(acptr = LocalClientArray[i]))
+          continue;
+        /* Don't return clients when this is a request for `all' */
+        if (doall && IsUser(acptr))
+          continue;
+        /* Don't show invisible people to unauthorized people when using
+         * wildcards  -- Is this still needed now /stats is oper only ? */
+        if (IsInvisible(acptr) && (doall || wilds) &&
+            !(MyConnect(sptr) && IsOper(sptr)) &&
+            !IsAnOper(acptr) && (acptr != sptr))
+          continue;
+        /* Only show the ones that match the given mask - if any */
+        if (!doall && wilds && match(name, acptr->name))
+          continue;
+        /* Skip all that do not match the specific query */
+        if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
+          continue;
+        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
+            acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
+            (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
+            CurrentTime - acptr->firsttime);
+      }
+      break;
+    }
+    case 'C':
+    case 'c':
+      report_configured_links(sptr, CONF_SERVER);
+      break;
+    case 'G':
+    case 'g': /* send glines */
+      gline_remove_expired(TStime());
+      for (gline = GlobalGlineList; gline; gline = gline->next) {
+        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
+                   sptr->name, 'G', gline->name, gline->host,
+                   gline->expire, gline->reason);
+      }
+      break;
+    case 'H':
+    case 'h':
+      report_configured_links(sptr, CONF_HUB | CONF_LEAF);
+      break;
+    case 'I':
+    case 'i':
+    case 'K':
+    case 'k':                   /* display CONF_IPKILL as well
+                                   as CONF_KILL -Kev */
+    {
+      int wilds, count;
+      char *user, *host, *p;
+      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
+      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
+      {
+        report_configured_links(sptr, conf_status);
+        break;
+      }
+      if (parc < 4 || *parv[3] == '\0')
+        return need_more_params(sptr,
+                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
+
+      wilds = 0;
+      for (p = parv[3]; *p; p++)
+      {
+        if (*p == '\\')
+        {
+          if (!*++p)
+            break;
+          continue;
+        }
+        if (*p == '?' || *p == '*')
+        {
+          wilds = 1;
+          break;
+        }
+      }
+      if (!(MyConnect(sptr) || IsOper(sptr)))
+      {
+        wilds = 0;
+        count = 3;
+      }
+      else
+        count = 1000;
+
+      if (conf_status == CONF_CLIENT)
+      {
+        user = 0;            /* Not used, but to avoid compiler warning. */
+
+        host = parv[3];
+      }
+      else
+      {
+        if ((host = strchr(parv[3], '@')))
+        {
+          user = parv[3];
+          *host++ = 0;;
+        }
+        else
+        {
+          user = 0;
+          host = parv[3];
+        }
+      }
+      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+      {
+        if ((aconf->status & conf_status))
+        {
+          if (conf_status == CONF_KLINE)
+          {
+            if ((!wilds && ((user || aconf->host[1]) &&
+                !match(aconf->host, host) &&
+                (!user || !match(aconf->name, user)))) ||
+                (wilds && !mmatch(host, aconf->host) &&
+                (!user || !mmatch(user, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
+                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+          else if (conf_status == CONF_CLIENT)
+          {
+            if ((!wilds && (!match(aconf->host, host) ||
+                !match(aconf->name, host))) ||
+                (wilds && (!mmatch(host, aconf->host) ||
+                !mmatch(host, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
+                  sptr->name, 'I', aconf->host, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+        }
+      }
+      break;
+    }
+    case 'M':
+#if !defined(NDEBUG)
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+#endif
+
+#if 0
+#ifdef MEMSIZESTATS
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], get_mem_size(), get_alloc_cnt());
+#endif
+#ifdef MEMLEAKSTATS
+      report_memleak_stats(sptr, parc, parv);
+#endif
+#if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+          "is not enabled on this server", me.name, parv[0]);
+#endif
+#endif /* 0 */
+      break;
+    case 'm':
+      for (mptr = msgtab; mptr->cmd; mptr++)
+        if (mptr->count)
+          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
+              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+      break;
+    case 'o':
+    case 'O':
+      report_configured_links(sptr, CONF_OPS);
+      break;
+    case 'p':
+    case 'P':
+      /*
+       * show listener ports
+       * show hidden ports to opers, if there are more than 3 parameters,
+       * interpret the fourth parameter as the port number, limit non-local
+       * or non-oper results to 8 ports.
+       */ 
+      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
+                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      break;
+    case 'R':
+    case 'r':
+#ifdef DEBUGMODE
+      send_usage(sptr, parv[0]);
+#endif
+      break;
+    case 'D':
+      report_configured_links(sptr, CONF_CRULEALL);
+      break;
+    case 'd':
+      report_configured_links(sptr, CONF_CRULE);
+      break;
+    case 't':
+      tstats(sptr, parv[0]);
+      break;
+    case 'T':
+      report_configured_links(sptr, CONF_TLINES);
+      break;
+    case 'U':
+      report_configured_links(sptr, CONF_UWORLD);
+      break;
+    case 'u':
+    {
+      time_t nowr;
+
+      nowr = CurrentTime - me.since;
+      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
+          nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
+      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
+          max_connection_count, max_client_count);
+      break;
+    }
+    case 'W':
+    case 'w':
+      calc_load(sptr);
+      break;
+    case 'X':
+    case 'x':
+#ifdef  DEBUGMODE
+      send_listinfo(sptr, parv[0]);
+#endif
+      break;
+    case 'Y':
+    case 'y':
+      report_classes(sptr);
+      break;
+    case 'Z':
+    case 'z':
+      count_memory(sptr, parv[0]);
+      break;
+    default:
+      stat = '*';
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  return 0;
+}
+
+#if 0
+/*
+ * m_stats
+ *
+ *    parv[0] = sender prefix
+ *    parv[1] = statistics selector (defaults to Message frequency)
+ *    parv[2] = target server (current server defaulted, if omitted)
+ * And 'stats l' and 'stats' L:
+ *    parv[3] = server mask ("*" defaulted, if omitted)
+ * Or for stats p,P:
+ *    parv[3] = port mask (returns p-lines when its port is matched by this)
+ * Or for stats k,K,i and I:
+ *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
+ *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
+ *              (defaults to old reply if ommitted, when local or Oper)
+ *              A remote mask (something containing wildcards) is only
+ *              allowed for IRC Operators.
+ * Or for stats M:
+ *    parv[3] = time param
+ *    parv[4] = time param 
+ *    (see report_memleak_stats() in runmalloc.c for details)
+ *
+ * This function is getting really ugly. -Ghostwolf
+ */
+int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
+      "RcveM RcveKBytes :Open since";
+  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
+  struct Message *mptr;
+  struct Client *acptr;
+  struct Gline* gline;
+  struct ConfItem *aconf;
+  char stat = parc > 1 ? parv[1][0] : '\0';
+  int i;
+
+/* m_stats is so obnoxiously full of special cases that the different
+ * hunt_server() possiblites were becoming very messy. It now uses a
+ * switch() so as to be easier to read and update as params change. 
+ * -Ghostwolf 
+ */
+  switch (stat)
+  {
+      /* open to all, standard # of params */
+    case 'U':
+    case 'u':
+    {
+      if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* open to all, varying # of params */
+    case 'k':
+    case 'K':
+    case 'i':
+    case 'I':
+    case 'p':
+    case 'P':
+    {
+      if (parc > 3)
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else
+      {
+        if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      break;
+    }
+
+      /* oper only, varying # of params */
+    case 'l':
+    case 'L':
+    case 'M':
+    {
+      if (parc == 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
+            != HUNTED_ISME)
+          return 0;
+      }
+      else if (parc > 4)
+      {
+        if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
+            parv) != HUNTED_ISME)
+          return 0;
+      }
+      else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+
+      /* oper only, standard # of params */
+    default:
+    {
+      if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
+          != HUNTED_ISME)
+        return 0;
+      break;
+    }
+  }
+
+  switch (stat)
+  {
+    case 'L':
+    case 'l':
+    {
+      int doall = 0, wilds = 0;
+      char *name = "*";
+      if (parc > 3 && *parv[3])
+      {
+        char *p;
+        name = parv[3];
+        wilds = (*name == '*' || *name == '?');
+        for (p = name + 1; *p; ++p)
+          if ((*p == '*' || *p == '?') && p[-1] != '\\')
+          {
+            wilds = 1;
+            break;
+          }
+      }
+      else
+        doall = 1;
+      /*
+       * Send info about connections which match, or all if the
+       * mask matches me.name.  Only restrictions are on those who
+       * are invisible not being visible to 'foreigners' who use
+       * a wild card based search to list it.
+       */
+      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
+      for (i = 0; i <= HighestFd; i++)
+      {
+        if (!(acptr = LocalClientArray[i]))
+          continue;
+        /* Don't return clients when this is a request for `all' */
+        if (doall && IsUser(acptr))
+          continue;
+        /* Don't show invisible people to unauthorized people when using
+         * wildcards  -- Is this still needed now /stats is oper only ? */
+        if (IsInvisible(acptr) && (doall || wilds) &&
+            !(MyConnect(sptr) && IsOper(sptr)) &&
+            !IsAnOper(acptr) && (acptr != sptr))
+          continue;
+        /* Only show the ones that match the given mask - if any */
+        if (!doall && wilds && match(name, acptr->name))
+          continue;
+        /* Skip all that do not match the specific query */
+        if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
+          continue;
+        sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
+                   acptr->name,
+                   (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
+                   (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
+                   CurrentTime - acptr->firsttime);
+      }
+      break;
+    }
+    case 'C':
+    case 'c':
+      report_configured_links(sptr, CONF_SERVER);
+      break;
+    case 'G':
+    case 'g': /* send glines */
+      gline_remove_expired(TStime());
+      for (gline = GlobalGlineList; gline; gline = gline->next) {
+        sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
+                   sptr->name, 'G', gline->name, gline->host,
+                   gline->expire, gline->reason);
+      }
+      break;
+    case 'H':
+    case 'h':
+      report_configured_links(sptr, CONF_HUB | CONF_LEAF);
+      break;
+    case 'I':
+    case 'i':
+    case 'K':
+    case 'k':                   /* display CONF_IPKILL as well
+                                   as CONF_KILL -Kev */
+    {
+      int wilds, count;
+      char *user, *host, *p;
+      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
+      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
+      {
+        report_configured_links(sptr, conf_status);
+        break;
+      }
+      if (parc < 4 || *parv[3] == '\0')
+        return need_more_params(sptr,
+                        (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
+
+      wilds = 0;
+      for (p = parv[3]; *p; p++)
+      {
+        if (*p == '\\')
+        {
+          if (!*++p)
+            break;
+          continue;
+        }
+        if (*p == '?' || *p == '*')
+        {
+          wilds = 1;
+          break;
+        }
+      }
+      if (!(MyConnect(sptr) || IsOper(sptr)))
+      {
+        wilds = 0;
+        count = 3;
+      }
+      else
+        count = 1000;
+
+      if (conf_status == CONF_CLIENT)
+      {
+        user = 0;            /* Not used, but to avoid compiler warning. */
+
+        host = parv[3];
+      }
+      else
+      {
+        if ((host = strchr(parv[3], '@')))
+        {
+          user = parv[3];
+          *host++ = 0;;
+        }
+        else
+        {
+          user = 0;
+          host = parv[3];
+        }
+      }
+      for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+      {
+        if ((aconf->status & conf_status))
+        {
+          if (conf_status == CONF_KLINE)
+          {
+            if ((!wilds && ((user || aconf->host[1]) &&
+                !match(aconf->host, host) &&
+                (!user || !match(aconf->name, user)))) ||
+                (wilds && !mmatch(host, aconf->host) &&
+                (!user || !mmatch(user, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
+                  sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+          else if (conf_status == CONF_CLIENT)
+          {
+            if ((!wilds && (!match(aconf->host, host) ||
+                !match(aconf->name, host))) ||
+                (wilds && (!mmatch(host, aconf->host) ||
+                !mmatch(host, aconf->name))))
+            {
+              sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
+                  sptr->name, 'I', aconf->host, aconf->name,
+                  aconf->port, get_conf_class(aconf));
+              if (--count == 0)
+                break;
+            }
+          }
+        }
+      }
+      break;
+    }
+    case 'M':
+#if !defined(NDEBUG)
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
+#endif
+
+#if 0
+#ifdef MEMSIZESTATS
+      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
+          me.name, parv[0], get_mem_size(), get_alloc_cnt());
+#endif
+#ifdef MEMLEAKSTATS
+      report_memleak_stats(sptr, parc, parv);
+#endif
+#if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
+      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
+          "is not enabled on this server", me.name, parv[0]);
+#endif
+#endif /* 0 */
+      break;
+    case 'm':
+      for (mptr = msgtab; mptr->cmd; mptr++)
+        if (mptr->count)
+          sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
+              me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
+      break;
+    case 'o':
+    case 'O':
+      report_configured_links(sptr, CONF_OPS);
+      break;
+    case 'p':
+    case 'P':
+      /*
+       * show listener ports
+       * show hidden ports to opers, if there are more than 3 parameters,
+       * interpret the fourth parameter as the port number, limit non-local
+       * or non-oper results to 8 ports.
+       */ 
+      show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0, 
+                 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
+      break;
+    case 'R':
+    case 'r':
+#ifdef DEBUGMODE
+      send_usage(sptr, parv[0]);
+#endif
+      break;
+    case 'D':
+      report_configured_links(sptr, CONF_CRULEALL);
+      break;
+    case 'd':
+      report_configured_links(sptr, CONF_CRULE);
+      break;
+    case 't':
+      tstats(sptr, parv[0]);
+      break;
+    case 'T':
+      report_configured_links(sptr, CONF_TLINES);
+      break;
+    case 'U':
+      report_configured_links(sptr, CONF_UWORLD);
+      break;
+    case 'u':
+    {
+      time_t nowr;
+
+      nowr = CurrentTime - me.since;
+      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
+                 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
+      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
+                 max_connection_count, max_client_count);
+      break;
+    }
+    case 'W':
+    case 'w':
+      calc_load(sptr);
+      break;
+    case 'X':
+    case 'x':
+#ifdef  DEBUGMODE
+      send_listinfo(sptr, parv[0]);
+#endif
+      break;
+    case 'Y':
+    case 'y':
+      report_classes(sptr);
+      break;
+    case 'Z':
+    case 'z':
+      count_memory(sptr, parv[0]);
+      break;
+    default:
+      stat = '*';
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_time.c b/ircd/m_time.c
new file mode 100644 (file)
index 0000000..7cba40d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_time.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_time - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_time(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  if (hunt_server(0, cptr, sptr, "%s%s " TOK_TIME " :%s", 1, parc, parv) != HUNTED_ISME)
+    return 0;
+
+  sendto_one(sptr, rpl_str(RPL_TIME), me.name,
+             parv[0], me.name, TStime(), TSoffset, date((long)0));
+  return 0;
+}
+
+#if 0
+/*
+ * m_time
+ *
+ * parv[0] = sender prefix
+ * parv[1] = servername
+ */
+int m_time(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  if (hunt_server(0, cptr, sptr, "%s%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
+    sendto_one(sptr, rpl_str(RPL_TIME), me.name,
+        parv[0], me.name, TStime(), TSoffset, date((long)0));
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_tmpl.c b/ircd/m_tmpl.c
new file mode 100644 (file)
index 0000000..0b2eeef
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_tmpl.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_tmpl - generic message handler
+ */
+int m_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+/*
+ * ms_tmpl - server message handler
+ */
+int ms_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+/*
+ * mo_tmpl - oper message handler
+ */
+int mo_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
+  
+/*
+ * mv_tmpl - service message handler
+ */
+int mv_tmpl(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  return 0;
+}
+
diff --git a/ircd/m_topic.c b/ircd/m_topic.c
new file mode 100644 (file)
index 0000000..a7e8368
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_topic.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_topic - generic message handler
+ *
+ * parv[0]        = sender prefix
+ * parv[1]        = channel
+ * parv[parc - 1] = topic (if parc > 2)
+ */
+int m_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *topic = 0, *name, *p = 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "TOPIC");
+
+  if (parc > 2)
+    topic = parv[parc - 1];
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = 0;
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
+        ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)))
+    {
+      sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
+          me.name, parv[0], chptr ? chptr->chname : name);
+      continue;
+    }
+    if (IsModelessChannel(name))
+    {
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+          chptr->chname);
+      continue;
+    }
+    if (IsLocalChannel(name) && !MyUser(sptr))
+      continue;
+
+    if (!topic)                 /* only asking  for topic  */
+    {
+      if (chptr->topic[0] == '\0')
+        sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname);
+      else
+      {
+        sendto_one(sptr, rpl_str(RPL_TOPIC),
+            me.name, parv[0], chptr->chname, chptr->topic);
+        sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
+            me.name, parv[0], chptr->chname,
+            chptr->topic_nick, chptr->topic_time);
+      }
+    }
+    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
+        is_chan_op(sptr, chptr)) && topic)
+    {
+      /* setting a topic */
+      ircd_strncpy(chptr->topic, topic, TOPICLEN);
+      ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
+      chptr->topic_time = CurrentTime;
+      sendto_serv_butone(cptr, "%s%s " TOK_TOPIC " %s :%s",
+          NumNick(sptr), chptr->chname, chptr->topic);
+      sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
+          parv[0], chptr->chname, chptr->topic);
+    }
+    else
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+          me.name, parv[0], chptr->chname);
+  }
+  return 0;
+}
+
+/*
+ * ms_topic - server message handler
+ *
+ * parv[0]        = sender prefix
+ * parv[1]        = channel
+ * parv[parc - 1] = topic (if parc > 2)
+ */
+int ms_topic(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  char *topic = 0, *name, *p = 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "TOPIC");
+
+  if (parc > 2)
+    topic = parv[parc - 1];
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = 0;
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
+        ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)))
+    {
+      sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
+          me.name, parv[0], chptr ? chptr->chname : name);
+      continue;
+    }
+    if (IsModelessChannel(name))
+    {
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+          chptr->chname);
+      continue;
+    }
+    if (IsLocalChannel(name) && !MyUser(sptr))
+      continue;
+
+    if (!topic)                 /* only asking  for topic  */
+    {
+      if (chptr->topic[0] == '\0')
+        sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname);
+      else
+      {
+        sendto_one(sptr, rpl_str(RPL_TOPIC),
+            me.name, parv[0], chptr->chname, chptr->topic);
+        sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
+            me.name, parv[0], chptr->chname,
+            chptr->topic_nick, chptr->topic_time);
+      }
+    }
+    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
+        is_chan_op(sptr, chptr)) && topic)
+    {
+      /* setting a topic */
+      ircd_strncpy(chptr->topic, topic, TOPICLEN);
+      ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
+      chptr->topic_time = CurrentTime;
+      sendto_serv_butone(cptr, "%s%s " TOK_TOPIC " %s :%s",
+          NumNick(sptr), chptr->chname, chptr->topic);
+      sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
+          parv[0], chptr->chname, chptr->topic);
+    }
+    else
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+          me.name, parv[0], chptr->chname);
+  }
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_topic
+ *
+ * parv[0]        = sender prefix
+ * parv[1]        = channel
+ * parv[parc - 1] = topic (if parc > 2)
+ */
+int m_topic(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr;
+  char *topic = 0, *name, *p = 0;
+
+  if (parc < 2)
+    return need_more_params(sptr, "TOPIC");
+
+  if (parc > 2)
+    topic = parv[parc - 1];
+
+  for (; (name = ircd_strtok(&p, parv[1], ",")); parv[1] = 0)
+  {
+    chptr = 0;
+    if (!IsChannelName(name) || !(chptr = FindChannel(name)) ||
+        ((topic || SecretChannel(chptr)) && !find_channel_member(sptr, chptr)))
+    {
+      sendto_one(sptr, err_str(chptr ? ERR_NOTONCHANNEL : ERR_NOSUCHCHANNEL),
+          me.name, parv[0], chptr ? chptr->chname : name);
+      continue;
+    }
+    if (IsModelessChannel(name))
+    {
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
+          chptr->chname);
+      continue;
+    }
+    if (IsLocalChannel(name) && !MyUser(sptr))
+      continue;
+
+    if (!topic)                 /* only asking  for topic  */
+    {
+      if (chptr->topic[0] == '\0')
+        sendto_one(sptr, rpl_str(RPL_NOTOPIC), me.name, parv[0], chptr->chname);
+      else
+      {
+        sendto_one(sptr, rpl_str(RPL_TOPIC),
+            me.name, parv[0], chptr->chname, chptr->topic);
+        sendto_one(sptr, rpl_str(RPL_TOPICWHOTIME),
+            me.name, parv[0], chptr->chname,
+            chptr->topic_nick, chptr->topic_time);
+      }
+    }
+    else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
+        is_chan_op(sptr, chptr)) && topic)
+    {
+      /* setting a topic */
+      ircd_strncpy(chptr->topic, topic, TOPICLEN);
+      ircd_strncpy(chptr->topic_nick, sptr->name, NICKLEN);
+      chptr->topic_time = CurrentTime;
+      sendto_serv_butone(cptr, "%s%s " TOK_TOPIC " %s :%s",
+          NumNick(sptr), chptr->chname, chptr->topic);
+      sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s",
+          parv[0], chptr->chname, chptr->topic);
+    }
+    else
+      sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+          me.name, parv[0], chptr->chname);
+  }
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_trace.c b/ircd/m_trace.c
new file mode 100644 (file)
index 0000000..601892f
--- /dev/null
@@ -0,0 +1,972 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_trace.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_user.h"
+#include "send.h"
+#include "version.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * m_trace - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int m_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int i;
+  struct Client *acptr;
+  struct ConfClass *cltmp;
+  char *tname;
+  int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+  int cnt = 0, wilds, dow;
+
+  if (parc < 2 || BadPtr(parv[1]))
+  {
+    /* just "TRACE" without parameters. Must be from local client */
+    parc = 1;
+    acptr = &me;
+    tname = me.name;
+    i = HUNTED_ISME;
+  }
+  else if (parc < 3 || BadPtr(parv[2]))
+  {
+    /* No target specified. Make one before propagating. */
+    parc = 2;
+    tname = parv[1];
+    if ((acptr = find_match_server(parv[1])) ||
+        ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
+    {
+      if (IsUser(acptr))
+        parv[2] = acptr->user->server->name;
+      else
+        parv[2] = acptr->name;
+      parc = 3;
+      parv[3] = 0;
+      if ((i = hunt_server(IsServer(acptr), cptr, sptr,
+          "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+        return 0;
+    }
+    else
+      i = HUNTED_ISME;
+  }
+  else
+  {
+    /* Got "TRACE <tname> :<target>" */
+    parc = 3;
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      acptr = find_match_server(parv[2]);
+    else
+      acptr = FindNServer(parv[2]);
+    if ((i = hunt_server(0, cptr, sptr,
+        "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+      return 0;
+    tname = parv[1];
+  }
+
+  if (i == HUNTED_PASS)
+  {
+    if (!acptr)
+      acptr = next_client(GlobalClientList, tname);
+    else
+      acptr = acptr->from;
+    sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+#ifndef GODMODE
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
+#else /* GODMODE */
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
+        (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
+#endif /* GODMODE */
+    return 0;
+  }
+
+  doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : 1;
+  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
+  dow = wilds || doall;
+
+  /* Don't give (long) remote listings to lusers */
+  if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
+    return 0;
+
+  for (i = 0; i < MAXCONNECTIONS; i++)
+    link_s[i] = 0, link_u[i] = 0;
+
+  if (doall)
+  {
+    for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
+      if (IsUser(acptr))
+        link_u[acptr->from->fd]++;
+      else if (IsServer(acptr))
+        link_s[acptr->from->fd]++;
+    }
+  }
+
+  /* report all direct connections */
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    unsigned int conClass;
+
+    if (!(acptr = LocalClientArray[i])) /* Local Connection? */
+      continue;
+    if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
+        !IsAnOper(acptr) && (acptr != sptr))
+      continue;
+    if (!doall && wilds && match(tname, acptr->name))
+      continue;
+    if (!dow && 0 != ircd_strcmp(tname, acptr->name))
+      continue;
+
+    conClass = get_client_class(acptr);
+
+    switch (acptr->status)
+    {
+      case STAT_CONNECTING:
+        sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
+                   me.name, parv[0], conClass, acptr->name);
+        cnt++;
+        break;
+      case STAT_HANDSHAKE:
+        sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
+                   me.name, parv[0], conClass, acptr->name);
+        cnt++;
+        break;
+      case STAT_ME:
+        break;
+      case STAT_UNKNOWN:
+      case STAT_UNKNOWN_USER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+            me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+      case STAT_UNKNOWN_SERVER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+                   me.name, parv[0], conClass, "Unknown Server");
+        cnt++;
+        break;
+      case STAT_USER:
+        /* Only opers see users if there is a wildcard
+           but anyone can see all the opers. */
+        if ((IsAnOper(sptr) && (MyUser(sptr) ||
+            !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
+        {
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
+                me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
+                CurrentTime - acptr->lasttime);
+          else
+            sendto_one(sptr, rpl_str(RPL_TRACEUSER),
+                me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
+                CurrentTime - acptr->lasttime);
+          cnt++;
+        }
+        break;
+        /*
+         * Connection is a server
+         *
+         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
+         *
+         * class        Class the server is in
+         * nS           Number of servers reached via this link
+         * nC           Number of clients reached via this link
+         * name         Name of the server linked
+         * ConnBy       Who established this link
+         * last         Seconds since we got something from this link
+         * age          Seconds this link has been alive
+         *
+         * Additional comments etc......        -Cym-<cym@acrux.net>
+         */
+
+      case STAT_SERVER:
+        if (acptr->serv->user)
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                     me.name, parv[0], conClass, link_s[i],
+                     link_u[i], acptr->name,
+                     (*acptr->serv->by) ? acptr->serv->by : "*",
+                     acptr->serv->user->username, acptr->serv->user->host,
+                     CurrentTime - acptr->lasttime,
+                     CurrentTime - acptr->serv->timestamp);
+        else
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                     me.name, parv[0], conClass, link_s[i],
+                     link_u[i], acptr->name,
+                     (*acptr->serv->by) ?  acptr->serv->by : "*", "*",
+                     me.name, CurrentTime - acptr->lasttime,
+                     CurrentTime - acptr->serv->timestamp);
+        cnt++;
+        break;
+      default:                  /* We actually shouldn't come here, -msa */
+        sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0],
+                   get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+    }
+  }
+  /*
+   * Add these lines to summarize the above which can get rather long
+   * and messy when done remotely - Avalon
+   */
+  if (!IsAnOper(sptr) || !cnt)
+  {
+    if (!cnt)
+      /* let the user have some idea that its at the end of the trace */
+      sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                 me.name, parv[0], 0, link_s[me.fd],
+                 link_u[me.fd], "<No_match>", *(me.serv->by) ?
+                 me.serv->by : "*", "*", me.name, 0, 0);
+    return 0;
+  }
+  for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
+    if (Links(cltmp) > 0)
+      sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
+                 parv[0], ConClass(cltmp), Links(cltmp));
+  return 0;
+}
+
+/*
+ * ms_trace - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int ms_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int i;
+  struct Client *acptr;
+  struct ConfClass *cltmp;
+  char *tname;
+  int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+  int cnt = 0, wilds, dow;
+
+  if (parc < 2 || BadPtr(parv[1]))
+  {
+    /* just "TRACE" without parameters. Must be from local client */
+    parc = 1;
+    acptr = &me;
+    tname = me.name;
+    i = HUNTED_ISME;
+  }
+  else if (parc < 3 || BadPtr(parv[2]))
+  {
+    /* No target specified. Make one before propagating. */
+    parc = 2;
+    tname = parv[1];
+    if ((acptr = find_match_server(parv[1])) ||
+        ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
+    {
+      if (IsUser(acptr))
+        parv[2] = acptr->user->server->name;
+      else
+        parv[2] = acptr->name;
+      parc = 3;
+      parv[3] = 0;
+      if ((i = hunt_server(IsServer(acptr), cptr, sptr,
+          "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+        return 0;
+    }
+    else
+      i = HUNTED_ISME;
+  }
+  else
+  {
+    /* Got "TRACE <tname> :<target>" */
+    parc = 3;
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      acptr = find_match_server(parv[2]);
+    else
+      acptr = FindNServer(parv[2]);
+    if ((i = hunt_server(0, cptr, sptr,
+        "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+      return 0;
+    tname = parv[1];
+  }
+
+  if (i == HUNTED_PASS)
+  {
+    if (!acptr)
+      acptr = next_client(GlobalClientList, tname);
+    else
+      acptr = acptr->from;
+    sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+#ifndef GODMODE
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
+#else /* GODMODE */
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
+        (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
+#endif /* GODMODE */
+    return 0;
+  }
+
+  doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : 1;
+  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
+  dow = wilds || doall;
+
+  /* Don't give (long) remote listings to lusers */
+  if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
+    return 0;
+
+  for (i = 0; i < MAXCONNECTIONS; i++)
+    link_s[i] = 0, link_u[i] = 0;
+
+  if (doall)
+  {
+    for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
+      if (IsUser(acptr))
+        link_u[acptr->from->fd]++;
+      else if (IsServer(acptr))
+        link_s[acptr->from->fd]++;
+    }
+  }
+
+  /* report all direct connections */
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    unsigned int conClass;
+
+    if (!(acptr = LocalClientArray[i])) /* Local Connection? */
+      continue;
+    if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
+        !IsAnOper(acptr) && (acptr != sptr))
+      continue;
+    if (!doall && wilds && match(tname, acptr->name))
+      continue;
+    if (!dow && 0 != ircd_strcmp(tname, acptr->name))
+      continue;
+    conClass = get_client_class(acptr);
+
+    switch (acptr->status)
+    {
+      case STAT_CONNECTING:
+        sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
+                   me.name, parv[0], conClass, acptr->name);
+        cnt++;
+        break;
+      case STAT_HANDSHAKE:
+        sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
+                   me.name, parv[0], conClass, acptr->name);
+        cnt++;
+        break;
+      case STAT_ME:
+        break;
+      case STAT_UNKNOWN:
+      case STAT_UNKNOWN_USER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+                   me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+      case STAT_UNKNOWN_SERVER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+                   me.name, parv[0], conClass, "Unknown Server");
+        cnt++;
+        break;
+      case STAT_USER:
+        /* Only opers see users if there is a wildcard
+           but anyone can see all the opers. */
+        if ((IsAnOper(sptr) && (MyUser(sptr) ||
+            !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
+        {
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
+                me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
+                CurrentTime - acptr->lasttime);
+          else
+            sendto_one(sptr, rpl_str(RPL_TRACEUSER),
+                me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
+                CurrentTime - acptr->lasttime);
+          cnt++;
+        }
+        break;
+        /*
+         * Connection is a server
+         *
+         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
+         *
+         * class        Class the server is in
+         * nS           Number of servers reached via this link
+         * nC           Number of clients reached via this link
+         * name         Name of the server linked
+         * ConnBy       Who established this link
+         * last         Seconds since we got something from this link
+         * age          Seconds this link has been alive
+         *
+         * Additional comments etc......        -Cym-<cym@acrux.net>
+         */
+
+      case STAT_SERVER:
+        if (acptr->serv->user)
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                     me.name, parv[0], conClass, link_s[i],
+                     link_u[i], acptr->name,
+                     (*acptr->serv->by) ? acptr->serv->by : "*",
+                     acptr->serv->user->username, acptr->serv->user->host,
+                     CurrentTime - acptr->lasttime,
+                     CurrentTime - acptr->serv->timestamp);
+        else
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                     me.name, parv[0], conClass, link_s[i],
+                     link_u[i], acptr->name,
+                     (*acptr->serv->by) ?  acptr->serv->by : "*", "*",
+                     me.name, CurrentTime - acptr->lasttime,
+                     CurrentTime - acptr->serv->timestamp);
+        cnt++;
+        break;
+      default:                  /* We actually shouldn't come here, -msa */
+        sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0],
+                   get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+    }
+  }
+  /*
+   * Add these lines to summarize the above which can get rather long
+   * and messy when done remotely - Avalon
+   */
+  if (!IsAnOper(sptr) || !cnt)
+  {
+    if (!cnt)
+      /* let the user have some idea that its at the end of the trace */
+      sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+          me.name, parv[0], 0, link_s[me.fd],
+          link_u[me.fd], "<No_match>", *(me.serv->by) ?
+          me.serv->by : "*", "*", me.name, 0, 0);
+    return 0;
+  }
+  for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
+    if (Links(cltmp) > 0)
+      sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
+          parv[0], ConClass(cltmp), Links(cltmp));
+  return 0;
+}
+
+/*
+ * mo_trace - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int mo_trace(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  int i;
+  struct Client *acptr;
+  struct ConfClass *cltmp;
+  char *tname;
+  int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+  int cnt = 0, wilds, dow;
+
+  if (parc < 2 || BadPtr(parv[1]))
+  {
+    /* just "TRACE" without parameters. Must be from local client */
+    parc = 1;
+    acptr = &me;
+    tname = me.name;
+    i = HUNTED_ISME;
+  }
+  else if (parc < 3 || BadPtr(parv[2]))
+  {
+    /* No target specified. Make one before propagating. */
+    parc = 2;
+    tname = parv[1];
+    if ((acptr = find_match_server(parv[1])) ||
+        ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
+    {
+      if (IsUser(acptr))
+        parv[2] = acptr->user->server->name;
+      else
+        parv[2] = acptr->name;
+      parc = 3;
+      parv[3] = 0;
+      if ((i = hunt_server(IsServer(acptr), cptr, sptr,
+          "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+        return 0;
+    }
+    else
+      i = HUNTED_ISME;
+  }
+  else
+  {
+    /* Got "TRACE <tname> :<target>" */
+    parc = 3;
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      acptr = find_match_server(parv[2]);
+    else
+      acptr = FindNServer(parv[2]);
+    if ((i = hunt_server(0, cptr, sptr,
+        "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+      return 0;
+    tname = parv[1];
+  }
+
+  if (i == HUNTED_PASS)
+  {
+    if (!acptr)
+      acptr = next_client(GlobalClientList, tname);
+    else
+      acptr = acptr->from;
+    sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+#ifndef GODMODE
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
+#else /* GODMODE */
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
+        (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
+#endif /* GODMODE */
+    return 0;
+  }
+
+  doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : 1;
+  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
+  dow = wilds || doall;
+
+  /* Don't give (long) remote listings to lusers */
+  if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
+    return 0;
+
+  for (i = 0; i < MAXCONNECTIONS; i++)
+    link_s[i] = 0, link_u[i] = 0;
+
+  if (doall)
+  {
+    for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
+      if (IsUser(acptr))
+        link_u[acptr->from->fd]++;
+      else if (IsServer(acptr))
+        link_s[acptr->from->fd]++;
+    }
+  }
+
+  /* report all direct connections */
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    unsigned int conClass;
+
+    if (!(acptr = LocalClientArray[i])) /* Local Connection? */
+      continue;
+    if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
+        !IsAnOper(acptr) && (acptr != sptr))
+      continue;
+    if (!doall && wilds && match(tname, acptr->name))
+      continue;
+    if (!dow && 0 != ircd_strcmp(tname, acptr->name))
+      continue;
+    conClass = get_client_class(acptr);
+
+    switch (acptr->status)
+    {
+      case STAT_CONNECTING:
+        sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
+                   me.name, parv[0], conClass, acptr->name);
+        cnt++;
+        break;
+      case STAT_HANDSHAKE:
+        sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
+                   me.name, parv[0], conClass, acptr->name);
+        cnt++;
+        break;
+      case STAT_ME:
+        break;
+      case STAT_UNKNOWN:
+      case STAT_UNKNOWN_USER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+                   me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+      case STAT_UNKNOWN_SERVER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+                   me.name, parv[0], conClass, "Unknown Server");
+        cnt++;
+        break;
+      case STAT_USER:
+        /* Only opers see users if there is a wildcard
+           but anyone can see all the opers. */
+        if ((IsAnOper(sptr) && (MyUser(sptr) ||
+            !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
+        {
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
+                       me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
+                       CurrentTime - acptr->lasttime);
+          else
+            sendto_one(sptr, rpl_str(RPL_TRACEUSER),
+                       me.name, parv[0], conClass, get_client_name(acptr, HIDE_IP),
+                       CurrentTime - acptr->lasttime);
+          cnt++;
+        }
+        break;
+        /*
+         * Connection is a server
+         *
+         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
+         *
+         * class        Class the server is in
+         * nS           Number of servers reached via this link
+         * nC           Number of clients reached via this link
+         * name         Name of the server linked
+         * ConnBy       Who established this link
+         * last         Seconds since we got something from this link
+         * age          Seconds this link has been alive
+         *
+         * Additional comments etc......        -Cym-<cym@acrux.net>
+         */
+
+      case STAT_SERVER:
+        if (acptr->serv->user)
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                     me.name, parv[0], conClass, link_s[i],
+                     link_u[i], acptr->name,
+                     (*acptr->serv->by) ? acptr->serv->by : "*",
+                     acptr->serv->user->username, acptr->serv->user->host,
+                     CurrentTime - acptr->lasttime,
+                     CurrentTime - acptr->serv->timestamp);
+        else
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                     me.name, parv[0], conClass, link_s[i],
+                     link_u[i], acptr->name,
+                     (*acptr->serv->by) ?  acptr->serv->by : "*", "*",
+                     me.name, CurrentTime - acptr->lasttime,
+                     CurrentTime - acptr->serv->timestamp);
+        cnt++;
+        break;
+      default:                  /* We actually shouldn't come here, -msa */
+        sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0],
+                   get_client_name(acptr, HIDE_IP));
+        cnt++;
+        break;
+    }
+  }
+  /*
+   * Add these lines to summarize the above which can get rather long
+   * and messy when done remotely - Avalon
+   */
+  if (!IsAnOper(sptr) || !cnt)
+  {
+    if (!cnt)
+      /* let the user have some idea that its at the end of the trace */
+      sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                 me.name, parv[0], 0, link_s[me.fd],
+                 link_u[me.fd], "<No_match>", *(me.serv->by) ?
+                 me.serv->by : "*", "*", me.name, 0, 0);
+    return 0;
+  }
+  for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
+    if (Links(cltmp) > 0)
+      sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
+                 parv[0], ConClass(cltmp), Links(cltmp));
+  return 0;
+}
+
+  
+#if 0
+/*
+ * m_trace
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nick or servername
+ * parv[2] = 'target' servername
+ */
+int m_trace(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  int i;
+  struct Client *acptr;
+  struct ConfClass *cltmp;
+  char *tname;
+  int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+  int cnt = 0, wilds, dow;
+
+  if (parc < 2 || BadPtr(parv[1]))
+  {
+    /* just "TRACE" without parameters. Must be from local client */
+    parc = 1;
+    acptr = &me;
+    tname = me.name;
+    i = HUNTED_ISME;
+  }
+  else if (parc < 3 || BadPtr(parv[2]))
+  {
+    /* No target specified. Make one before propagating. */
+    parc = 2;
+    tname = parv[1];
+    if ((acptr = find_match_server(parv[1])) ||
+        ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
+    {
+      if (IsUser(acptr))
+        parv[2] = acptr->user->server->name;
+      else
+        parv[2] = acptr->name;
+      parc = 3;
+      parv[3] = 0;
+      if ((i = hunt_server(IsServer(acptr), cptr, sptr,
+          "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+        return 0;
+    }
+    else
+      i = HUNTED_ISME;
+  }
+  else
+  {
+    /* Got "TRACE <tname> :<target>" */
+    parc = 3;
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      acptr = find_match_server(parv[2]);
+    else
+      acptr = FindNServer(parv[2]);
+    if ((i = hunt_server(0, cptr, sptr,
+        "%s%s " TOK_TRACE " %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
+      return 0;
+    tname = parv[1];
+  }
+
+  if (i == HUNTED_PASS)
+  {
+    if (!acptr)
+      acptr = next_client(GlobalClientList, tname);
+    else
+      acptr = acptr->from;
+    sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+#ifndef GODMODE
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
+#else /* GODMODE */
+        version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
+        (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
+#endif /* GODMODE */
+    return 0;
+  }
+
+  doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
+  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
+  dow = wilds || doall;
+
+  /* Don't give (long) remote listings to lusers */
+  if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
+    return 0;
+
+  for (i = 0; i < MAXCONNECTIONS; i++)
+    link_s[i] = 0, link_u[i] = 0;
+
+  if (doall)
+  {
+    for (acptr = GlobalClientList; acptr; acptr = acptr->next) {
+      if (IsUser(acptr))
+        link_u[acptr->from->fd]++;
+      else if (IsServer(acptr))
+        link_s[acptr->from->fd]++;
+    }
+  }
+
+  /* report all direct connections */
+
+  for (i = 0; i <= HighestFd; i++)
+  {
+    const char* name;
+    unsigned int conClass;
+
+    if (!(acptr = LocalClientArray[i])) /* Local Connection? */
+      continue;
+    if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
+        !IsAnOper(acptr) && (acptr != sptr))
+      continue;
+    if (!doall && wilds && match(tname, acptr->name))
+      continue;
+    if (!dow && 0 != ircd_strcmp(tname, acptr->name))
+      continue;
+    conClass = get_client_class(acptr);
+
+    switch (acptr->status)
+    {
+      case STAT_CONNECTING:
+        sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
+            me.name, parv[0], conClass, name);
+        cnt++;
+        break;
+      case STAT_HANDSHAKE:
+        sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
+            me.name, parv[0], conClass, name);
+        cnt++;
+        break;
+      case STAT_ME:
+        break;
+      case STAT_UNKNOWN:
+      case STAT_UNKNOWN_USER:
+      case STAT_UNKNOWN_SERVER:
+        sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+            me.name, parv[0], conClass, name);
+        cnt++;
+        break;
+      case STAT_USER:
+        /* Only opers see users if there is a wildcard
+           but anyone can see all the opers. */
+        if ((IsAnOper(sptr) && (MyUser(sptr) ||
+            !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
+        {
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
+                me.name, parv[0], conClass, name, CurrentTime - acptr->lasttime);
+          else
+            sendto_one(sptr, rpl_str(RPL_TRACEUSER),
+                me.name, parv[0], conClass, name, CurrentTime - acptr->lasttime);
+          cnt++;
+        }
+        break;
+        /*
+         * Connection is a server
+         *
+         * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
+         *
+         * class        Class the server is in
+         * nS           Number of servers reached via this link
+         * nC           Number of clients reached via this link
+         * name         Name of the server linked
+         * ConnBy       Who established this link
+         * last         Seconds since we got something from this link
+         * age          Seconds this link has been alive
+         *
+         * Additional comments etc......        -Cym-<cym@acrux.net>
+         */
+
+      case STAT_SERVER:
+        if (acptr->serv->user)
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+              me.name, parv[0], conClass, link_s[i],
+              link_u[i], name, (*acptr->serv->by) ? acptr->serv->by : "*",
+              acptr->serv->user->username, acptr->serv->user->host,
+              CurrentTime - acptr->lasttime,
+              CurrentTime - acptr->serv->timestamp);
+        else
+          sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+              me.name, parv[0], conClass, link_s[i],
+              link_u[i], name, (*acptr->serv->by) ?  acptr->serv->by : "*", "*",
+              me.name, CurrentTime - acptr->lasttime,
+              CurrentTime - acptr->serv->timestamp);
+        cnt++;
+        break;
+      default:                  /* We actually shouldn't come here, -msa */
+        sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0], name);
+        cnt++;
+        break;
+    }
+  }
+  /*
+   * Add these lines to summarize the above which can get rather long
+   * and messy when done remotely - Avalon
+   */
+  if (!IsAnOper(sptr) || !cnt)
+  {
+    if (!cnt)
+      /* let the user have some idea that its at the end of the trace */
+      sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+          me.name, parv[0], 0, link_s[me.fd],
+          link_u[me.fd], "<No_match>", *(me.serv->by) ?
+          me.serv->by : "*", "*", me.name, 0, 0);
+    return 0;
+  }
+  for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
+    if (Links(cltmp) > 0)
+      sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
+          parv[0], ConClass(cltmp), Links(cltmp));
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_user.c b/ircd/m_user.c
new file mode 100644 (file)
index 0000000..6513b93
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_user.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define UFLAGS  (FLAGS_INVISIBLE|FLAGS_SERVNOTICE)
+
+/*
+ * m_user
+ *
+ * parv[0] = sender prefix
+ * parv[1] = username           (login name, account)
+ * parv[2] = umode mask         (host name)
+ * parv[3] = server notice mask (server name)
+ * parv[4] = users real name info
+ */
+int m_user(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char*        username;
+  char*        umode;
+  char*        snomask;
+  char*        info;
+  struct User* user;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (IsServerPort(cptr))
+    return exit_client(cptr, cptr, &me, "Use a different port");
+
+  if (parc < 5)
+    return need_more_params(sptr, "USER");
+
+  /* 
+   * Copy parameters into better documenting variables
+   *
+   * ignore host part if u@h
+   */
+  if (!EmptyString(parv[1])) {
+    if ((username = strchr(parv[1], '@')))
+      *username = '\0';
+    username = parv[1];
+  }
+  else
+    username = "NoUser";
+
+  umode    = (EmptyString(parv[2])) ? "."       : parv[2];
+  snomask  = (EmptyString(parv[3])) ? "."       : parv[3];
+  info     = (EmptyString(parv[4])) ? "No Info" : parv[4];
+
+  user = make_user(cptr);
+
+  if (!strchr(umode, '.'))        /* Not an IP# as hostname ? */
+    cptr->flags |= (UFLAGS & atoi(umode));
+
+  if ((cptr->flags & FLAGS_SERVNOTICE))
+    set_snomask(cptr, (IsDigit(*snomask) && !strchr(snomask, '.')) ?
+                (atoi(snomask) & SNO_USER) : SNO_DEFAULT, SNO_SET);
+
+  user->server = &me;
+  ircd_strncpy(cptr->info, info, REALLEN);
+
+  if (cptr->name[0] && cptr->cookie == COOKIE_VERIFIED) {
+    /*
+     * NICK and PONG already received, now we have USER...
+     */
+    return register_user(cptr, sptr, sptr->name, username);
+  }
+  else {
+    ircd_strncpy(user->username, username, USERLEN);
+    ircd_strncpy(user->host, cptr->sockhost, HOSTLEN);
+  }
+  return 0;
+}
+
diff --git a/ircd/m_userhost.c b/ircd/m_userhost.c
new file mode 100644 (file)
index 0000000..4a7811e
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_userhost.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "struct.h"
+
+#include <assert.h>
+
+static char* userhost_formatter(struct Client* cptr, char* buf)
+{
+  assert(IsUser(cptr));
+  return sprintf_irc(buf, "%s%s=%c%s@%s", cptr->name,
+                     IsAnOper(cptr) ? "*" : "",
+                     (cptr->user->away) ? '-' : '+',
+                     cptr->user->username, cptr->user->host);
+}
+
+/*
+ * m_userhost - generic message handler
+ */
+int m_userhost(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(sptr == cptr);
+
+  if (parc < 2)
+    return need_more_params(sptr, "USERHOST");
+
+  send_user_info(sptr, parv[1], RPL_USERHOST, userhost_formatter);
+  return 0;
+}
+
+#if 0
+/*
+ * m_userhost
+ *
+ * Added by Darren Reed 13/8/91 to aid clients and reduce the need for
+ * complicated requests like WHOIS.
+ *
+ * Returns user/host information only (no spurious AWAY labels or channels).
+ *
+ * Rewritten to speed it up by Carlo Wood 3/8/97.
+ */
+int m_userhost(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *s;
+  int i, j = 5;
+  char *p = 0, *sbuf;
+  struct Client *acptr;
+
+  if (parc < 2)
+    return need_more_params(sptr, "USERHOST");
+
+  sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERHOST), me.name, parv[0]);
+  for (i = j, s = ircd_strtok(&p, parv[1], " "); i && s;
+      s = ircd_strtok(&p, (char *)0, " "), i--)
+    if ((acptr = FindUser(s)))
+    {
+      if (i < j)
+        *sbuf++ = ' ';
+      sbuf = sprintf_irc(sbuf, "%s%s=%c%s@%s", acptr->name,
+          IsAnOper(acptr) ? "*" : "", (acptr->user->away) ? '-' : '+',
+          acptr->user->username, acptr->user->host);
+    }
+    else
+    {
+      if (i < j)
+        sendbufto_one(sptr);
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], s);
+      sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERHOST), me.name, parv[0]);
+      j = i - 1;
+    }
+  if (j)
+    sendbufto_one(sptr);
+  return 0;
+}
+#endif
diff --git a/ircd/m_userip.c b/ircd/m_userip.c
new file mode 100644 (file)
index 0000000..8f8cb1a
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_userip.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "s_user.h"
+#include "struct.h"
+
+#include <assert.h>
+
+static char* userip_formatter(struct Client* cptr, char* buf)
+{
+  assert(IsUser(cptr));
+  return sprintf_irc(buf, "%s%s=%c%s@%s", cptr->name,
+                     IsAnOper(cptr) ? "*" : "",
+                     (cptr->user->away) ? '-' : '+',
+                     cptr->user->username,
+                     ircd_ntoa((const char*) &cptr->ip));
+}
+
+/*
+ * m_userip - generic message handler
+ */
+int m_userip(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  if (parc < 2)
+    return need_more_params(sptr, "USERIP");
+  send_user_info(sptr, parv[1], RPL_USERIP, userip_formatter); 
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_userip added by Carlo Wood 3/8/97.
+ *
+ * The same as USERHOST, but with the IP-number instead of the hostname.
+ */
+int m_userip(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *s;
+  int i, j = 5;
+  char *p = 0, *sbuf;
+  struct Client *acptr;
+
+  if (parc < 2)
+    return need_more_params(sptr, "USERIP");
+
+  sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERIP), me.name, parv[0]);
+  for (i = j, s = ircd_strtok(&p, parv[1], " "); i && s;
+      s = ircd_strtok(&p, (char *)0, " "), i--)
+    if ((acptr = FindUser(s)))
+    {
+      if (i < j)
+        *sbuf++ = ' ';
+      sbuf = sprintf_irc(sbuf, "%s%s=%c%s@%s", acptr->name,
+          IsAnOper(acptr) ? "*" : "", (acptr->user->away) ? '-' : '+',
+          acptr->user->username, ircd_ntoa((const char*) &acptr->ip));
+    }
+    else
+    {
+      if (i < j)
+        sendbufto_one(sptr);
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], s);
+      sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERIP), me.name, parv[0]);
+      j = i - 1;
+    }
+  if (i < j)
+    sendbufto_one(sptr);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_version.c b/ircd/m_version.c
new file mode 100644 (file)
index 0000000..0eb1230
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_version.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "s_user.h"
+#include "send.h"
+#include "version.h"
+
+#include <assert.h>
+
+/*
+ * m_version - generic message handler
+ *
+ *   parv[0] = sender prefix
+ *   parv[1] = remote server
+ */
+int m_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (MyConnect(sptr) && parc > 1)
+  {
+    if (!(acptr = find_match_server(parv[1])))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
+      return 0;
+    }
+    parv[1] = acptr->name;
+  }
+
+  if (hunt_server(0, cptr, sptr, "%s%s " TOK_VERSION " :%s", 1, parc, parv) ==
+      HUNTED_ISME)
+    sendto_one(sptr, rpl_str(RPL_VERSION),
+        me.name, parv[0], version, debugmode, me.name, serveropts);
+
+  return 0;
+}
+
+/*
+ * ms_version - server message handler
+ *
+ *   parv[0] = sender prefix
+ *   parv[1] = remote server
+ */
+int ms_version(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Client *acptr;
+
+  if (MyConnect(sptr) && parc > 1)
+  {
+    if (!(acptr = find_match_server(parv[1])))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
+      return 0;
+    }
+    parv[1] = acptr->name;
+  }
+
+  if (hunt_server(0, cptr, sptr, "%s%s " TOK_VERSION " :%s", 1, parc, parv) ==
+      HUNTED_ISME)
+    sendto_one(sptr, rpl_str(RPL_VERSION),
+        me.name, parv[0], version, debugmode, me.name, serveropts);
+
+  return 0;
+}
+
+#if 0
+/*
+ * m_version
+ *
+ *   parv[0] = sender prefix
+ *   parv[1] = remote server
+ */
+int m_version(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Client *acptr;
+
+  if (MyConnect(sptr) && parc > 1)
+  {
+    if (!(acptr = find_match_server(parv[1])))
+    {
+      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
+      return 0;
+    }
+    parv[1] = acptr->name;
+  }
+
+  if (hunt_server(0, cptr, sptr, "%s%s " TOK_VERSION " :%s", 1, parc, parv) ==
+      HUNTED_ISME)
+    sendto_one(sptr, rpl_str(RPL_VERSION),
+        me.name, parv[0], version, debugmode, me.name, serveropts);
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_wallchops.c b/ircd/m_wallchops.c
new file mode 100644 (file)
index 0000000..8313504
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_wallchops.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+
+#include <assert.h>
+
+/*
+ * m_wallchops - local generic message handler
+ */
+int m_wallchops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+
+  assert(0 != cptr);
+  assert(cptr == sptr);
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || EmptyString(parv[1]))
+    return send_error_to_client(sptr, ERR_NORECIPIENT, "WALLCHOPS");
+
+  if (parc < 3 || EmptyString(parv[parc - 1]))
+    return send_error_to_client(sptr, ERR_NOTEXTTOSEND);
+
+  if (IsChannelName(parv[1]) && (chptr = FindChannel(parv[1]))) {
+    if (client_can_send_to_channel(sptr, chptr)) {
+      if ((chptr->mode.mode & MODE_NOPRIVMSGS) &&
+          check_target_limit(sptr, chptr, chptr->chname, 0))
+        return 0;
+      /* Send to local clients: */
+      sendto_lchanops_butone(cptr, sptr, chptr,
+            ":%s " MSG_NOTICE " @%s :%s", sptr->name, parv[1], parv[parc - 1]);
+      /* And to other servers: */
+      sendto_chanopsserv_butone(cptr, sptr, chptr,
+            "%s%s " TOK_WALLCHOPS " %s :%s", NumNick(sptr), parv[1], parv[parc - 1]);
+    }
+    else
+      send_error_to_client(sptr, ERR_CANNOTSENDTOCHAN, parv[1]);
+  }
+  else
+    send_error_to_client(sptr, ERR_NOSUCHCHANNEL, parv[1]);
+
+  return 0;
+}
+
+/*
+ * ms_wallchops - server message handler
+ */
+int ms_wallchops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Channel *chptr;
+  assert(0 != cptr);
+  assert(0 != sptr);
+
+  if (parc < 3 || !IsUser(sptr))
+    return 0;
+
+  if ((chptr = FindChannel(parv[1]))) {
+    if (client_can_send_to_channel(sptr, chptr)) {
+      /*
+       * Send to local clients:
+       */
+      sendto_lchanops_butone(cptr, sptr, chptr,
+          ":%s " MSG_NOTICE " @%s :%s", sptr->name, parv[1], parv[parc - 1]);
+      /*
+       * And to other servers:
+       */
+      sendto_chanopsserv_butone(cptr, sptr, chptr,
+          "%s%s " TOK_WALLCHOPS " %s :%s", NumNick(sptr), parv[1], parv[parc - 1]);
+    }
+    else
+      sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN), me.name, sptr->name, parv[1]);
+  }
+  return 0;
+}
+
+#if 0
+/*
+ * m_wallchops
+ *
+ * parv[0] = sender prefix
+ * parv[1] = target channel
+ * parv[parc - 1] = wallchops text
+ */
+int m_wallchops(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Channel *chptr;
+
+  sptr->flags &= ~FLAGS_TS8;
+
+  if (parc < 2 || *parv[1] == '\0')
+  {
+    sendto_one(sptr, err_str(ERR_NORECIPIENT), me.name, parv[0], "WALLCHOPS");
+    return -1;
+  }
+
+  if (parc < 3 || *parv[parc - 1] == '\0')
+  {
+    sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+    return -1;
+  }
+
+  if (MyUser(sptr))
+    parv[1] = canonize(parv[1]);
+
+  if (IsChannelName(parv[1]))
+  {
+    if ((chptr = FindChannel(parv[1])))
+    {
+      if (client_can_send_to_channel(sptr, chptr))
+      {
+        if (MyUser(sptr) && (chptr->mode.mode & MODE_NOPRIVMSGS) &&
+            check_target_limit(sptr, chptr, chptr->chname, 0))
+          return 0;
+        /* Send to local clients: */
+        sendto_lchanops_butone(cptr, sptr, chptr,
+            ":%s NOTICE @%s :%s", parv[0], parv[1], parv[parc - 1]);
+        /* And to other servers: */
+        sendto_chanopsserv_butone(cptr, sptr, chptr,
+            ":%s WC %s :%s", parv[0], parv[1], parv[parc - 1]);
+      }
+      else
+        sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
+            me.name, parv[0], parv[1]);
+    }
+  }
+  else
+    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]);
+
+  return 0;
+}
+#endif /* 0 */
diff --git a/ircd/m_wallops.c b/ircd/m_wallops.c
new file mode 100644 (file)
index 0000000..af2015b
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_wallops.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "send.h"
+
+#include <assert.h>
+
+
+/*
+ * ms_wallops - server message handler
+ */
+int ms_wallops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  if (EmptyString(message))
+    return need_more_params(sptr, "WALLOPS");
+
+  sendto_ops_butone(cptr, sptr, ":%s WALLOPS :%s", parv[0], message);
+  return 0;
+}
+
+/*
+ * mo_wallops - oper message handler
+ */
+int mo_wallops(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  if (EmptyString(message))
+    return need_more_params(sptr, "WALLOPS");
+
+  sendto_ops_butone(0, sptr, ":%s WALLOPS :%s", parv[0], message);
+  return 0;
+}
+
+  
+#if 0
+/*
+ * m_wallops
+ *
+ * Writes to all +w users currently online
+ *
+ * parv[0] = sender prefix
+ * parv[1] = message text
+ */
+int m_wallops(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *message;
+
+  message = parc > 1 ? parv[1] : 0;
+
+  if (BadPtr(message))
+    return need_more_params(sptr, "WALLOPS");
+
+  if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return 0;
+  }
+  sendto_ops_butone(IsServer(cptr) ? cptr : 0, sptr,
+      ":%s WALLOPS :%s", parv[0], message);
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_who.c b/ircd/m_who.c
new file mode 100644 (file)
index 0000000..e93320f
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_who.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "send.h"
+#include "support.h"
+#include "whocmds.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+/*
+ * A little spin-marking utility to tell us wich clients we have already
+ * processed and wich not
+ */
+static int who_marker = 0;
+static void move_marker(void)
+{
+  if (!++who_marker)
+  {
+    struct Client *cptr = GlobalClientList;
+    while (cptr)
+    {
+      cptr->marker = 0;
+      cptr = cptr->next;
+    }
+    who_marker++;
+  }
+}
+
+#define CheckMark(x, y) ((x == y) ? 0 : (x = y))
+#define Process(cptr) CheckMark(cptr->marker, who_marker)
+
+/*
+ * m_who - generic message handler
+ *
+ *  parv[0] = sender prefix
+ *  parv[1] = nickname mask list
+ *  parv[2] = additional selection flag, only 'o' for now.
+ *            and %flags to specify what fields to output
+ *            plus a ,querytype if the t flag is specified
+ *            so the final thing will be like o%tnchu,777
+ *  parv[3] = _optional_ parameter that overrides parv[1]
+ *            This can be used as "/quote who foo % :The Black Hacker
+ *            to find me, parv[3] _can_ contain spaces !.
+ */
+int m_who(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  char *mask;           /* The mask we are looking for              */
+  char ch;                      /* Scratch char register                    */
+  struct Channel *chptr;                /* Channel to show                          */
+  struct Client *acptr;         /* Client to show                           */
+
+  int bitsel;                   /* Mask of selectors to apply               */
+  int matchsel;                 /* Wich fields the match should apply on    */
+  int counter;                  /* Query size counter,
+                                   initially used to count fields           */
+  int commas;                   /* Does our mask contain any comma ?
+                                   If so is a list..                        */
+  int fields;                   /* Mask of fields to show                   */
+  int isthere = 0;              /* When this set the user is member of chptr */
+  char *nick;                   /* Single element extracted from
+                                   the mask list                            */
+  char *p;                      /* Scratch char pointer                     */
+  char *qrt;                    /* Pointer to the query type                */
+  static char mymask[512];      /* To save the mask before corrupting it    */
+
+  /* Let's find where is our mask, and if actually contains something */
+  mask = ((parc > 1) ? parv[1] : 0);
+  if (parc > 3 && parv[3])
+    mask = parv[3];
+  if (mask && ((mask[0] == '\0') ||
+      (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*')))))
+    mask = 0;
+
+  /* Evaluate the flags now, we consider the second parameter 
+     as "matchFlags%fieldsToInclude,querytype"           */
+  bitsel = fields = counter = matchsel = 0;
+  qrt = 0;
+  if (parc > 2 && parv[2] && *parv[2])
+  {
+    p = parv[2];
+    while (((ch = *(p++))) && (ch != '%') && (ch != ','))
+      switch (ch)
+      {
+        case 'o':
+        case 'O':
+          bitsel |= WHOSELECT_OPER;
+          continue;
+        case 'x':
+        case 'X':
+          bitsel |= WHOSELECT_EXTRA;
+#ifdef WPATH
+          if (IsAnOper(sptr))
+            write_log(WPATH, "# " TIME_T_FMT " %s!%s@%s WHO %s %s\n",
+                CurrentTime, sptr->name, sptr->user->username, sptr->user->host,
+                (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]);
+#endif /* WPATH */
+          continue;
+        case 'n':
+        case 'N':
+          matchsel |= WHO_FIELD_NIC;
+          continue;
+        case 'u':
+        case 'U':
+          matchsel |= WHO_FIELD_UID;
+          continue;
+        case 'h':
+        case 'H':
+          matchsel |= WHO_FIELD_HOS;
+          continue;
+        case 'i':
+        case 'I':
+          matchsel |= WHO_FIELD_NIP;
+          continue;
+        case 's':
+        case 'S':
+          matchsel |= WHO_FIELD_SER;
+          continue;
+        case 'r':
+        case 'R':
+          matchsel |= WHO_FIELD_REN;
+          continue;
+      }
+    if (ch == '%')
+      while ((ch = *p++) && (ch != ','))
+      {
+        counter++;
+        switch (ch)
+        {
+          case 'c':
+          case 'C':
+            fields |= WHO_FIELD_CHA;
+            break;
+          case 'd':
+          case 'D':
+            fields |= WHO_FIELD_DIS;
+            break;
+          case 'f':
+          case 'F':
+            fields |= WHO_FIELD_FLA;
+            break;
+          case 'h':
+          case 'H':
+            fields |= WHO_FIELD_HOS;
+            break;
+          case 'i':
+          case 'I':
+            fields |= WHO_FIELD_NIP;
+            break;
+          case 'n':
+          case 'N':
+            fields |= WHO_FIELD_NIC;
+            break;
+          case 'r':
+          case 'R':
+            fields |= WHO_FIELD_REN;
+            break;
+          case 's':
+          case 'S':
+            fields |= WHO_FIELD_SER;
+            break;
+          case 't':
+          case 'T':
+            fields |= WHO_FIELD_QTY;
+            break;
+          case 'u':
+          case 'U':
+            fields |= WHO_FIELD_UID;
+            break;
+          default:
+            break;
+        }
+      };
+    if (ch)
+      qrt = p;
+  }
+
+  if (!matchsel)
+    matchsel = WHO_FIELD_DEF;
+  if (!fields)
+    counter = 7;
+
+  if (qrt && (fields & WHO_FIELD_QTY))
+  {
+    p = qrt;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    *p = '\0';
+  }
+  else
+    qrt = 0;
+
+  /* I'd love to add also a check on the number of matches fields per time */
+  counter = (2048 / (counter + 4));
+  if (mask && (strlen(mask) > 510))
+    mask[510] = '\0';
+  move_marker();
+  commas = (mask && strchr(mask, ','));
+
+  /* First treat mask as a list of plain nicks/channels */
+  if (mask)
+  {
+    strcpy(mymask, mask);
+    for (p = 0, nick = ircd_strtok(&p, mymask, ","); nick;
+        nick = ircd_strtok(&p, 0, ","))
+    {
+      if (IsChannelName(nick) && (chptr = FindChannel(nick)))
+      {
+        isthere = (find_channel_member(sptr, chptr) != 0);
+        if (isthere || SEE_CHANNEL(sptr, chptr, bitsel))
+        {
+          struct Membership* member;
+          for (member = chptr->members; member; member = member->next_member)
+          {
+            acptr = member->user;
+            if ((bitsel & WHOSELECT_OPER) && !(IsAnOper(acptr)))
+              continue;
+            if ((acptr != sptr) && (member->status & CHFL_ZOMBIE))
+              continue;
+            if (!(isthere || (SEE_USER(sptr, acptr, bitsel))))
+              continue;
+            if (!Process(acptr))        /* This can't be moved before other checks */
+              continue;
+            if (!(isthere || (SHOW_MORE(sptr, counter))))
+              break;
+            do_who(sptr, acptr, chptr, fields, qrt);
+          }
+        }
+      }
+      else
+      {
+        if ((acptr = FindUser(nick)) &&
+            ((!(bitsel & WHOSELECT_OPER)) || IsAnOper(acptr)) &&
+            Process(acptr) && SHOW_MORE(sptr, counter))
+        {
+          do_who(sptr, acptr, 0, fields, qrt);
+        }
+      }
+    }
+  }
+
+  /* If we didn't have any comma in the mask treat it as a
+     real mask and try to match all relevant fields */
+  if (!(commas || (counter < 1)))
+  {
+    int minlen, cset;
+    static struct in_mask imask;
+    if (mask)
+    {
+      matchcomp(mymask, &minlen, &cset, mask);
+      if (matchcompIP(&imask, mask))
+        matchsel &= ~WHO_FIELD_NIP;
+      if ((minlen > NICKLEN) || !(cset & NTL_IRCNK))
+        matchsel &= ~WHO_FIELD_NIC;
+      if ((matchsel & WHO_FIELD_SER) &&
+          ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN))
+          || (!markMatchexServer(mymask, minlen))))
+        matchsel &= ~WHO_FIELD_SER;
+      if ((minlen > USERLEN) || !(cset & NTL_IRCUI))
+        matchsel &= ~WHO_FIELD_UID;
+      if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN))
+        matchsel &= ~WHO_FIELD_HOS;
+    }
+
+    /* First of all loop through the clients in common channels */
+    if ((!(counter < 1)) && matchsel) {
+      struct Membership* member;
+      struct Membership* chan;
+      for (chan = sptr->user->channel; chan; chan = chan->next_channel) {
+        chptr = chan->channel;
+        for (member = chptr->members; member; member = member->next_member)
+        {
+          acptr = member->user;
+          if (!(IsUser(acptr) && Process(acptr)))
+            continue;           /* Now Process() is at the beginning, if we fail
+                                   we'll never have to show this acptr in this query */
+          if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
+            continue;
+          if ((mask) &&
+              ((!(matchsel & WHO_FIELD_NIC))
+              || matchexec(acptr->name, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_UID))
+              || matchexec(acptr->user->username, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_SER))
+              || (!(acptr->user->server->flags & FLAGS_MAP)))
+              && ((!(matchsel & WHO_FIELD_HOS))
+              || matchexec(acptr->user->host, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_REN))
+              || matchexec(acptr->info, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_NIP))
+              || ((((acptr->ip.s_addr & imask.mask.s_addr) !=
+              imask.bits.s_addr)) || (imask.fall
+              && matchexec(ircd_ntoa((const char*) &acptr->ip), mymask, minlen)))))
+            continue;
+          if (!SHOW_MORE(sptr, counter))
+            break;
+          do_who(sptr, acptr, chptr, fields, qrt);
+        }
+      }
+    }
+    /* Loop through all clients :-\, if we still have something to match to 
+       and we can show more clients */
+    if ((!(counter < 1)) && matchsel)
+      for (acptr = me.prev; acptr; acptr = acptr->prev)
+      {
+        if (!(IsUser(acptr) && Process(acptr)))
+          continue;
+        if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
+          continue;
+        if (!(SEE_USER(sptr, acptr, bitsel)))
+          continue;
+        if ((mask) &&
+            ((!(matchsel & WHO_FIELD_NIC))
+            || matchexec(acptr->name, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_UID))
+            || matchexec(acptr->user->username, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_SER))
+            || (!(acptr->user->server->flags & FLAGS_MAP)))
+            && ((!(matchsel & WHO_FIELD_HOS))
+            || matchexec(acptr->user->host, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_REN))
+            || matchexec(acptr->info, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_NIP))
+            || ((((acptr->ip.s_addr & imask.mask.s_addr) != imask.bits.s_addr))
+            || (imask.fall
+            && matchexec(ircd_ntoa((const char*) &acptr->ip), mymask, minlen)))))
+          continue;
+        if (!SHOW_MORE(sptr, counter))
+          break;
+        do_who(sptr, acptr, 0, fields, qrt);
+      }
+  }
+
+  /* Make a clean mask suitable to be sent in the "end of" */
+  if (mask && (p = strchr(mask, ' ')))
+    *p = '\0';
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHO),
+      me.name, parv[0], BadPtr(mask) ? "*" : mask);
+
+  /* Notify the user if we decided that his query was too long */
+  if (counter < 0)
+    sendto_one(sptr, err_str(ERR_QUERYTOOLONG), me.name, parv[0], "WHO");
+
+  return 0;
+}
+
+
+#if 0
+/*
+ *  m_who
+ *
+ *  parv[0] = sender prefix
+ *  parv[1] = nickname mask list
+ *  parv[2] = additional selection flag, only 'o' for now.
+ *            and %flags to specify what fields to output
+ *            plus a ,querytype if the t flag is specified
+ *            so the final thing will be like o%tnchu,777
+ *  parv[3] = _optional_ parameter that overrides parv[1]
+ *            This can be used as "/quote who foo % :The Black Hacker
+ *            to find me, parv[3] _can_ contain spaces !.
+ */
+
+int m_who(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char *mask;           /* The mask we are looking for              */
+  char ch;                      /* Scratch char register                    */
+  struct Channel *chptr;                /* Channel to show                          */
+  struct Client *acptr;         /* Client to show                           */
+
+  int bitsel;                   /* Mask of selectors to apply               */
+  int matchsel;                 /* Wich fields the match should apply on    */
+  int counter;                  /* Query size counter,
+                                   initially used to count fields           */
+  int commas;                   /* Does our mask contain any comma ?
+                                   If so is a list..                        */
+  int fields;                   /* Mask of fields to show                   */
+  int isthere = 0;              /* When this set the user is member of chptr */
+  char *nick;                   /* Single element extracted from
+                                   the mask list                            */
+  char *p;                      /* Scratch char pointer                     */
+  char *qrt;                    /* Pointer to the query type                */
+  static char mymask[512];      /* To save the mask before corrupting it    */
+
+  /* Let's find where is our mask, and if actually contains something */
+  mask = ((parc > 1) ? parv[1] : 0);
+  if (parc > 3 && parv[3])
+    mask = parv[3];
+  if (mask && ((mask[0] == '\0') ||
+      (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*')))))
+    mask = 0;
+
+  /* Evaluate the flags now, we consider the second parameter 
+     as "matchFlags%fieldsToInclude,querytype"           */
+  bitsel = fields = counter = matchsel = 0;
+  qrt = 0;
+  if (parc > 2 && parv[2] && *parv[2])
+  {
+    p = parv[2];
+    while (((ch = *(p++))) && (ch != '%') && (ch != ','))
+      switch (ch)
+      {
+        case 'o':
+        case 'O':
+          bitsel |= WHOSELECT_OPER;
+          continue;
+        case 'x':
+        case 'X':
+          bitsel |= WHOSELECT_EXTRA;
+#ifdef WPATH
+          if (IsAnOper(sptr))
+            write_log(WPATH, "# " TIME_T_FMT " %s!%s@%s WHO %s %s\n",
+                CurrentTime, sptr->name, sptr->user->username, sptr->user->host,
+                (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]);
+#endif /* WPATH */
+          continue;
+        case 'n':
+        case 'N':
+          matchsel |= WHO_FIELD_NIC;
+          continue;
+        case 'u':
+        case 'U':
+          matchsel |= WHO_FIELD_UID;
+          continue;
+        case 'h':
+        case 'H':
+          matchsel |= WHO_FIELD_HOS;
+          continue;
+        case 'i':
+        case 'I':
+          matchsel |= WHO_FIELD_NIP;
+          continue;
+        case 's':
+        case 'S':
+          matchsel |= WHO_FIELD_SER;
+          continue;
+        case 'r':
+        case 'R':
+          matchsel |= WHO_FIELD_REN;
+          continue;
+      }
+    if (ch == '%')
+      while ((ch = *p++) && (ch != ','))
+      {
+        counter++;
+        switch (ch)
+        {
+          case 'c':
+          case 'C':
+            fields |= WHO_FIELD_CHA;
+            break;
+          case 'd':
+          case 'D':
+            fields |= WHO_FIELD_DIS;
+            break;
+          case 'f':
+          case 'F':
+            fields |= WHO_FIELD_FLA;
+            break;
+          case 'h':
+          case 'H':
+            fields |= WHO_FIELD_HOS;
+            break;
+          case 'i':
+          case 'I':
+            fields |= WHO_FIELD_NIP;
+            break;
+          case 'n':
+          case 'N':
+            fields |= WHO_FIELD_NIC;
+            break;
+          case 'r':
+          case 'R':
+            fields |= WHO_FIELD_REN;
+            break;
+          case 's':
+          case 'S':
+            fields |= WHO_FIELD_SER;
+            break;
+          case 't':
+          case 'T':
+            fields |= WHO_FIELD_QTY;
+            break;
+          case 'u':
+          case 'U':
+            fields |= WHO_FIELD_UID;
+            break;
+          default:
+            break;
+        }
+      };
+    if (ch)
+      qrt = p;
+  }
+
+  if (!matchsel)
+    matchsel = WHO_FIELD_DEF;
+  if (!fields)
+    counter = 7;
+
+  if (qrt && (fields & WHO_FIELD_QTY))
+  {
+    p = qrt;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    if (!((*p > '9') || (*p < '0')))
+      p++;
+    *p = '\0';
+  }
+  else
+    qrt = 0;
+
+  /* I'd love to add also a check on the number of matches fields per time */
+  counter = (2048 / (counter + 4));
+  if (mask && (strlen(mask) > 510))
+    mask[510] = '\0';
+  move_marker();
+  commas = (mask && strchr(mask, ','));
+
+  /* First treat mask as a list of plain nicks/channels */
+  if (mask)
+  {
+    strcpy(mymask, mask);
+    for (p = 0, nick = ircd_strtok(&p, mymask, ","); nick;
+        nick = ircd_strtok(&p, 0, ","))
+    {
+      if (IsChannelName(nick) && (chptr = FindChannel(nick)))
+      {
+        isthere = (find_channel_member(sptr, chptr) != 0);
+        if (isthere || SEE_CHANNEL(sptr, chptr, bitsel))
+        {
+          struct Membership* member;
+          for (member = chptr->members; member; member = member->next_member)
+          {
+            acptr = member->user;
+            if ((bitsel & WHOSELECT_OPER) && !(IsAnOper(acptr)))
+              continue;
+            if ((acptr != sptr) && (member->status & CHFL_ZOMBIE))
+              continue;
+            if (!(isthere || (SEE_USER(sptr, acptr, bitsel))))
+              continue;
+            if (!Process(acptr))        /* This can't be moved before other checks */
+              continue;
+            if (!(isthere || (SHOW_MORE(sptr, counter))))
+              break;
+            do_who(sptr, acptr, chptr, fields, qrt);
+          }
+        }
+      }
+      else
+      {
+        if ((acptr = FindUser(nick)) &&
+            ((!(bitsel & WHOSELECT_OPER)) || IsAnOper(acptr)) &&
+            Process(acptr) && SHOW_MORE(sptr, counter))
+        {
+          do_who(sptr, acptr, 0, fields, qrt);
+        }
+      }
+    }
+  }
+
+  /* If we didn't have any comma in the mask treat it as a
+     real mask and try to match all relevant fields */
+  if (!(commas || (counter < 1)))
+  {
+    int minlen, cset;
+    static struct in_mask imask;
+    if (mask)
+    {
+      matchcomp(mymask, &minlen, &cset, mask);
+      if (matchcompIP(&imask, mask))
+        matchsel &= ~WHO_FIELD_NIP;
+      if ((minlen > NICKLEN) || !(cset & NTL_IRCNK))
+        matchsel &= ~WHO_FIELD_NIC;
+      if ((matchsel & WHO_FIELD_SER) &&
+          ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN))
+          || (!markMatchexServer(mymask, minlen))))
+        matchsel &= ~WHO_FIELD_SER;
+      if ((minlen > USERLEN) || !(cset & NTL_IRCUI))
+        matchsel &= ~WHO_FIELD_UID;
+      if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN))
+        matchsel &= ~WHO_FIELD_HOS;
+    }
+
+    /* First of all loop through the clients in common channels */
+    if ((!(counter < 1)) && matchsel) {
+      struct Membership* member;
+      struct Membership* chan;
+      for (chan = sptr->user->channel; chan; chan = chan->next_channel) {
+        chptr = chan->channel;
+        for (member = chptr->members; member; member = member->next_member)
+        {
+          acptr = member->user;
+          if (!(IsUser(acptr) && Process(acptr)))
+            continue;           /* Now Process() is at the beginning, if we fail
+                                   we'll never have to show this acptr in this query */
+          if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
+            continue;
+          if ((mask) &&
+              ((!(matchsel & WHO_FIELD_NIC))
+              || matchexec(acptr->name, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_UID))
+              || matchexec(acptr->user->username, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_SER))
+              || (!(acptr->user->server->flags & FLAGS_MAP)))
+              && ((!(matchsel & WHO_FIELD_HOS))
+              || matchexec(acptr->user->host, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_REN))
+              || matchexec(acptr->info, mymask, minlen))
+              && ((!(matchsel & WHO_FIELD_NIP))
+              || ((((acptr->ip.s_addr & imask.mask.s_addr) !=
+              imask.bits.s_addr)) || (imask.fall
+              && matchexec(inet_ntoa(acptr->ip), mymask, minlen)))))
+            continue;
+          if (!SHOW_MORE(sptr, counter))
+            break;
+          do_who(sptr, acptr, chptr, fields, qrt);
+        }
+      }
+    }
+    /* Loop through all clients :-\, if we still have something to match to 
+       and we can show more clients */
+    if ((!(counter < 1)) && matchsel)
+      for (acptr = me.prev; acptr; acptr = acptr->prev)
+      {
+        if (!(IsUser(acptr) && Process(acptr)))
+          continue;
+        if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
+          continue;
+        if (!(SEE_USER(sptr, acptr, bitsel)))
+          continue;
+        if ((mask) &&
+            ((!(matchsel & WHO_FIELD_NIC))
+            || matchexec(acptr->name, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_UID))
+            || matchexec(acptr->user->username, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_SER))
+            || (!(acptr->user->server->flags & FLAGS_MAP)))
+            && ((!(matchsel & WHO_FIELD_HOS))
+            || matchexec(acptr->user->host, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_REN))
+            || matchexec(acptr->info, mymask, minlen))
+            && ((!(matchsel & WHO_FIELD_NIP))
+            || ((((acptr->ip.s_addr & imask.mask.s_addr) != imask.bits.s_addr))
+            || (imask.fall
+            && matchexec(inet_ntoa(acptr->ip), mymask, minlen)))))
+          continue;
+        if (!SHOW_MORE(sptr, counter))
+          break;
+        do_who(sptr, acptr, 0, fields, qrt);
+      }
+  }
+
+  /* Make a clean mask suitable to be sent in the "end of" */
+  if (mask && (p = strchr(mask, ' ')))
+    *p = '\0';
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHO),
+      me.name, parv[0], BadPtr(mask) ? "*" : mask);
+
+  /* Notify the user if we decided that his query was too long */
+  if (counter < 0)
+    sendto_one(sptr, err_str(ERR_QUERYTOOLONG), me.name, parv[0], "WHO");
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_whois.c b/ircd/m_whois.c
new file mode 100644 (file)
index 0000000..f99df5c
--- /dev/null
@@ -0,0 +1,966 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_whois.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "send.h"
+#include "whocmds.h"
+
+#include <assert.h>
+#include <string.h>
+
+/*
+ * m_whois - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ *
+ * or
+ *
+ * parv[1] = target server
+ * parv[2] = nickname masklist
+ */
+int m_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct User*    user;
+  struct Client*  acptr;
+  struct Client*  a2cptr;
+  struct Channel* chptr;
+  char*           nick;
+  char*           tmp;
+  char*           name;
+  char*           p = 0;
+  int             found;
+  int             len;
+  int             mlen;
+  int             total;
+  static char     buf[512];
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    struct Client *acptr;
+    /* For convenience: Accept a nickname as first parameter, by replacing
+       it with the correct servername - as is needed by hunt_server() */
+    if (MyUser(sptr) && (acptr = FindUser(parv[1])))
+      parv[1] = acptr->user->server->name;
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    parv[1] = parv[2];
+  }
+
+  total = 0;
+  for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+  {
+    int invis, showperson, member, wilds;
+
+    found = 0;
+    collapse(nick);
+    wilds = (strchr(nick, '?') || strchr(nick, '*'));
+    /* Do a hash lookup if the nick does not contain wilds */
+    if (wilds)
+    {
+      /*
+       * We're no longer allowing remote users to generate requests with wildcards.
+       */
+      if (!MyConnect(sptr))
+        continue;
+      for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
+          acptr = acptr->next)
+      {
+        if (!IsRegistered(acptr) || IsServer(acptr))
+          continue;
+        /*
+         * I'm always last :-) and acptr->next == 0!!
+         */
+        if (IsMe(acptr))
+          break;
+        /*
+         * '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;
+         */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+
+        invis = acptr != sptr && IsInvisible(acptr);
+        member = (user && user->channel) ? 1 : 0;
+        showperson = (wilds && !invis && !member) || !wilds;
+        if (user) {
+          struct Membership* chan;
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            member = find_channel_member(sptr, chptr) ? 1 : 0;
+            if (invis && !member)
+              continue;
+            if (IsZombie(chan))
+              continue;
+            if (member || (!invis && PubChannel(chptr)))
+            {
+              showperson = 1;
+              break;
+            }
+            if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
+              showperson = 1;
+          }
+        }
+        if (!showperson)
+          continue;
+
+        if (user)
+        {
+          a2cptr = user->server;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, user->username, user->host, acptr->info);
+        }
+        else
+        {
+          a2cptr = &me;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, "<unknown>", "<unknown>", "<unknown>");
+        }
+
+        found = 1;
+
+exact_match:
+        if (user && !IsChannelService(acptr))
+        {
+          struct Membership* chan;
+          mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
+          len = 0;
+          *buf = '\0';
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            if (ShowChannel(sptr, chptr) &&
+                (acptr == sptr || !IsZombie(chan)))
+            {
+              if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
+              {
+                sendto_one(sptr, ":%s %d %s %s :%s",
+                    me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
+                *buf = '\0';
+                len = 0;
+              }
+              if (IsDeaf(acptr))
+                *(buf + len++) = '-';
+              if (is_chan_op(acptr, chptr))
+                *(buf + len++) = '@';
+              else if (has_voice(acptr, chptr))
+                *(buf + len++) = '+';
+              else if (IsZombie(chan))
+                *(buf + len++) = '!';
+              if (len)
+                *(buf + len) = '\0';
+              strcpy(buf + len, chptr->chname);
+              len += strlen(chptr->chname);
+              strcat(buf + len, " ");
+              len++;
+            }
+          }
+          if (buf[0] != '\0')
+            sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
+                me.name, parv[0], name, buf);
+        }
+
+        sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
+            parv[0], name, a2cptr->name, a2cptr->info);
+
+        if (user)
+        {
+          if (user->away)
+            sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
+                parv[0], name, user->away);
+
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
+                me.name, parv[0], name);
+
+          if (MyConnect(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
+                parv[0], name, CurrentTime - user->last, acptr->firsttime);
+        }
+        if (found == 2 || total++ >= MAX_WHOIS_LINES)
+          break;
+      }
+    }
+    else
+    {
+      /* No wildcards */
+      if ((acptr = FindUser(nick)))
+      {
+        found = 2;              /* Make sure we exit the loop after passing it once */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+        a2cptr = user->server;
+        sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+            parv[0], name, user->username, user->host, acptr->info);
+        goto exact_match;
+      }
+    }
+    if (!found)
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+    if (p)
+      p[-1] = ',';
+    if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
+
+  return 0;
+}
+
+/*
+ * ms_whois - server message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ *
+ * or
+ *
+ * parv[1] = target server
+ * parv[2] = nickname masklist
+ */
+int ms_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct User*    user;
+  struct Client*  acptr;
+  struct Client*  a2cptr;
+  struct Channel* chptr;
+  char*           nick;
+  char*           tmp;
+  char*           name;
+  char*           p = 0;
+  int             found;
+  int             len;
+  int             mlen;
+  int             total;
+  static char     buf[512];
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    struct Client *acptr;
+    /* For convenience: Accept a nickname as first parameter, by replacing
+       it with the correct servername - as is needed by hunt_server() */
+    if (MyUser(sptr) && (acptr = FindUser(parv[1])))
+      parv[1] = acptr->user->server->name;
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    parv[1] = parv[2];
+  }
+
+  total = 0;
+  for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+  {
+    int invis, showperson, member, wilds;
+
+    found = 0;
+    collapse(nick);
+    wilds = (strchr(nick, '?') || strchr(nick, '*'));
+    /* Do a hash lookup if the nick does not contain wilds */
+    if (wilds)
+    {
+      /*
+       * We're no longer allowing remote users to generate requests with wildcards.
+       */
+      if (!MyConnect(sptr))
+        continue;
+      for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
+          acptr = acptr->next)
+      {
+        if (!IsRegistered(acptr) || IsServer(acptr))
+          continue;
+        /*
+         * I'm always last :-) and acptr->next == 0!!
+         */
+        if (IsMe(acptr))
+          break;
+        /*
+         * '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;
+         */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+
+        invis = acptr != sptr && IsInvisible(acptr);
+        member = (user && user->channel) ? 1 : 0;
+        showperson = (wilds && !invis && !member) || !wilds;
+        if (user) {
+          struct Membership* chan;
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            member = find_channel_member(sptr, chptr) ? 1 : 0;
+            if (invis && !member)
+              continue;
+            if (IsZombie(chan))
+              continue;
+            if (member || (!invis && PubChannel(chptr)))
+            {
+              showperson = 1;
+              break;
+            }
+            if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
+              showperson = 1;
+          }
+        }
+        if (!showperson)
+          continue;
+
+        if (user)
+        {
+          a2cptr = user->server;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, user->username, user->host, acptr->info);
+        }
+        else
+        {
+          a2cptr = &me;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, "<unknown>", "<unknown>", "<unknown>");
+        }
+
+        found = 1;
+
+exact_match:
+        if (user && !IsChannelService(acptr))
+        {
+          struct Membership* chan;
+          mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
+          len = 0;
+          *buf = '\0';
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            if (ShowChannel(sptr, chptr) &&
+                (acptr == sptr || !IsZombie(chan)))
+            {
+              if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
+              {
+                sendto_one(sptr, ":%s %d %s %s :%s",
+                    me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
+                *buf = '\0';
+                len = 0;
+              }
+              if (IsDeaf(acptr))
+                *(buf + len++) = '-';
+              if (is_chan_op(acptr, chptr))
+                *(buf + len++) = '@';
+              else if (has_voice(acptr, chptr))
+                *(buf + len++) = '+';
+              else if (IsZombie(chan))
+                *(buf + len++) = '!';
+              if (len)
+                *(buf + len) = '\0';
+              strcpy(buf + len, chptr->chname);
+              len += strlen(chptr->chname);
+              strcat(buf + len, " ");
+              len++;
+            }
+          }
+          if (buf[0] != '\0')
+            sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
+                me.name, parv[0], name, buf);
+        }
+
+        sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
+            parv[0], name, a2cptr->name, a2cptr->info);
+
+        if (user)
+        {
+          if (user->away)
+            sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
+                parv[0], name, user->away);
+
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
+                me.name, parv[0], name);
+
+          if (MyConnect(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
+                parv[0], name, CurrentTime - user->last, acptr->firsttime);
+        }
+        if (found == 2 || total++ >= MAX_WHOIS_LINES)
+          break;
+      }
+    }
+    else
+    {
+      /* No wildcards */
+      if ((acptr = FindUser(nick)))
+      {
+        found = 2;              /* Make sure we exit the loop after passing it once */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+        a2cptr = user->server;
+        sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+            parv[0], name, user->username, user->host, acptr->info);
+        goto exact_match;
+      }
+    }
+    if (!found)
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+    if (p)
+      p[-1] = ',';
+    if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
+
+  return 0;
+}
+
+/*
+ * mo_whois - oper message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ *
+ * or
+ *
+ * parv[1] = target server
+ * parv[2] = nickname masklist
+ */
+int mo_whois(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct User*    user;
+  struct Client*  acptr;
+  struct Client*  a2cptr;
+  struct Channel* chptr;
+  char*           nick;
+  char*           tmp;
+  char*           name;
+  char*           p = 0;
+  int             found;
+  int             len;
+  int             mlen;
+  int             total;
+  static char     buf[512];
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    struct Client *acptr;
+    /* For convenience: Accept a nickname as first parameter, by replacing
+       it with the correct servername - as is needed by hunt_server() */
+    if (MyUser(sptr) && (acptr = FindUser(parv[1])))
+      parv[1] = acptr->user->server->name;
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    parv[1] = parv[2];
+  }
+
+  total = 0;
+  for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+  {
+    int invis, showperson, member, wilds;
+
+    found = 0;
+    collapse(nick);
+    wilds = (strchr(nick, '?') || strchr(nick, '*'));
+    /* Do a hash lookup if the nick does not contain wilds */
+    if (wilds)
+    {
+      /*
+       * We're no longer allowing remote users to generate requests with wildcards.
+       */
+      if (!MyConnect(sptr))
+        continue;
+      for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
+          acptr = acptr->next)
+      {
+        if (!IsRegistered(acptr) || IsServer(acptr))
+          continue;
+        /*
+         * I'm always last :-) and acptr->next == 0!!
+         */
+        if (IsMe(acptr))
+          break;
+        /*
+         * '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;
+         */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+
+        invis = acptr != sptr && IsInvisible(acptr);
+        member = (user && user->channel) ? 1 : 0;
+        showperson = (wilds && !invis && !member) || !wilds;
+        if (user) {
+          struct Membership* chan;
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            member = find_channel_member(sptr, chptr) ? 1 : 0;
+            if (invis && !member)
+              continue;
+            if (IsZombie(chan))
+              continue;
+            if (member || (!invis && PubChannel(chptr)))
+            {
+              showperson = 1;
+              break;
+            }
+            if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
+              showperson = 1;
+          }
+        }
+        if (!showperson)
+          continue;
+
+        if (user)
+        {
+          a2cptr = user->server;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, user->username, user->host, acptr->info);
+        }
+        else
+        {
+          a2cptr = &me;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, "<unknown>", "<unknown>", "<unknown>");
+        }
+
+        found = 1;
+
+exact_match:
+        if (user && !IsChannelService(acptr))
+        {
+          struct Membership* chan;
+          mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
+          len = 0;
+          *buf = '\0';
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            if (ShowChannel(sptr, chptr) &&
+                (acptr == sptr || !IsZombie(chan)))
+            {
+              if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
+              {
+                sendto_one(sptr, ":%s %d %s %s :%s",
+                    me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
+                *buf = '\0';
+                len = 0;
+              }
+              if (IsDeaf(acptr))
+                *(buf + len++) = '-';
+              if (is_chan_op(acptr, chptr))
+                *(buf + len++) = '@';
+              else if (has_voice(acptr, chptr))
+                *(buf + len++) = '+';
+              else if (IsZombie(chan))
+                *(buf + len++) = '!';
+              if (len)
+                *(buf + len) = '\0';
+              strcpy(buf + len, chptr->chname);
+              len += strlen(chptr->chname);
+              strcat(buf + len, " ");
+              len++;
+            }
+          }
+          if (buf[0] != '\0')
+            sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
+                me.name, parv[0], name, buf);
+        }
+
+        sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
+            parv[0], name, a2cptr->name, a2cptr->info);
+
+        if (user)
+        {
+          if (user->away)
+            sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
+                parv[0], name, user->away);
+
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
+                me.name, parv[0], name);
+
+          if (MyConnect(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
+                parv[0], name, CurrentTime - user->last, acptr->firsttime);
+        }
+        if (found == 2 || total++ >= MAX_WHOIS_LINES)
+          break;
+      }
+    }
+    else
+    {
+      /* No wildcards */
+      if ((acptr = FindUser(nick)))
+      {
+        found = 2;              /* Make sure we exit the loop after passing it once */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+        a2cptr = user->server;
+        sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+            parv[0], name, user->username, user->host, acptr->info);
+        goto exact_match;
+      }
+    }
+    if (!found)
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+    if (p)
+      p[-1] = ',';
+    if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
+
+  return 0;
+}
+
+  
+
+#if 0
+/*
+ * m_whois
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname masklist
+ *
+ * or
+ *
+ * parv[1] = target server
+ * parv[2] = nickname masklist
+ */
+int m_whois(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct User*    user;
+  struct Client*  acptr;
+  struct Client*  a2cptr;
+  struct Channel* chptr;
+  char*           nick;
+  char*           tmp;
+  char*           name;
+  char*           p = 0;
+  int             found;
+  int             len;
+  int             mlen;
+  int             total;
+  static char     buf[512];
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+
+  if (parc > 2)
+  {
+    struct Client *acptr;
+    /* For convenience: Accept a nickname as first parameter, by replacing
+       it with the correct servername - as is needed by hunt_server() */
+    if (MyUser(sptr) && (acptr = FindUser(parv[1])))
+      parv[1] = acptr->user->server->name;
+    if (hunt_server(0, cptr, sptr, "%s%s " TOK_WHOIS " %s :%s", 1, parc, parv) !=
+        HUNTED_ISME)
+      return 0;
+    parv[1] = parv[2];
+  }
+
+  total = 0;
+  for (tmp = parv[1]; (nick = ircd_strtok(&p, tmp, ",")); tmp = 0)
+  {
+    int invis, showperson, member, wilds;
+
+    found = 0;
+    collapse(nick);
+    wilds = (strchr(nick, '?') || strchr(nick, '*'));
+    /* Do a hash lookup if the nick does not contain wilds */
+    if (wilds)
+    {
+      /*
+       * We're no longer allowing remote users to generate requests with wildcards.
+       */
+      if (!MyConnect(sptr))
+        continue;
+      for (acptr = GlobalClientList; (acptr = next_client(acptr, nick));
+          acptr = acptr->next)
+      {
+        if (!IsRegistered(acptr) || IsServer(acptr))
+          continue;
+        /*
+         * I'm always last :-) and acptr->next == NULL!!
+         */
+        if (IsMe(acptr))
+          break;
+        /*
+         * '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;
+         */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+
+        invis = acptr != sptr && IsInvisible(acptr);
+        member = (user && user->channel) ? 1 : 0;
+        showperson = (wilds && !invis && !member) || !wilds;
+        if (user) {
+          struct Membership* chan;
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            member = find_channel_member(sptr, chptr) ? 1 : 0;
+            if (invis && !member)
+              continue;
+            if (IsZombie(chan))
+              continue;
+            if (member || (!invis && PubChannel(chptr)))
+            {
+              showperson = 1;
+              break;
+            }
+            if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
+              showperson = 1;
+          }
+        }
+        if (!showperson)
+          continue;
+
+        if (user)
+        {
+          a2cptr = user->server;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, user->username, user->host, acptr->info);
+        }
+        else
+        {
+          a2cptr = &me;
+          sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+              parv[0], name, "<unknown>", "<unknown>", "<unknown>");
+        }
+
+        found = 1;
+
+exact_match:
+        if (user && !IsChannelService(acptr))
+        {
+          struct Membership* chan;
+          mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
+          len = 0;
+          *buf = '\0';
+          for (chan = user->channel; chan; chan = chan->next_channel)
+          {
+            chptr = chan->channel;
+            if (ShowChannel(sptr, chptr) &&
+                (acptr == sptr || !IsZombie(chan)))
+            {
+              if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
+              {
+                sendto_one(sptr, ":%s %d %s %s :%s",
+                    me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
+                *buf = '\0';
+                len = 0;
+              }
+              if (IsDeaf(acptr))
+                *(buf + len++) = '-';
+              if (is_chan_op(acptr, chptr))
+                *(buf + len++) = '@';
+              else if (has_voice(acptr, chptr))
+                *(buf + len++) = '+';
+              else if (IsZombie(chan))
+                *(buf + len++) = '!';
+              if (len)
+                *(buf + len) = '\0';
+              strcpy(buf + len, chptr->chname);
+              len += strlen(chptr->chname);
+              strcat(buf + len, " ");
+              len++;
+            }
+          }
+          if (buf[0] != '\0')
+            sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
+                me.name, parv[0], name, buf);
+        }
+
+        sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
+            parv[0], name, a2cptr->name, a2cptr->info);
+
+        if (user)
+        {
+          if (user->away)
+            sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
+                parv[0], name, user->away);
+
+          if (IsAnOper(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
+                me.name, parv[0], name);
+
+          if (MyConnect(acptr))
+            sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
+                parv[0], name, CurrentTime - user->last, acptr->firsttime);
+        }
+        if (found == 2 || total++ >= MAX_WHOIS_LINES)
+          break;
+      }
+    }
+    else
+    {
+      /* No wildcards */
+      if ((acptr = FindUser(nick)))
+      {
+        found = 2;              /* Make sure we exit the loop after passing it once */
+        user = acptr->user;
+        name = (!*acptr->name) ? "?" : acptr->name;
+        a2cptr = user->server;
+        sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+            parv[0], name, user->username, user->host, acptr->info);
+        goto exact_match;
+      }
+    }
+    if (!found)
+      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
+    if (p)
+      p[-1] = ',';
+    if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
+      break;
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
+
+  return 0;
+}
+#endif /* 0 */
+
diff --git a/ircd/m_whowas.c b/ircd/m_whowas.c
new file mode 100644 (file)
index 0000000..47907c2
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * IRC - Internet Relay Chat, ircd/m_whowas.c
+ * Copyright (C) 1990 Jarkko Oikarinen and
+ *                    University of Oulu, Computing Center
+ *
+ * See file AUTHORS in IRC package for additional names of
+ * the programmers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *    cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *            structure (with an open socket connected!). This
+ *            identifies the physical socket where the message
+ *            originated (or which caused the m_function to be
+ *            executed--some m_functions may call others...).
+ *
+ *    sptr    is the source of the message, defined by the
+ *            prefix part of the message if present. If not
+ *            or prefix not found, then sptr==cptr.
+ *
+ *            (!IsServer(cptr)) => (cptr == sptr), because
+ *            prefixes are taken *only* from servers...
+ *
+ *            (IsServer(cptr))
+ *                    (sptr == cptr) => the message didn't
+ *                    have the prefix.
+ *
+ *                    (sptr != cptr && IsServer(sptr) means
+ *                    the prefix specified servername. (?)
+ *
+ *                    (sptr != cptr && !IsServer(sptr) means
+ *                    that message originated from a remote
+ *                    user (not local).
+ *
+ *            combining
+ *
+ *            (!IsServer(sptr)) means that, sptr can safely
+ *            taken as defining the target structure of the
+ *            message in this server.
+ *
+ *    *Always* true (if 'parse' and others are working correct):
+ *
+ *    1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *            *cannot* be a local connection, unless it's
+ *            actually cptr!). [MyConnect(x) should probably
+ *            be defined as (x == x->from) --msa ]
+ *
+ *    parc    number of variable parameter strings (if zero,
+ *            parv is allowed to be NULL)
+ *
+ *    parv    a NULL terminated list of parameter pointers,
+ *
+ *                    parv[0], sender (prefix string), if not present
+ *                            this points to an empty string.
+ *                    parv[1]...parv[parc-1]
+ *                            pointers to additional parameters
+ *                    parv[parc] == NULL, *always*
+ *
+ *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                    non-NULL pointers.
+ */
+#if 0
+/*
+ * No need to include handlers.h here the signatures must match
+ * and we don't need to force a rebuild of all the handlers everytime
+ * we add a new one to the list. --Bleep
+ */
+#include "handlers.h"
+#endif /* 0 */
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_user.h"
+#include "s_misc.h"
+#include "send.h"
+#include "whowas.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+/*
+ * m_whowas - generic message handler
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname queried
+ * parv[2] = maximum returned items (optional, default is unlimitted)
+ * parv[3] = remote server target (Opers only, max returned items 20)
+ */
+int m_whowas(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
+{
+  struct Whowas *temp;
+  int cur = 0;
+  int max = -1, found = 0;
+  char *p, *nick, *s;
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+  if (parc > 2)
+    max = atoi(parv[2]);
+  if (parc > 3)
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_WHOWAS " %s %s :%s", 3, parc, parv))
+      return 0;
+
+  parv[1] = canonize(parv[1]);
+  if (!MyConnect(sptr) && (max > 20))
+    max = 20;                   /* Set max replies at 20 */
+  for (s = parv[1]; (nick = ircd_strtok(&p, s, ",")); s = 0)
+  {
+    /* Search through bucket, finding all nicknames that match */
+    found = 0;
+    for (temp = whowashash[hash_whowas_name(nick)]; temp; temp = temp->hnext)
+    {
+      if (0 == ircd_strcmp(nick, temp->name))
+      {
+        sendto_one(sptr, rpl_str(RPL_WHOWASUSER),
+            me.name, parv[0], temp->name, temp->username,
+            temp->hostname, temp->realname);
+        sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0],
+            temp->name, temp->servername, myctime(temp->logoff));
+        if (temp->away)
+          sendto_one(sptr, rpl_str(RPL_AWAY),
+              me.name, parv[0], temp->name, temp->away);
+        cur++;
+        found++;
+      }
+      if (max >= 0 && cur >= max)
+        break;
+    }
+    if (!found)
+      sendto_one(sptr, err_str(ERR_WASNOSUCHNICK), me.name, parv[0], nick);
+    /* To keep parv[1] intact for ENDOFWHOWAS */
+    if (p)
+      p[-1] = ',';
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]);
+  return 0;
+}
+
+
+#if 0
+/*
+ * m_whowas
+ *
+ * parv[0] = sender prefix
+ * parv[1] = nickname queried
+ * parv[2] = maximum returned items (optional, default is unlimitted)
+ * parv[3] = remote server target (Opers only, max returned items 20)
+ */
+int m_whowas(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct Whowas *temp;
+  int cur = 0;
+  int max = -1, found = 0;
+  char *p, *nick, *s;
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+    return 0;
+  }
+  if (parc > 2)
+    max = atoi(parv[2]);
+  if (parc > 3)
+    if (hunt_server(1, cptr, sptr, "%s%s " TOK_WHOWAS " %s %s :%s", 3, parc, parv))
+      return 0;
+
+  parv[1] = canonize(parv[1]);
+  if (!MyConnect(sptr) && (max > 20))
+    max = 20;                   /* Set max replies at 20 */
+  for (s = parv[1]; (nick = ircd_strtok(&p, s, ",")); s = 0)
+  {
+    /* Search through bucket, finding all nicknames that match */
+    found = 0;
+    for (temp = whowashash[hash_whowas_name(nick)]; temp; temp = temp->hnext)
+    {
+      if (0 == ircd_strcmp(nick, temp->name))
+      {
+        sendto_one(sptr, rpl_str(RPL_WHOWASUSER),
+            me.name, parv[0], temp->name, temp->username,
+            temp->hostname, temp->realname);
+        sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0],
+            temp->name, temp->servername, myctime(temp->logoff));
+        if (temp->away)
+          sendto_one(sptr, rpl_str(RPL_AWAY),
+              me.name, parv[0], temp->name, temp->away);
+        cur++;
+        found++;
+      }
+      if (max >= 0 && cur >= max)
+        break;
+    }
+    if (!found)
+      sendto_one(sptr, err_str(ERR_WASNOSUCHNICK), me.name, parv[0], nick);
+    /* To keep parv[1] intact for ENDOFWHOWAS */
+    if (p)
+      p[-1] = ',';
+  }
+  sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]);
+  return 0;
+}
+#endif /* 0 */
index 3be7411620bcbca61d357b6bc393fa09fcf2b013..09396fb315e6c91258dfd42c63dd7cb9fd8dc4fa 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
+#include "map.h"
+#include "client.h"
+#include "ircd.h"
+#include "list.h"
+#include "match.h"
 #include "numeric.h"
+#include "numnicks.h"
+#include "querycmds.h"
 #include "send.h"
-#include "match.h"
-#include "list.h"
-#include "s_err.h"
-#include "ircd.h"
-#include "s_bsd.h"
-#include "s_misc.h"
-#include "map.h"
+#include "struct.h"
 
-RCSTAG_CC("$Id$");
 
-static void dump_map(aClient *cptr, aClient *server, char *mask,
-    int prompt_length)
+void dump_map(struct Client *cptr, struct Client *server, char *mask, int prompt_length)
 {
   static char prompt[64];
-  register Dlink *lp;
-  register char *p = &prompt[prompt_length];
-  register int cnt = 0;
+  struct DLink *lp;
+  char *p = &prompt[prompt_length];
+  int cnt = 0;
 
   *p = '\0';
   if (prompt_length > 60)
     sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name,
-       prompt, server->name);
+        prompt, server->name);
   else
     sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name,
-       prompt, server->name);
+        prompt, NumServ(server), server->name, 
+        server->serv->lag>0 ? server->serv->lag : 0,
+        (server == &me) ? UserStats.local_clients : server->serv->clients);
   if (prompt_length > 0)
   {
     p[-1] = ' ';
@@ -76,13 +75,14 @@ static void dump_map(aClient *cptr, aClient *server, char *mask,
     p[-1] = '-';
 }
 
+#if 0
 /*
  * m_map  -- by Run
  *
  * parv[0] = sender prefix
  * parv[1] = server mask
  */
-int m_map(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
+int m_map(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
 {
   if (parc < 2)
     parv[1] = "*";
@@ -92,3 +92,5 @@ int m_map(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
 
   return 0;
 }
+#endif /* 0 */
+
index f66f2b454d1d8af9e0bab8ec797dd5d353cf8247..06993daf14482aba14305b534a9ad86e120fe118 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
-#include "common.h"
 #include "match.h"
-#include "ircd.h"
-
-RCSTAG_CC("$Id$");
-
+#include "ircd_chattr.h"
 /*
  * mmatch()
  *
  * Written by Run (carlo@runaway.xs4all.nl), 25-10-96
- */
-
-/*
+ *
+ *
  * From: Carlo Wood <carlo@runaway.xs4all.nl>
  * Message-Id: <199609021026.MAA02393@runaway.xs4all.nl>
  * Subject: [C-Com] Analysis for `mmatch' (was: gline4 problem)
@@ -50,8 +43,8 @@ RCSTAG_CC("$Id$");
 
 int mmatch(const char *old_mask, const char *new_mask)
 {
-  register const char *m = old_mask;
-  register const char *n = new_mask;
+  const char *m = old_mask;
+  const char *n = new_mask;
   const char *ma = m;
   const char *na = n;
   int wild = 0;
@@ -62,7 +55,7 @@ int mmatch(const char *old_mask, const char *new_mask)
     if (*m == '*')
     {
       while (*m == '*')
-       m++;
+        m++;
       wild = 1;
       ma = m;
       na = n;
@@ -71,25 +64,25 @@ int mmatch(const char *old_mask, const char *new_mask)
     if (!*m)
     {
       if (!*n)
-       return 0;
+        return 0;
       for (m--; (m > old_mask) && (*m == '?'); m--)
-       ;
+        ;
       if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
-       return 0;
+        return 0;
       if (!wild)
-       return 1;
+        return 1;
       m = ma;
 
       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
-       ++na;
+        ++na;
 
       n = ++na;
     }
     else if (!*n)
     {
       while (*m == '*')
-       m++;
+        m++;
       return (*m != 0);
     }
     if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
@@ -116,7 +109,7 @@ int mmatch(const char *old_mask, const char *new_mask)
  *    *               any             (*m == '*' && !mq) ||
  *    ?               any except '*'  (*m == '?' && !mq && (*n != '*' || nq)) ||
  * any except * or ?  same as m       (!((*m == '*' || *m == '?') && !mq) &&
- *                                      toLower(*m) == toLower(*n) &&
+ *                                      ToLower(*m) == ToLower(*n) &&
  *                                        !((mq && !nq) || (!mq && nq)))
  *
  * Here `any' also includes \* and \? !
@@ -126,23 +119,23 @@ int mmatch(const char *old_mask, const char *new_mask)
  *  cases upfront (which took 2 hours!)).
  */
     if ((*m == '*' && !mq) ||
-       ((!mq || nq) && toLower(*m) == toLower(*n)) ||
-       (*m == '?' && !mq && (*n != '*' || nq)))
+        ((!mq || nq) && ToLower(*m) == ToLower(*n)) ||
+        (*m == '?' && !mq && (*n != '*' || nq)))
     {
       if (*m)
-       m++;
+        m++;
       if (*n)
-       n++;
+        n++;
     }
     else
     {
       if (!wild)
-       return 1;
+        return 1;
       m = ma;
 
       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
-       ++na;
+        ++na;
 
       n = ++na;
     }
@@ -169,53 +162,53 @@ int mmatch(const char *old_mask, const char *new_mask)
 
 int match(const char *mask, const char *string)
 {
-  register const char *m = mask, *s = string;
-  register char ch;
-  const char *bm, *bs;         /* Will be reg anyway on a decent CPU/compiler */
+  const char *m = mask, *s = string;
+  char ch;
+  const char *bm, *bs;          /* Will be reg anyway on a decent CPU/compiler */
 
   /* Process the "head" of the mask, if any */
   while ((ch = *m++) && (ch != '*'))
     switch (ch)
     {
       case '\\':
-       if (*m == '?' || *m == '*')
-         ch = *m++;
+        if (*m == '?' || *m == '*')
+          ch = *m++;
       default:
-       if (toLower(*s) != toLower(ch))
-         return 1;
+        if (ToLower(*s) != ToLower(ch))
+          return 1;
       case '?':
-       if (!*s++)
-         return 1;
+        if (!*s++)
+          return 1;
     };
   if (!ch)
     return *s;
 
   /* We got a star: quickly find if/where we match the next char */
 got_star:
-  bm = m;                      /* Next try rollback here */
+  bm = m;                       /* Next try rollback here */
   while ((ch = *m++))
     switch (ch)
     {
       case '?':
-       if (!*s++)
-         return 1;
+        if (!*s++)
+          return 1;
       case '*':
-       bm = m;
-       continue;               /* while */
+        bm = m;
+        continue;               /* while */
       case '\\':
-       if (*m == '?' || *m == '*')
-         ch = *m++;
+        if (*m == '?' || *m == '*')
+          ch = *m++;
       default:
-       goto break_while;       /* C is structured ? */
+        goto break_while;       /* C is structured ? */
     };
 break_while:
   if (!ch)
-    return 0;                  /* mask ends with '*', we got it */
-  ch = toLower(ch);
-  while (toLower(*s++) != ch)
+    return 0;                   /* mask ends with '*', we got it */
+  ch = ToLower(ch);
+  while (ToLower(*s++) != ch)
     if (!*s)
       return 1;
-  bs = s;                      /* Next try start from here */
+  bs = s;                       /* Next try start from here */
 
   /* Check the rest of the "chunk" */
   while ((ch = *m++))
@@ -223,20 +216,20 @@ break_while:
     switch (ch)
     {
       case '*':
-       goto got_star;
+        goto got_star;
       case '\\':
-       if (*m == '?' || *m == '*')
-         ch = *m++;
+        if (*m == '?' || *m == '*')
+          ch = *m++;
       default:
-       if (toLower(*s) != toLower(ch))
-       {
-         m = bm;
-         s = bs;
-         goto got_star;
-       };
+        if (ToLower(*s) != ToLower(ch))
+        {
+          m = bm;
+          s = bs;
+          goto got_star;
+        };
       case '?':
-       if (!*s++)
-         return 1;
+        if (!*s++)
+          return 1;
     };
   };
   if (*s)
@@ -261,9 +254,9 @@ break_while:
 
 char *collapse(char *mask)
 {
-  register int star = 0;
-  register char *m = mask;
-  register char *b;
+  int star = 0;
+  char *m = mask;
+  char *b;
 
   if (m)
   {
@@ -271,30 +264,30 @@ char *collapse(char *mask)
     {
       if ((*m == '*') && ((m[1] == '*') || (m[1] == '?')))
       {
-       b = m;
-       do
-       {
-         if (*m == '*')
-           star = 1;
-         else
-         {
-           if (star && (*m != '?'))
-           {
-             *b++ = '*';
-             star = 0;
-           };
-           *b++ = *m;
-           if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
-             *b++ = *++m;
-         };
-       }
-       while (*m++);
-       break;
+        b = m;
+        do
+        {
+          if (*m == '*')
+            star = 1;
+          else
+          {
+            if (star && (*m != '?'))
+            {
+              *b++ = '*';
+              star = 0;
+            };
+            *b++ = *m;
+            if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+              *b++ = *++m;
+          };
+        }
+        while (*m++);
+        break;
       }
       else
       {
-       if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
-         m++;
+        if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
+          m++;
       };
     }
     while (*m++);
@@ -386,8 +379,8 @@ int matchcomp(char *cmask, int *minlen, int *charset, const char *mask)
 {
   const char *m = mask;
   char *b = cmask;
-  char *fs = NULL;
-  char *ls = NULL;
+  char *fs = 0;
+  char *ls = 0;
   char *x1, *x2;
   int l1, l2, lmin, loop, sign;
   int star = 0;
@@ -400,29 +393,30 @@ int matchcomp(char *cmask, int *minlen, int *charset, const char *mask)
     while ((ch = *m++))
       switch (ch)
       {
-       case '*':
-         star = 1;
-         break;
-       case '?':
-         cnt++;
-         *b++ = 'A';
-         chset2 &= ~NTL_LOWER;
-         break;
-       case '\\':
-         if ((*m == '?') || (*m == '*'))
-           ch = *m++;
-       default:
-         if (star)
-         {
-           ls = b;
-           fs = fs ? fs : b;
-           *b++ = 'Z';
-           chset2 &= ~NTL_LOWER;
-           star = 0;
-         };
-         cnt++;
-         chset &= NTL_char_attrib[((*b++ = toLower(ch))) - CHAR_MIN];
-         chset2 &= ~NTL_UPPER;
+        case '*':
+          star = 1;
+          break;
+        case '?':
+          cnt++;
+          *b++ = 'A';
+          chset2 &= ~NTL_LOWER;
+          break;
+        case '\\':
+          if ((*m == '?') || (*m == '*'))
+            ch = *m++;
+        default:
+          if (star)
+          {
+            ls = b;
+            fs = fs ? fs : b;
+            *b++ = 'Z';
+            chset2 &= ~NTL_LOWER;
+            star = 0;
+          };
+          cnt++;
+          *b = ToLower(ch);
+          chset &= IRCD_CharAttrTab[*b++ - CHAR_MIN];
+          chset2 &= ~NTL_UPPER;
       };
 
   if (charset)
@@ -451,9 +445,9 @@ int matchcomp(char *cmask, int *minlen, int *charset, const char *mask)
       x2 = x1 + l1;
       for (loop = 0; loop < lmin; loop++)
       {
-       ch = x1[loop];
-       x1[loop] = x2[loop];
-       x2[loop] = ch;
+        ch = x1[loop];
+        x1[loop] = x2[loop];
+        x2[loop] = ch;
       };
       x1 += lmin;
       sign = l1 - l2;
@@ -480,16 +474,16 @@ int matchcomp(char *cmask, int *minlen, int *charset, const char *mask)
 
 int matchexec(const char *string, const char *cmask, int minlen)
 {
-  register const char *s = string - 1;
-  register const char *b = cmask - 1;
-  register int trash;
-  register const char *bb, *bs;
-  register char ch;
+  const char *s = string - 1;
+  const char *b = cmask - 1;
+  int trash;
+  const char *bb, *bs;
+  char ch;
 
 tryhead:
-  while ((toLower(*++s) == *++b) && *s);
+  while ((ToLower(*++s) == *++b) && *s);
   if (!*s)
-    return ((*b != '\000') && ((*b++ != 'Z') || (*b != '\000')));
+    return ((*b != '\0') && ((*b++ != 'Z') || (*b != '\0')));
   if (*b != 'Z')
   {
     if (*b == 'A')
@@ -504,13 +498,13 @@ tryhead:
     return 2;
 
 trytail:
-  while ((toLower(*--s) == *++b) && *b && (toLower(*--s) == *++b) && *b
-      && (toLower(*--s) == *++b) && *b && (toLower(*--s) == *++b) && *b);
+  while ((ToLower(*--s) == *++b) && *b && (ToLower(*--s) == *++b) && *b
+      && (ToLower(*--s) == *++b) && *b && (ToLower(*--s) == *++b) && *b);
   if (*b != 'Z')
   {
     if (*b == 'A')
       goto trytail;
-    return (*b != '\000');
+    return (*b != '\0');
   };
 
   s = --bs;
@@ -518,13 +512,13 @@ trytail:
 
   while ((ch = *++b))
   {
-    while ((toLower(*++s) != ch))
+    while ((ToLower(*++s) != ch))
       if (--trash < 0)
-       return 4;
+        return 4;
     bs = s;
 
-  trychunk:
-    while ((toLower(*++s) == *++b) && *b);
+trychunk:
+    while ((ToLower(*++s) == *++b) && *b);
     if (!*b)
       return 0;
     if (*b == 'Z')
@@ -560,14 +554,14 @@ trytail:
 
 int matchdecomp(char *mask, const char *cmask)
 {
-  register char *rtb = mask;
-  register const char *rcm = cmask;
-  register const char *begtail, *endtail;
+  char *rtb = mask;
+  const char *rcm = cmask;
+  const char *begtail, *endtail;
 
-  if (rtb == NULL)
+  if (rtb ==0)
     return (-1);
 
-  if (rcm == NULL)
+  if (rcm == 0)
     return (-2);
 
   for (; (*rcm != 'Z'); rcm++, rtb++)
@@ -591,17 +585,17 @@ int matchdecomp(char *mask, const char *cmask)
     while (*++rcm)
       switch (*rcm)
       {
-       case 'A':
-         *rtb++ = '?';
-         break;
-       case 'Z':
-         *rtb++ = '*';
-         break;
-       case '*':
-       case '?':
-         *rtb++ = '\\';
-       default:
-         *rtb++ = *rcm;
+        case 'A':
+          *rtb++ = '?';
+          break;
+        case 'Z':
+          *rtb++ = '*';
+          break;
+        case '*':
+        case '?':
+          *rtb++ = '\\';
+        default:
+          *rtb++ = *rcm;
       };
     *rtb++ = '*';
   };
@@ -610,7 +604,7 @@ int matchdecomp(char *mask, const char *cmask)
     if ((*rcm == '?') || (*rcm == '*'))
       *rtb++ = '\\';
 
-  *rtb = '\000';
+  *rtb = '\0';
   return (rtb - mask);
 }
 
@@ -631,8 +625,8 @@ int matchdecomp(char *mask, const char *cmask)
 
 int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
 {
-  register const char *w, *r, *br, *bw, *rx, *rz;
-  register int eat, trash;
+  const char *w, *r, *br, *bw, *rx, *rz;
+  int eat, trash;
 
   /* First of all rm must have enough non-stars to 'contain' wm */
   if ((trash = rminlen - wminlen) < 0)
@@ -648,12 +642,12 @@ int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
   /* Match the head of wm with the head of rm */
   for (; (*r) && (*r != 'Z') && ((*w == *r) || (*w == 'A')); r++, w++);
   if (*r == 'Z')
-    while (*w == 'A')          /* Eat extra '?' before '*' in wm if got '*' in rm */
+    while (*w == 'A')           /* Eat extra '?' before '*' in wm if got '*' in rm */
       w++, eat++;
-  if (*w != 'Z')               /* head1<any>.. can't match head2<any>.. */
-    return ((*w) || (*r)) ? 1 : 0;     /* and head<nul> matches only head<nul> */
+  if (*w != 'Z')                /* head1<any>.. can't match head2<any>.. */
+    return ((*w) || (*r)) ? 1 : 0;      /* and head<nul> matches only head<nul> */
   if (!*++w)
-    return 0;                  /* headZ<nul> matches head<anything>    */
+    return 0;                   /* headZ<nul> matches head<anything>    */
 
   /* Does rm have any stars in it ? let's check */
   for (rx = r; *r && (*r != 'Z'); r++);
@@ -666,82 +660,82 @@ int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
     if (*w != 'Z')
     {
       for (; r--, (*w) && ((*w == *r) || (*w == 'A')); w++);
-      if (*w != 'Z')           /* headZliat1<any> fails on head<any>2tail  */
-       return (*w) ? 1 : 0;    /* but headZliat<nul> matches head<any>tail */
-    };
+      if (*w != 'Z')            /* headZliat1<any> fails on head<any>2tail  */
+        return (*w) ? 1 : 0;    /* but headZliat<nul> matches head<any>tail */
+    }
 
     /* match the chunks */
     while (1)
-    {                          /* This loop can't break but only return   */
+    {                           /* This loop can't break but only return   */
 
-      for (bw = w++; (*w != *rx); rx++)        /* Seek the 1st char of the chunk */
-       if (--trash < 0)        /* See if we can trash one more char of rm */
-         return 1;             /* If not we can only fail of course       */
+      for (bw = w++; (*w != *rx); rx++) /* Seek the 1st char of the chunk */
+        if (--trash < 0)        /* See if we can trash one more char of rm */
+          return 1;             /* If not we can only fail of course       */
       for (r = ++rx, w++; (*w) && ((*w == *r) || (*w == 'A')); r++, w++);
-      if (!*w)                 /* Did last loop match the rest of chunk ? */
-       return 0;               /* ... Yes, end of wm, matched !           */
+      if (!*w)                  /* Did last loop match the rest of chunk ? */
+        return 0;               /* ... Yes, end of wm, matched !           */
       if (*w != 'Z')
-      {                                /* ... No, hitted non-star                 */
-       w = bw;                 /* Rollback at beginning of chunk          */
-       if (--trash < 0)        /* Trashed the char where this try started */
-         return 1;             /* if we can't trash more chars fail       */
+      {                         /* ... No, hitted non-star                 */
+        w = bw;                 /* Rollback at beginning of chunk          */
+        if (--trash < 0)        /* Trashed the char where this try started */
+          return 1;             /* if we can't trash more chars fail       */
       }
       else
       {
-       rx = r;                 /* Successfully matched a chunk, move rx   */
-      };                       /* and go on with the next one             */
-    };
-  };
+        rx = r;                 /* Successfully matched a chunk, move rx   */
+      }                 /* and go on with the next one             */
+    }
+  }
 
   /* rm has at least one '*' and thus is a 'real' mask */
-  rz = r++;                    /* rx = unused of head, rz = beg-tail */
+  rz = r++;                     /* rx = unused of head, rz = beg-tail */
 
   /* Match the tail of wm (if any) against the tail of rm */
   if (*w != 'Z')
   {
     for (; (*w) && (*r != 'Z') && ((*w == *r) || (*w == 'A')); w++, r++);
-    if (*r == 'Z')             /* extra '?' before tail are fluff, just flush 'em */
+    if (*r == 'Z')              /* extra '?' before tail are fluff, just flush 'em */
       while (*w == 'A')
-       w++;
-    if (*w != 'Z')             /* We aren't matching a chunk, can't rollback      */
+        w++;
+    if (*w != 'Z')              /* We aren't matching a chunk, can't rollback      */
       return (*w) ? 1 : 0;
-  };
+  }
 
   /* Match the chunks of wm against what remains of the head of rm */
   while (1)
   {
     bw = w;
-    for (bw++; (rx < rz) && (*bw != *rx); rx++)        /* Seek the first           */
-      if (--trash < 0)         /* waste some trash reserve */
-       return 1;
-    if (!(rx < rz))            /* head finished            */
+    for (bw++; (rx < rz) && (*bw != *rx); rx++) /* Seek the first           */
+      if (--trash < 0)          /* waste some trash reserve */
+        return 1;
+    if (!(rx < rz))             /* head finished            */
       break;
     for (bw++, (br = ++rx);
-       (br < rz) && (*bw) && ((*bw == *br) || (*bw == 'A')); br++, bw++);
-    if (!(br < rz))            /* Note that we didn't use any 'eat' char yet, if  */
-      while (*bw == 'A')       /* there were eat-en chars the head would be over  */
-       bw++, eat++;            /* Happens only at end of head, and eat is still 0 */
+        (br < rz) && (*bw) && ((*bw == *br) || (*bw == 'A')); br++, bw++);
+    if (!(br < rz))             /* Note that we didn't use any 'eat' char yet, if  */
+      while (*bw == 'A')        /* there were eat-en chars the head would be over  */
+        bw++, eat++;            /* Happens only at end of head, and eat is still 0 */
     if (!*bw)
       return 0;
     if (*bw != 'Z')
     {
       eat = 0;
       if (!(br < rz))
-      {                                /* If we failed because we got the end of head */
-       trash -= (br - rx);     /* it makes no sense to rollback, just trash   */
-       if (--trash < 0)        /* all the rest of the head wich isn't long    */
-         return 1;             /* enough for this chunk and go out of this    */
-       break;                  /* loop, then we try with the chunks of rm     */
+      {                         /* If we failed because we got the end of head */
+        trash -= (br - rx);     /* it makes no sense to rollback, just trash   */
+        if (--trash < 0)        /* all the rest of the head wich isn't long    */
+          return 1;             /* enough for this chunk and go out of this    */
+        break;                  /* loop, then we try with the chunks of rm     */
       };
       if (--trash < 0)
-       return 1;
+        return 1;
     }
     else
     {
       w = bw;
       rx = br;
-    };
-  };
+    }
+  }
 
   /* Match the unused chunks of wm against the chunks of rm */
   rx = r;
@@ -752,56 +746,56 @@ int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
     while (*r)
     {
       bw = w;
-      while (eat && *r)                /* the '?' we had eated make us skip as many chars */
-       if (*r++ != 'Z')        /* here, but can't skip stars or trailing zero     */
-         eat--;
+      while (eat && *r)         /* the '?' we had eated make us skip as many chars */
+        if (*r++ != 'Z')        /* here, but can't skip stars or trailing zero     */
+          eat--;
       for (bw++; (*r) && (*bw != *r); r++)
-       if ((*r != 'Z') && (--trash < 0))
-         return 1;
+        if ((*r != 'Z') && (--trash < 0))
+          return 1;
       if (!*r)
-       break;
+        break;
       for ((br = ++r), bw++;
-         (*br) && (*br != 'Z') && ((*bw == *br) || (*bw == 'A')); br++, bw++);
+          (*br) && (*br != 'Z') && ((*bw == *br) || (*bw == 'A')); br++, bw++);
       if (*br == 'Z')
-       while (*bw == 'A')
-         bw++, eat++;
+        while (*bw == 'A')
+          bw++, eat++;
       if (!*bw)
-       return 0;
+        return 0;
       if (*bw != 'Z')
       {
-       eat = 0;
-       if ((!*br) || (*r == 'Z'))
-       {                       /* If we hit the end of rm or a star in it */
-         trash -= (br - r);    /* makes no sense to rollback within this  */
-         if (trash < 0)        /* same chunk of br, skip it all and then  */
-           return 1;           /* either rollback or break this loop if   */
-         if (!*br)             /* it was the end of rm                    */
-           break;
-         r = br;
-       };
-       if (--trash < 0)
-         return 1;
+        eat = 0;
+        if ((!*br) || (*r == 'Z'))
+        {                       /* If we hit the end of rm or a star in it */
+          trash -= (br - r);    /* makes no sense to rollback within this  */
+          if (trash < 0)        /* same chunk of br, skip it all and then  */
+            return 1;           /* either rollback or break this loop if   */
+          if (!*br)             /* it was the end of rm                    */
+            break;
+          r = br;
+        }
+        if (--trash < 0)
+          return 1;
       }
       else
       {
-       r = br;
-       w = bw;
-      };
-    };
-  };
+        r = br;
+        w = bw;
+      }
+    }
+  }
 
   /* match the remaining chunks of wm against what remains of the tail of rm */
-  r = rz - eat - 1;            /* can't have <nul> or 'Z'within the tail, so just move r */
+  r = rz - eat - 1;             /* can't have <nul> or 'Z'within the tail, so just move r */
   while (r >= rx)
   {
     bw = w;
     for (bw++; (*bw != *r); r--)
       if (--trash < 0)
-       return 1;
+        return 1;
     if (!(r >= rx))
       return 1;
     for ((br = --r), bw++;
-       (*bw) && (br >= rx) && ((*bw == *br) || (*bw == 'A')); br--, bw++);
+        (*bw) && (br >= rx) && ((*bw == *br) || (*bw == 'A')); br--, bw++);
     if (!*bw)
       return 0;
     if (!(br >= rx))
@@ -809,15 +803,15 @@ int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
     if (*bw != 'Z')
     {
       if (--trash < 0)
-       return 1;
+        return 1;
     }
     else
     {
       r = br;
       w = bw;
-    };
-  };
-  return 1;                    /* Auch... something left out ? Fail */
+    }
+  }
+  return 1;                     /* Auch... something left out ? Fail */
 }
 
 /*
@@ -869,23 +863,23 @@ int mmexec(const char *wcm, int wminlen, const char *rcm, int rminlen)
 
 int matchcompIP(struct in_mask *imask, const char *mask)
 {
-  register const char *m = mask;
-  register unsigned int bits = 0;
-  register unsigned int filt = 0;
-  register int unco = 0;
-  register int digits = 0;
-  register int shift = 24;
-  register int tmp = 0;
+  const char *m = mask;
+  unsigned int bits = 0;
+  unsigned int filt = 0;
+  int unco = 0;
+  int digits = 0;
+  int shift = 24;
+  int tmp = 0;
 
   do
   {
     switch (*m)
     {
       case '\\':
-       if ((m[1] == '\\') || (m[1] == '*') || (m[1] == '?')
-           || (m[1] == '\000'))
-         break;
-       continue;
+        if ((m[1] == '\\') || (m[1] == '*') || (m[1] == '?')
+            || (m[1] == '\0'))
+          break;
+        continue;
       case '0':
       case '1':
       case '2':
@@ -896,112 +890,112 @@ int matchcompIP(struct in_mask *imask, const char *mask)
       case '7':
       case '8':
       case '9':
-       if (digits && !tmp)     /* Leading zeros */
-         break;
-       digits++;
-       tmp *= 10;
-       tmp += (*m - '0');      /* Can't overflow, INT_MAX > 2559 */
-       if (tmp > 255)
-         break;
-       continue;
-      case '\000':
-       filt = 0xFFFFFFFF;
-       /* Intentional fallthrough */
+        if (digits && !tmp)     /* Leading zeros */
+          break;
+        digits++;
+        tmp *= 10;
+        tmp += (*m - '0');      /* Can't overflow, INT_MAX > 2559 */
+        if (tmp > 255)
+          break;
+        continue;
+      case '\0':
+        filt = 0xFFFFFFFF;
+        /* Intentional fallthrough */
       case '.':
-       if ((!shift) != (!*m))
-         break;
-       /* Intentional fallthrough */
+        if ((!shift) != (!*m))
+          break;
+        /* Intentional fallthrough */
       case '/':
-       bits |= (tmp << shift);
-       shift -= 8;
-       digits = 0;
-       tmp = 0;
-       if (*m != '/')
-         continue;
-       shift = 24;
-       do
-       {
-         m++;
-         if (isDigit(*m))
-         {
-           if (digits && !tmp) /* Leading zeros */
-             break;
-           digits++;
-           tmp *= 10;
-           tmp += (*m - '0');  /* Can't overflow, INT_MAX > 2559 */
-           if (tmp > 255)
-             break;
-         }
-         else
-         {
-           switch (*m)
-           {
-             case '.':
-             case '\000':
-               if ((!shift) && (*m))
-                 break;
-               filt |= (tmp << shift);
-               shift -= 8;
-               tmp = 0;
-               digits = 0;
-               continue;
-             default:
-               break;
-           }
-           break;
-         }
-       }
-       while (*m);
-       if (*m)
-         break;
-       if (filt && (!(shift < 16)) && (!(filt & 0xE0FFFFFF)))
-         filt = 0xFFFFFFFF << (32 - ((filt >> 24)));
-       bits &= filt;
-       continue;
+        bits |= (tmp << shift);
+        shift -= 8;
+        digits = 0;
+        tmp = 0;
+        if (*m != '/')
+          continue;
+        shift = 24;
+        do
+        {
+          m++;
+          if (IsDigit(*m))
+          {
+            if (digits && !tmp) /* Leading zeros */
+              break;
+            digits++;
+            tmp *= 10;
+            tmp += (*m - '0');  /* Can't overflow, INT_MAX > 2559 */
+            if (tmp > 255)
+              break;
+          }
+          else
+          {
+            switch (*m)
+            {
+              case '.':
+              case '\0':
+                if ((!shift) && (*m))
+                  break;
+                filt |= (tmp << shift);
+                shift -= 8;
+                tmp = 0;
+                digits = 0;
+                continue;
+              default:
+                break;
+            }
+            break;
+          }
+        }
+        while (*m);
+        if (*m)
+          break;
+        if (filt && (!(shift < 16)) && (!(filt & 0xE0FFFFFF)))
+          filt = 0xFFFFFFFF << (32 - ((filt >> 24)));
+        bits &= filt;
+        continue;
       case '?':
-       unco = 1;
-       /* Intentional fallthrough */
+        unco = 1;
+        /* Intentional fallthrough */
       case '*':
-       if (digits)
-         unco = 1;
-       filt = (0xFFFFFFFF << (shift)) << 8;
-       while (*++m)
-       {
-         if (isDigit(*m))
-           unco = 1;
-         else
-         {
-           switch (*m)
-           {
-             case '.':
-               if (m[1] != '*')
-                 unco = 1;
-               if (!shift)
-                 break;
-               shift -= 8;
-               continue;
-             case '?':
-               unco = 1;
-             case '*':
-               continue;
-             default:
-               break;
-           }
-           break;
-         }
-       }
-       if (*m)
-         break;
-       continue;
+        if (digits)
+          unco = 1;
+        filt = (0xFFFFFFFF << (shift)) << 8;
+        while (*++m)
+        {
+          if (IsDigit(*m))
+            unco = 1;
+          else
+          {
+            switch (*m)
+            {
+              case '.':
+                if (m[1] != '*')
+                  unco = 1;
+                if (!shift)
+                  break;
+                shift -= 8;
+                continue;
+              case '?':
+                unco = 1;
+              case '*':
+                continue;
+              default:
+                break;
+            }
+            break;
+          }
+        }
+        if (*m)
+          break;
+        continue;
       default:
-       break;
+        break;
     }
 
     /* If we get here there is some error and this can't ever match */
     filt = 0;
     bits = ~0;
     unco = 0;
-    break;                     /* This time break the loop :) */
+    break;                      /* This time break the loop :) */
 
   }
   while (*m++);
index f5d3e7632ce59247328c7d4857da1cb0073b4833..8838e3869f37dc7f2f5f164955b7efbb29f01cd0 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
 
 #include "numnicks.h"
-
-#include "sys.h"
-#include "h.h"
-#include "s_serv.h"
-#include "struct.h"
-#include "common.h"
+#include "client.h"
 #include "ircd.h"
-#include "s_misc.h"
+#include "ircd_alloc.h"
+#include "ircd_string.h"
 #include "match.h"
 #include "s_bsd.h"
 #include "s_debug.h"
+#include "s_misc.h"
+#include "struct.h"
 
 #include <assert.h>
+#include <stdio.h>
+#include <string.h>
 
-RCSTAG_CC("$Id$");
 
 /*
  * Numeric nicks are new as of version ircu2.10.00beta1.
@@ -62,16 +63,16 @@ RCSTAG_CC("$Id$");
 /* These must be the same on ALL servers ! Do not change ! */
 
 #define NUMNICKLOG 6
-#define NUMNICKMAXCHAR 'z'     /* See convert2n[] */
-#define NUMNICKBASE 64         /* (2 << NUMNICKLOG) */
-#define NUMNICKMASK 63         /* (NUMNICKBASE-1) */
-#define NN_MAX_SERVER 4096     /* (NUMNICKBASE * NUMNICKBASE) */
+#define NUMNICKMAXCHAR 'z'      /* See convert2n[] */
+#define NUMNICKBASE 64          /* (2 << NUMNICKLOG) */
+#define NUMNICKMASK 63          /* (NUMNICKBASE-1) */
+#define NN_MAX_SERVER 4096      /* (NUMNICKBASE * NUMNICKBASE) */
 
 /*
  * The internal counter for the 'XX' of local clients
  */
 static unsigned int lastNNServer = 0;
-static struct Client *server_list[NN_MAX_SERVER];
+static struct Clientserver_list[NN_MAX_SERVER];
 
 /* *INDENT-OFF* */
 
@@ -81,13 +82,13 @@ static struct Client *server_list[NN_MAX_SERVER];
  *
  * '\0' : Because we use '\0' as end of line.
  *
- * ' ' : Because parse_*() uses this as parameter seperator.
- * ':' : Because parse_server() uses this to detect if a prefix is a
- *       numeric or a name.
- * '+' : Because m_nick() uses this to determine if parv[6] is a
- *       umode or not.
+ * ' '  : Because parse_*() uses this as parameter seperator.
+ * ':'  : Because parse_server() uses this to detect if a prefix is a
+ *        numeric or a name.
+ * '+'  : Because m_nick() uses this to determine if parv[6] is a
+ *        umode or not.
  * '&', '#', '+', '$', '@' and '%' :
- *       Because m_message() matches these characters to detect special cases.
+ *        Because m_message() matches these characters to detect special cases.
  */
 static const char convert2y[] = {
   'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
@@ -119,29 +120,27 @@ static const unsigned int convert2n[] = {
 /* *INDENT-ON* */
 
 
-unsigned int base64toint(const char *s)
+unsigned int base64toint(const chars)
 {
-  unsigned int i = convert2n[(unsigned char)*s++];
-  while (*s)
-  {
+  unsigned int i = convert2n[(unsigned char) *s++];
+  while (*s) {
     i <<= NUMNICKLOG;
-    i += convert2n[(unsigned char)*s++];
+    i += convert2n[(unsigned char) *s++];
   }
   return i;
 }
 
-const char *inttobase64(char *buf, unsigned int v, size_t count)
+const char* inttobase64(char* buf, unsigned int v, size_t count)
 {
-  buf[count] = '\0';
-  while (count > 0)
-  {
+  buf[count] = '\0';  
+  while (count > 0) {
     buf[--count] = convert2y[(v & NUMNICKMASK)];
     v >>= NUMNICKLOG;
   }
   return buf;
 }
 
-static struct Client *FindXNServer(const char *numeric)
+static struct Client* FindXNServer(const char* numeric)
 {
   char buf[3];
   buf[0] = *numeric++;
@@ -151,29 +150,47 @@ static struct Client *FindXNServer(const char *numeric)
   return server_list[base64toint(buf)];
 }
 
-struct Client *FindNServer(const char *numeric)
+struct Client* FindNServer(const char* numeric)
 {
   size_t len = strlen(numeric);
-  if (len < 3)
-  {
+
+  if (len < 3) {
     Debug((DEBUG_DEBUG, "FindNServer: %s(%d)", numeric, base64toint(numeric)));
     return server_list[base64toint(numeric)];
   }
-  else if (len == 3)
-  {
-    Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric,
-       convert2n[(unsigned char)*numeric]));
-    return server_list[convert2n[(unsigned char)*numeric]];
+  else if (len == 3) {
+    Debug((DEBUG_DEBUG, "FindNServer: %c(%d)", *numeric, 
+           convert2n[(unsigned char) *numeric]));
+    return server_list[convert2n[(unsigned char) *numeric]];
   }
   return FindXNServer(numeric);
 }
 
-void RemoveYXXClient(struct Client *server, const char *yxx)
+struct Client* findNUser(const char* yxx)
+{
+  struct Client* server = 0;
+  unsigned int index    = 0;
+  if (5 == strlen(yxx)) {
+    if (0 != (server = FindXNServer(yxx))) {
+      Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, 
+             base64toint(yxx + 2), server));
+      if ((index = base64toint(yxx + 2)) <= server->serv->nn_mask)
+        return server->serv->client_list[index];
+    }
+  }
+  else if (0 != (server = FindNServer(yxx))) {
+    index  = base64toint(yxx + 1) & server->serv->nn_mask;
+    Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, index, server));
+    return server->serv->client_list[index];
+  }
+  return 0;
+}
+
+void RemoveYXXClient(struct Client* server, const char* yxx)
 {
   assert(0 != server);
   assert(0 != yxx);
-  if (*yxx)
-  {
+  if (*yxx) {
     unsigned int index = 0;
 
     if (strlen(yxx) < 3)
@@ -188,58 +205,20 @@ void RemoveYXXClient(struct Client *server, const char *yxx)
   }
 }
 
-void SetServerYXX(struct Client *cptr, struct Client *server, const char *yxx)
+void SetServerYXX(struct Client* cptr, struct Client* server, const char* yxx)
 {
   unsigned int index;
-#ifndef NO_PROTOCOL9
-  /* Use cptr, because we do protocol 9 -> 10 translation for numeric nicks ! */
-  if (Protocol(cptr) > 9)
-  {
-#endif
-    if (5 == strlen(yxx))
-    {
-      strncpy(server->yxx, yxx, 2);
-      strncpy(server->serv->nn_capacity, yxx + 2, 3);
-    }
-    else
-    {
-      server->yxx[0] = yxx[0];
-      server->serv->nn_capacity[0] = yxx[1];
-      server->serv->nn_capacity[1] = yxx[2];
-    }
-    server->serv->nn_mask = base64toint(server->serv->nn_capacity);
-
-#ifndef NO_PROTOCOL9
+  if (5 == strlen(yxx)) {
+    ircd_strncpy(server->yxx, yxx, 2);
+    ircd_strncpy(server->serv->nn_capacity, yxx + 2, 3);
   }
-  else
-  {
-    static const struct ServerNameNumeric {
-      const char *name;
-      unsigned int numeric;
-    } server_table[] = {
-      { "Uworld.undernet.org",    22},
-      { "Uworld2.undernet.org",   23},
-      { "channels.undernet.org",  30},
-      { "channels2.undernet.org", 31},
-      {
-      0, 0}
-    };
-    int i;
-    for (i = 0; i < 4; ++i)
-    {
-      if (!strCasediff(server_table[i].name, server->name))
-      {
-       /*
-        * XXX - just use the old format for services for now
-        */
-       *server->yxx = convert2y[server_table[i].numeric];
-       inttobase64(server->serv->nn_capacity, 63, 2);
-       server->serv->nn_mask = 63;
-       break;
-      }
-    }
+  else {
+    server->yxx[0]               = yxx[0];
+    server->serv->nn_capacity[0] = yxx[1];
+    server->serv->nn_capacity[1] = yxx[2];
   }
-#endif
+  server->serv->nn_mask = base64toint(server->serv->nn_capacity);
+
   index = base64toint(server->yxx);
   if (index >= lastNNServer)
     lastNNServer = index + 1;
@@ -249,16 +228,16 @@ void SetServerYXX(struct Client *cptr, struct Client *server, const char *yxx)
    * determine that SetServerYXX has been called - and then calls
    * ClearServerYXX. However, freeing the allocation happens in free_client() */
   server->serv->client_list =
-      (struct Client **)RunCalloc(server->serv->nn_mask + 1,
-      sizeof(struct Client *));
+      (struct Client**) MyCalloc(server->serv->nn_mask + 1, 
+                                   sizeof(struct Client*));
 }
 
-void SetYXXCapacity(struct Client *c, size_t capacity)
+void SetYXXCapacity(struct Clientc, size_t capacity)
 {
   unsigned int max_clients;
 #if defined(EXTENDED_NUMERICS)
   max_clients = capacity - 1;
-  inttobase64(c->serv->nn_capacity, max_clients, 3);
+  inttobase64(c->serv->nn_capacity, max_clients, 3); 
 #else
   max_clients = 16;
   /* 
@@ -269,23 +248,22 @@ void SetYXXCapacity(struct Client *c, size_t capacity)
   /*
    * Sanity checks
    */
-  if (max_clients > NN_MAX_SERVER)
-  {
+  if (max_clients > NN_MAX_SERVER) {
     fprintf(stderr, "MAXCLIENTS (or MAXCONNECTIONS) is (at least) %d "
-       "too large ! Please decrease this value.\n",
-       max_clients - NN_MAX_SERVER);
+            "too large ! Please decrease this value.\n",
+             max_clients - NN_MAX_SERVER);
     exit(-1);
   }
   --max_clients;
-  inttobase64(c->serv->nn_capacity, max_clients, 2);
+  inttobase64(c->serv->nn_capacity, max_clients, 2); 
 #endif
-  c->serv->nn_mask = max_clients;      /* Our Numeric Nick mask */
-  c->serv->client_list = (struct Client **)RunCalloc(max_clients + 1,
-      sizeof(struct Client *));
+  c->serv->nn_mask = max_clients;       /* Our Numeric Nick mask */
+  c->serv->client_list = (struct Client**) MyCalloc(max_clients + 1, 
+                                                     sizeof(struct Client*));
   server_list[base64toint(c->yxx)] = c;
 }
 
-void SetYXXServerName(struct Client *c, unsigned int numeric)
+void SetYXXServerName(struct Clientc, unsigned int numeric)
 {
   assert(0 != c);
   assert(numeric < NN_MAX_SERVER);
@@ -304,7 +282,7 @@ void SetYXXServerName(struct Client *c, unsigned int numeric)
 void ClearServerYXX(const struct Client *server)
 {
   unsigned int index = base64toint(server->yxx);
-  if (server_list[index] == server)    /* Sanity check */
+  if (server_list[index] == server)     /* Sanity check */
     server_list[index] = NULL;
 }
 
@@ -314,19 +292,17 @@ void ClearServerYXX(const struct Client *server)
  * Register numeric of new, remote, client.
  * Add it to the appropriate client_list.
  */
-int SetRemoteNumNick(struct Client *acptr, const char *yxx)
+int SetRemoteNumNick(struct Clientacptr, const char *yxx)
 {
-  struct Client **acptrp;
-  struct Client *server = acptr->user->server;
+  struct Client** acptrp;
+  struct Client*  server = acptr->user->server;
   unsigned int index = 0;
-
-  if (5 == strlen(yxx))
-  {
+  if (5 == strlen(yxx)) {
     strcpy(acptr->yxx, yxx + 2);
     index = base64toint(acptr->yxx);
   }
-  else
-  {
+  else {
     acptr->yxx[0] = *++yxx;
     acptr->yxx[1] = *++yxx;
     acptr->yxx[2] = 0;
@@ -340,8 +316,7 @@ int SetRemoteNumNick(struct Client *acptr, const char *yxx)
   assert(index <= server->serv->nn_mask);
 
   acptrp = &server->serv->client_list[index];
-  if (*acptrp)
-  {
+  if (*acptrp) {
     /*
      * this exits the old client in the array, not the client
      * that is being set
@@ -360,24 +335,22 @@ int SetRemoteNumNick(struct Client *acptr, const char *yxx)
  */
 void SetLocalNumNick(struct Client *cptr)
 {
-  static unsigned int last_nn = 0;
-  struct Client **client_list = me.serv->client_list;
-  unsigned int capacity = me.serv->nn_mask + 1;
-  unsigned int count = 0;
+  static unsigned int last_nn     = 0;
+  struct Client**     client_list = me.serv->client_list;
+  unsigned int        capacity    = me.serv->nn_mask + 1;
+  unsigned int        count       = 0;
 
   assert(cptr->user->server == &me);
 
-  while (client_list[last_nn])
-  {
-    if (++count == capacity)
-    {
+  while (client_list[last_nn]) {
+    if (++count == capacity) {
       assert(count < capacity);
       return;
     }
     if (++last_nn == capacity)
       last_nn = 0;
   }
-  client_list[last_nn] = cptr; /* Reserve the numeric ! */
+  client_list[last_nn] = cptr;  /* Reserve the numeric ! */
 
 #if defined(EXTENDED_NUMERICS)
   inttobase64(cptr->yxx, last_nn, 3);
@@ -386,29 +359,6 @@ void SetLocalNumNick(struct Client *cptr)
 #endif
 }
 
-struct Client *findNUser(const char *yxx)
-{
-  struct Client *server = 0;
-  unsigned int index = 0;
-  if (5 == strlen(yxx))
-  {
-    if (0 != (server = FindXNServer(yxx)))
-    {
-      Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx,
-         base64toint(yxx + 2), server));
-      if ((index = base64toint(yxx + 2)) <= server->serv->nn_mask)
-       return server->serv->client_list[index];
-    }
-  }
-  else if (0 != (server = FindNServer(yxx)))
-  {
-    index = base64toint(yxx + 1) & server->serv->nn_mask;
-    Debug((DEBUG_DEBUG, "findNUser: %s(%d) (%p)", yxx, index, server));
-    return server->serv->client_list[index];
-  }
-  return 0;
-}
-
 /* 
  * markMatchexServer()
  * Mark all servers whose name matches the given (compiled) mask
@@ -420,78 +370,32 @@ int markMatchexServer(const char *cmask, int minlen)
   int i;
   struct Client *acptr;
 
-  for (i = 0; i < lastNNServer; i++)
-  {
-    if ((acptr = server_list[i]))
-    {
+  for (i = 0; i < lastNNServer; i++) {
+    if ((acptr = server_list[i])) {
       if (matchexec(acptr->name, cmask, minlen))
-       acptr->flags &= ~FLAGS_MAP;
-      else
-      {
-       acptr->flags |= FLAGS_MAP;
-       cnt++;
+        acptr->flags &= ~FLAGS_MAP;
+      else {
+        acptr->flags |= FLAGS_MAP;
+        cnt++;
       }
     }
   }
   return cnt;
 }
 
-struct Client *find_match_server(char *mask)
+struct Clientfind_match_server(char *mask)
 {
   struct Client *acptr;
   int i;
 
-  if (!(BadPtr(mask)))
-  {
+  if (!(BadPtr(mask))) {
     collapse(mask);
-    for (i = 0; i < lastNNServer; i++)
-    {
+    for (i = 0; i < lastNNServer; i++) {
       if ((acptr = server_list[i]) && (!match(mask, acptr->name)))
-       return acptr;
+        return acptr;
     }
   }
   return NULL;
 }
 
 
-#ifndef NO_PROTOCOL9
-
-/******************************************************************************
- *
- * The following functions can be removed as soon as all servers have upgraded
- * to ircu2.10.
- */
-
-/*
- * CreateNNforProtocol9server
- *
- * We do not receive numeric nicks from servers behind a protocol 9 link
- * so we generate it ourselfs.
- */
-const char *CreateNNforProtocol9server(const struct Client *server)
-{
-  static char YXX[4];
-  struct Server *serv = server->serv;
-  unsigned int count = 0;
-
-  assert(IsServer(server));
-  assert(9 == Protocol(server));
-
-  YXX[0] = *server->yxx;
-  YXX[3] = 0;
-
-  while (serv->client_list[serv->nn_last])
-  {
-    if (++count == NUMNICKBASE)
-    {
-      assert(count < NUMNICKBASE);
-      return NULL;
-    }
-    if (++serv->nn_last == NUMNICKBASE)
-      serv->nn_last = 0;
-  }
-  inttobase64(YXX + 1, serv->nn_last, 2);
-  return YXX;
-}
-
-#endif /* !NO_PROTOCOL9 */
index 2b0e057862d73d9ce3e0c588c039b4749f63db2c..eb459866d61e7d315f42c41892d38a92fe90d2e3 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <sys/stat.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stdlib.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include "h.h"
 #include "opercmds.h"
-#include "struct.h"
+#include "class.h"
+#include "client.h"
+#include "crule.h"
 #include "ircd.h"
-#include "s_bsd.h"
-#include "send.h"
-#include "s_err.h"
-#include "numeric.h"
+#include "ircd_chattr.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "listener.h"
 #include "match.h"
-#include "s_misc.h"
-#include "s_conf.h"
-#include "class.h"
-#include "s_user.h"
-#include "common.h"
 #include "msg.h"
-#include "sprintf_irc.h"
-#include "userload.h"
-#include "parse.h"
+#include "numeric.h"
 #include "numnicks.h"
-#include "crule.h"
-#include "version.h"
-#include "support.h"
-#include "s_serv.h"
-#include "hash.h"
-
-RCSTAG_CC("$Id$");
-
-/*
- *  m_squit
- *
- *    parv[0] = sender prefix
- *    parv[1] = server name
- *    parv[2] = timestamp
- *    parv[parc-1] = comment
- */
-int m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 aConfItem *aconf;
-  char *server;
-  Reg2 aClient *acptr;
-  char *comment = (parc > ((!IsServer(cptr)) ? 2 : 3) &&
-      !BadPtr(parv[parc - 1])) ? parv[parc - 1] : cptr->name;
-
-  if (!IsPrivileged(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-
-  if (parc > (IsServer(cptr) ? 2 : 1))
-  {
-    server = parv[1];
-    /*
-     * To accomodate host masking, a squit for a masked server
-     * name is expanded if the incoming mask is the same as
-     * the server name for that link to the name of link.
-     */
-    if ((*server == '*') && IsServer(cptr) && (aconf = cptr->serv->nline) &&
-       !strCasediff(server, my_name_for_link(me.name, aconf)))
-    {
-      server = cptr->name;
-      acptr = cptr;
-    }
-    else
-    {
-      /*
-       * The following allows wild cards in SQUIT. Only usefull
-       * when the command is issued by an oper.
-       */
-      for (acptr = client; (acptr = next_client(acptr, server));
-         acptr = acptr->next)
-       if (IsServer(acptr) || IsMe(acptr))
-         break;
-
-      if (acptr)
-      {
-       if (IsMe(acptr))
-       {
-         if (IsServer(cptr))
-         {
-           acptr = cptr;
-           server = cptr->sockhost;
-         }
-         else
-           acptr = NULL;
-       }
-       else
-       {
-         /*
-          * Look for a matching server that is closer,
-          * that way we won't accidently squit two close
-          * servers like davis.* and davis-r.* when typing
-          * /SQUIT davis*
-          */
-         aClient *acptr2;
-         for (acptr2 = acptr->serv->up; acptr2 != &me;
-             acptr2 = acptr2->serv->up)
-           if (!match(server, acptr2->name))
-             acptr = acptr2;
-       }
-      }
-    }
-    /* If atoi(parv[2]) == 0 we must indeed squit !
-     * It wil be our neighbour.
-     */
-    if (acptr && IsServer(cptr) &&
-       atoi(parv[2]) && atoi(parv[2]) != acptr->serv->timestamp)
-    {
-      Debug((DEBUG_NOTICE, "Ignoring SQUIT with wrong timestamp"));
-      return 0;
-    }
-  }
-  else
-  {
-    sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SQUIT");
-    if (IsServer(cptr))
-    {
-      /*
-       * This is actually protocol error. But, well, closing
-       * the link is very proper answer to that...
-       */
-      server = cptr->sockhost;
-      acptr = cptr;
-    }
-    else
-      return 0;
-  }
-  if (!acptr)
-  {
-    if (IsUser(sptr))
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], server);
-    return 0;
-  }
-  if (IsLocOp(sptr) && !MyConnect(acptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
+#include "s_conf.h"
+#include "send.h"
+#include "struct.h"
 
-  return exit_client(cptr, acptr, sptr, comment);
-}
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
 
 /*
  * m_stats/stats_conf
@@ -188,8 +56,7 @@ int m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[])
  */
 
 static unsigned int report_array[17][3] = {
-  {CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
-  {CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
+  {CONF_SERVER, RPL_STATSCLINE, 'C'},
   {CONF_CLIENT, RPL_STATSILINE, 'I'},
   {CONF_KILL, RPL_STATSKLINE, 'K'},
   {CONF_IPKILL, RPL_STATSKLINE, 'k'},
@@ -201,26 +68,25 @@ static unsigned int report_array[17][3] = {
   {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
   {CONF_UWORLD, RPL_STATSULINE, 'U'},
   {CONF_TLINES, RPL_STATSTLINE, 'T'},
-  {CONF_LISTEN_PORT, RPL_STATSPLINE, 'P'},
   {0, 0}
 };
 
-static void report_configured_links(aClient *sptr, int mask)
+void report_configured_links(struct Client *sptr, int mask)
 {
   static char null[] = "<NULL>";
-  aConfItem *tmp;
+  struct ConfItem *tmp;
   unsigned int *p;
   unsigned short int port;
   char c, *host, *pass, *name;
 
-  for (tmp = conf; tmp; tmp = tmp->next)
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
     if ((tmp->status & mask))
     {
       for (p = &report_array[0][0]; *p; p += 3)
-       if (*p == tmp->status)
-         break;
+        if (*p == tmp->status)
+          break;
       if (!*p)
-       continue;
+        continue;
       c = (char)*(p + 2);
       host = BadPtr(tmp->host) ? null : tmp->host;
       pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
@@ -232,1665 +98,40 @@ static void report_configured_links(aClient *sptr, int mask)
        */
       /* Special-case 'k' or 'K' lines as appropriate... -Kev */
       if ((tmp->status & CONF_KLINE))
-       sendto_one(sptr, rpl_str(p[1]), me.name,
-           sptr->name, c, host, pass, name, port, get_conf_class(tmp));
-      /* connect rules are classless */
+        sendto_one(sptr, rpl_str(p[1]), me.name,
+            sptr->name, c, host, pass, name, port, get_conf_class(tmp));
+      /*
+       * connect rules are classless
+       */
       else if ((tmp->status & CONF_CRULE))
-       sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name);
+        sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name);
       else if ((tmp->status & CONF_TLINES))
-       sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, pass);
-      else if ((tmp->status & CONF_LISTEN_PORT))
-       sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, port,
-           tmp->clients, tmp->status);
+        sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, pass);
       else if ((tmp->status & CONF_UWORLD))
-       sendto_one(sptr, rpl_str(p[1]),
-           me.name, sptr->name, c, host, pass, name, port,
-           get_conf_class(tmp));
-      else if ((tmp->status & (CONF_CONNECT_SERVER|CONF_NOCONNECT_SERVER)))
-       sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, "*", name,
-           port, get_conf_class(tmp));
-      else
-       sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name,
-           port, get_conf_class(tmp));
-    }
-  return;
-}
-
-/*
- * m_stats
- *
- *    parv[0] = sender prefix
- *    parv[1] = statistics selector (defaults to Message frequency)
- *    parv[2] = target server (current server defaulted, if omitted)
- * And 'stats l' and 'stats' L:
- *    parv[3] = server mask ("*" defaulted, if omitted)
- * Or for stats p,P:
- *    parv[3] = port mask (returns p-lines when its port is matched by this)
- * Or for stats k,K,i and I:
- *    parv[3] = [user@]host.name  (returns which K/I-lines match this)
- *           or [user@]host.mask  (returns which K/I-lines are mmatched by this)
- *              (defaults to old reply if ommitted, when local or Oper)
- *              A remote mask (something containing wildcards) is only
- *              allowed for IRC Operators.
- * Or for stats M:
- *    parv[3] = time param
- *    parv[4] = time param 
- *    (see report_memleak_stats() in runmalloc.c for details)
- *
- * This function is getting really ugly. -Ghostwolf
- */
-int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
-      "RcveM RcveKBytes :Open since";
-  static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
-  aMessage *mptr;
-  aClient *acptr;
-  aGline *agline, *a2gline;
-  aConfItem *aconf;
-  char stat = parc > 1 ? parv[1][0] : '\0';
-  Reg1 int i;
-
-/* m_stats is so obnoxiously full of special cases that the different
- * hunt_server() possiblites were becoming very messy. It now uses a
- * switch() so as to be easier to read and update as params change. 
- * -Ghostwolf 
- */
-  switch (stat)
-  {
-      /* open to all, standard # of params */
-    case 'U':
-    case 'u':
-    {
-      if (hunt_server(0, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
-         != HUNTED_ISME)
-       return 0;
-      break;
-    }
-
-      /* open to all, varying # of params */
-    case 'k':
-    case 'K':
-    case 'i':
-    case 'I':
-    case 'p':
-    case 'P':
-    {
-      if (parc > 3)
-      {
-       if (hunt_server(0, cptr, sptr, ":%s STATS %s %s :%s", 2, parc, parv)
-           != HUNTED_ISME)
-         return 0;
-      }
-      else
-      {
-       if (hunt_server(0, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
-           != HUNTED_ISME)
-         return 0;
-      }
-      break;
-    }
-
-      /* oper only, varying # of params */
-    case 'l':
-    case 'L':
-    case 'M':
-    {
-      if (parc == 4)
-      {
-       if (hunt_server(1, cptr, sptr, ":%s STATS %s %s :%s", 2, parc, parv)
-           != HUNTED_ISME)
-         return 0;
-      }
-      else if (parc > 4)
-      {
-       if (hunt_server(1, cptr, sptr, ":%s STATS %s %s %s :%s", 2, parc,
-           parv) != HUNTED_ISME)
-         return 0;
-      }
-      else if (hunt_server(1, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
-         != HUNTED_ISME)
-       return 0;
-      break;
-    }
-
-      /* oper only, standard # of params */
-    default:
-    {
-      if (hunt_server(1, cptr, sptr, ":%s STATS %s :%s", 2, parc, parv)
-         != HUNTED_ISME)
-       return 0;
-      break;
-    }
-  }
-
-  switch (stat)
-  {
-    case 'L':
-    case 'l':
-    {
-      int doall = 0, wilds = 0;
-      char *name = "*";
-      if (parc > 3 && *parv[3])
-      {
-       char *p;
-       name = parv[3];
-       wilds = (*name == '*' || *name == '?');
-       for (p = name + 1; *p; ++p)
-         if ((*p == '*' || *p == '?') && p[-1] != '\\')
-         {
-           wilds = 1;
-           break;
-         }
-      }
-      else
-       doall = 1;
-      /*
-       * Send info about connections which match, or all if the
-       * mask matches me.name.  Only restrictions are on those who
-       * are invisible not being visible to 'foreigners' who use
-       * a wild card based search to list it.
-       */
-      sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
-      for (i = 0; i <= highest_fd; i++)
-      {
-       if (!(acptr = loc_clients[i]))
-         continue;
-       /* Don't return clients when this is a request for `all' */
-       if (doall && IsUser(acptr))
-         continue;
-       /* Don't show invisible people to unauthorized people when using
-        * wildcards  -- Is this still needed now /stats is oper only ? */
-       if (IsInvisible(acptr) && (doall || wilds) &&
-           !(MyConnect(sptr) && IsOper(sptr)) &&
-           !IsAnOper(acptr) && (acptr != sptr))
-         continue;
-       /* Only show the ones that match the given mask - if any */
-       if (!doall && wilds && match(name, acptr->name))
-         continue;
-       /* Skip all that do not match the specific query */
-       if (!(doall || wilds) && strCasediff(name, acptr->name))
-         continue;
-       sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
-            acptr->name,
-           (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
-           (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
-           time(NULL) - acptr->firsttime);
-      }
-      break;
-    }
-    case 'C':
-    case 'c':
-      report_configured_links(sptr,
-         CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER);
-      break;
-    case 'G':
-    case 'g':
-      /* send glines */
-      for (agline = gline, a2gline = NULL; agline; agline = agline->next)
-      {
-       if (agline->expire <= TStime())
-       {                       /* handle expired glines */
-         free_gline(agline, a2gline);
-         agline = a2gline ? a2gline : gline;   /* make sure to splice
-                                                  list together */
-         if (!agline)
-           break;              /* last gline; break out of loop */
-         continue;             /* continue! */
-       }
-       sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
-           sptr->name, 'G', agline->name, agline->host,
-           agline->expire, agline->reason);
-       a2gline = agline;
-      }
-      break;
-    case 'H':
-    case 'h':
-      report_configured_links(sptr, CONF_HUB | CONF_LEAF);
-      break;
-    case 'I':
-    case 'i':
-    case 'K':
-    case 'k':                  /* display CONF_IPKILL as well
-                                  as CONF_KILL -Kev */
-    {
-      int wilds, count;
-      char *user, *host, *p;
-      int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
-      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
-      {
-       report_configured_links(sptr, conf_status);
-       break;
-      }
-      if (parc < 4 || *parv[3] == '\0')
-      {
-       sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
-           (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
-       return 0;
-      }
-      wilds = 0;
-      for (p = parv[3]; *p; p++)
-      {
-       if (*p == '\\')
-       {
-         if (!*++p)
-           break;
-         continue;
-       }
-       if (*p == '?' || *p == '*')
-       {
-         wilds = 1;
-         break;
-       }
-      }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-      {
-       wilds = 0;
-       count = 3;
-      }
-      else
-       count = 1000;
-
-      if (conf_status == CONF_CLIENT)
-      {
-       user = NULL;            /* Not used, but to avoid compiler warning. */
-
-       host = parv[3];
-      }
-      else
-      {
-       if ((host = strchr(parv[3], '@')))
-       {
-         user = parv[3];
-         *host++ = 0;;
-       }
-       else
-       {
-         user = NULL;
-         host = parv[3];
-       }
-      }
-      for (aconf = conf; aconf; aconf = aconf->next)
-      {
-       if ((aconf->status & conf_status))
-       {
-         if (conf_status == CONF_KLINE)
-         {
-           if ((!wilds && ((user || aconf->host[1]) &&
-               !match(aconf->host, host) &&
-               (!user || !match(aconf->name, user)))) ||
-               (wilds && !mmatch(host, aconf->host) &&
-               (!user || !mmatch(user, aconf->name))))
-           {
-             sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
-                 sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
-                 aconf->port, get_conf_class(aconf));
-             if (--count == 0)
-               break;
-           }
-         }
-         else if (conf_status == CONF_CLIENT)
-         {
-           if ((!wilds && (!match(aconf->host, host) ||
-               !match(aconf->name, host))) ||
-               (wilds && (!mmatch(host, aconf->host) ||
-               !mmatch(host, aconf->name))))
-           {
-             sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
-                 sptr->name, 'I', aconf->host, aconf->name,
-                 aconf->port, get_conf_class(aconf));
-             if (--count == 0)
-               break;
-           }
-         }
-       }
-      }
-      break;
-    }
-    case 'M':
-#ifdef MEMSIZESTATS
-      sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
-         me.name, parv[0], get_mem_size(), get_alloc_cnt());
-#endif
-#ifdef MEMLEAKSTATS
-      report_memleak_stats(sptr, parc, parv);
-#endif
-#if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
-      sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
-         "is not enabled on this server", me.name, parv[0]);
-#endif
-      break;
-    case 'm':
-      for (mptr = msgtab; mptr->cmd; mptr++)
-       if (mptr->count)
-         sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
-             me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
-      break;
-    case 'o':
-    case 'O':
-      report_configured_links(sptr, CONF_OPS);
-      break;
-    case 'p':
-    case 'P':
-    {
-      int count = 100;
-      char port[6];
-      if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
-      {
-       report_configured_links(sptr, CONF_LISTEN_PORT);
-       break;
-      }
-      if (!(MyConnect(sptr) || IsOper(sptr)))
-       count = 3;
-      for (aconf = conf; aconf; aconf = aconf->next)
-       if (aconf->status == CONF_LISTEN_PORT)
-       {
-         if (parc >= 4 && *parv[3] != '\0')
-         {
-           sprintf_irc(port, "%u", aconf->port);
-           if (match(parv[3], port))
-             continue;
-         }
-         sendto_one(sptr, rpl_str(RPL_STATSPLINE), me.name, sptr->name, 'P',
-             aconf->port, aconf->clients, aconf->status);
-         if (--count == 0)
-           break;
-       }
-      break;
-    }
-    case 'R':
-    case 'r':
-#ifdef DEBUGMODE
-      send_usage(sptr, parv[0]);
-#endif
-      break;
-    case 'D':
-      report_configured_links(sptr, CONF_CRULEALL);
-      break;
-    case 'd':
-      report_configured_links(sptr, CONF_CRULE);
-      break;
-    case 't':
-      tstats(sptr, parv[0]);
-      break;
-    case 'T':
-      report_configured_links(sptr, CONF_TLINES);
-      break;
-    case 'U':
-      report_configured_links(sptr, CONF_UWORLD);
-      break;
-    case 'u':
-    {
-      register time_t nowr;
-
-      nowr = now - me.since;
-      sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
-         nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
-      sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
-         max_connection_count, max_client_count);
-      break;
-    }
-    case 'W':
-    case 'w':
-      calc_load(sptr);
-      break;
-    case 'X':
-    case 'x':
-#ifdef DEBUGMODE
-      send_listinfo(sptr, parv[0]);
-#endif
-      break;
-    case 'Y':
-    case 'y':
-      report_classes(sptr);
-      break;
-    case 'Z':
-    case 'z':
-      count_memory(sptr, parv[0]);
-      break;
-    default:
-      stat = '*';
-      break;
-  }
-  sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
-  return 0;
-}
-
-/*
- *  m_connect                           - Added by Jto 11 Feb 1989
- *
- *    parv[0] = sender prefix
- *    parv[1] = servername
- *    parv[2] = port number
- *    parv[3] = remote server
- */
-int m_connect(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  int retval;
-  unsigned short int port, tmpport;
-  aConfItem *aconf, *cconf;
-  aClient *acptr;
-
-  if (!IsPrivileged(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return -1;
-  }
-
-  if (IsLocOp(sptr) && parc > 3)       /* Only allow LocOps to make */
-    return 0;                  /* local CONNECTS --SRB      */
-
-  if (parc > 3 && MyUser(sptr))
-  {
-    aClient *acptr2, *acptr3;
-    if (!(acptr3 = find_match_server(parv[3])))
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[3]);
-      return 0;
-    }
-
-    /* Look for closest matching server */
-    for (acptr2 = acptr3; acptr2 != &me; acptr2 = acptr2->serv->up)
-      if (!match(parv[3], acptr2->name))
-       acptr3 = acptr2;
-
-    parv[3] = acptr3->name;
-  }
-
-  if (hunt_server(1, cptr, sptr, ":%s CONNECT %s %s :%s", 3, parc, parv) !=
-      HUNTED_ISME)
-    return 0;
-
-  if (parc < 2 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "CONNECT");
-    return -1;
-  }
-
-  if ((acptr = FindServer(parv[1])))
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
-         me.name, parv[0], parv[1], "already exists from", acptr->from->name);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :Connect: Server %s %s %s.",
-         NumServ(&me), NumNick(sptr), parv[1], "already exists from",
-         acptr->from->name);
-    return 0;
-  }
-
-  for (aconf = conf; aconf; aconf = aconf->next)
-    if (aconf->status == CONF_CONNECT_SERVER &&
-       match(parv[1], aconf->name) == 0)
-      break;
-  /* Checked first servernames, then try hostnames. */
-  if (!aconf)
-    for (aconf = conf; aconf; aconf = aconf->next)
-      if (aconf->status == CONF_CONNECT_SERVER &&
-         (match(parv[1], aconf->host) == 0 ||
-         match(parv[1], strchr(aconf->host, '@') + 1) == 0))
-       break;
-
-  if (!aconf)
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr,
-         ":%s NOTICE %s :Connect: Host %s not listed in ircd.conf",
-         me.name, parv[0], parv[1]);
-    else
-      sendto_one(sptr,
-         "%s NOTICE %s%s :Connect: Host %s not listed in ircd.conf",
-         NumServ(&me), NumNick(sptr), parv[1]);
-    return 0;
-  }
-  /*
-   *  Get port number from user, if given. If not specified,
-   *  use the default from configuration structure. If missing
-   *  from there, then use the precompiled default.
-   */
-  tmpport = port = aconf->port;
-  if (parc > 2 && !BadPtr(parv[2]))
-  {
-    if ((port = atoi(parv[2])) == 0)
-    {
-      if (MyUser(sptr) || Protocol(cptr) < 10)
-       sendto_one(sptr,
-           ":%s NOTICE %s :Connect: Invalid port number", me.name, parv[0]);
+        sendto_one(sptr, rpl_str(p[1]),
+            me.name, sptr->name, c, host, pass, name, port,
+            get_conf_class(tmp));
+      else if ((tmp->status & CONF_SERVER))
+        sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, "*", name,
+            port, get_conf_class(tmp));
       else
-       sendto_one(sptr, "%s NOTICE %s%s :Connect: Invalid port number",
-           NumServ(&me), NumNick(sptr));
-      return 0;
+        sendto_one(sptr, rpl_str(p[1]), me.name, sptr->name, c, host, name,
+            port, get_conf_class(tmp));
     }
   }
-  else if (port == 0 && (port = PORTNUM) == 0)
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
-         me.name, parv[0]);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :Connect: missing port number",
-         NumServ(&me), NumNick(sptr));
-    return 0;
-  }
-
-  /*
-   * Evaluate connection rules...  If no rules found, allow the
-   * connect.   Otherwise stop with the first true rule (ie: rules
-   * are ored together.  Oper connects are effected only by D
-   * lines (CRULEALL) not d lines (CRULEAUTO).
-   */
-  for (cconf = conf; cconf; cconf = cconf->next)
-    if ((cconf->status == CONF_CRULEALL) &&
-       (match(cconf->host, aconf->name) == 0))
-      if (crule_eval(cconf->passwd))
-      {
-       if (MyUser(sptr) || Protocol(cptr) < 10)
-         sendto_one(sptr, ":%s NOTICE %s :Connect: Disallowed by rule: %s",
-             me.name, parv[0], cconf->name);
-       else
-         sendto_one(sptr, "%s NOTICE %s%s :Connect: Disallowed by rule: %s",
-             NumServ(&me), NumNick(sptr), cconf->name);
-       return 0;
-      }
-
-  /*
-   * Notify all operators about remote connect requests
-   */
-  if (!IsAnOper(cptr))
-  {
-    sendto_ops_butone(NULL, &me, ":%s WALLOPS :Remote CONNECT %s %s from %s",
-       me.name, parv[1], parv[2] ? parv[2] : "", get_client_name(sptr, FALSE));
-#if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
-    syslog(LOG_DEBUG,
-       "CONNECT From %s : %s %d", parv[0], parv[1], parv[2] ? parv[2] : "");
-#endif
-  }
-  aconf->port = port;
-  switch (retval = connect_server(aconf, sptr, NULL))
-  {
-    case 0:
-      if (MyUser(sptr) || Protocol(cptr) < 10)
-       sendto_one(sptr,
-           ":%s NOTICE %s :*** Connecting to %s.",
-           me.name, parv[0], aconf->name);
-      else
-       sendto_one(sptr,
-           "%s NOTICE %s%s :*** Connecting to %s.",
-           NumServ(&me), NumNick(sptr), aconf->name);
-      break;
-    case -1:
-      /* Comments already sent */
-      break;
-    case -2:
-      if (MyUser(sptr) || Protocol(cptr) < 10)
-       sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
-           me.name, parv[0], aconf->name);
-      else
-       sendto_one(sptr, "%s NOTICE %s%s :*** Host %s is unknown.",
-           NumServ(&me), NumNick(sptr), aconf->name);
-      break;
-    default:
-      if (MyUser(sptr) || Protocol(cptr) < 10)
-       sendto_one(sptr,
-           ":%s NOTICE %s :*** Connection to %s failed: %s",
-           me.name, parv[0], aconf->name, strerror(retval));
-      else
-       sendto_one(sptr,
-           "%s NOTICE %s%s :*** Connection to %s failed: %s",
-           NumServ(&me), NumNick(sptr), aconf->name, strerror(retval));
-  }
-  aconf->port = tmpport;
-  return 0;
-}
-
-/*
- * m_wallops
- *
- * Writes to all +w users currently online
- *
- * parv[0] = sender prefix
- * parv[1] = message text
- */
-int m_wallops(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  char *message;
-
-  message = parc > 1 ? parv[1] : NULL;
-
-  if (BadPtr(message))
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "WALLOPS");
-    return 0;
-  }
-
-  if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-  sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
-      ":%s WALLOPS :%s", parv[0], message);
-  return 0;
 }
 
-/*
- * m_time
- *
- * parv[0] = sender prefix
- * parv[1] = servername
- */
-int m_time(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  if (hunt_server(0, cptr, sptr, ":%s TIME :%s", 1, parc, parv) == HUNTED_ISME)
-    sendto_one(sptr, rpl_str(RPL_TIME), me.name,
-       parv[0], me.name, TStime(), TSoffset, date((long)0));
-  return 0;
-}
-
-/*
- * m_settime
- *
- * parv[0] = sender prefix
- * parv[1] = new time
- * parv[2] = servername (Only used when sptr is an Oper).
- */
-int m_settime(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  time_t t;
-  long int dt;
-  static char tbuf[11];
-  Dlink *lp;
-
-  if (!IsPrivileged(sptr))
-    return 0;
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SETTIME");
-    return 0;
-  }
-
-  if (parc == 2 && MyUser(sptr))
-    parv[parc++] = me.name;
-
-  t = atoi(parv[1]);
-  dt = TStime() - t;
-
-  if (t < 779557906 || dt < -9000000)
-  {
-    sendto_one(sptr, ":%s NOTICE %s :SETTIME: Bad value", me.name, parv[0]);
-    return 0;
-  }
-
-  if (IsServer(sptr))          /* send to unlagged servers */
-  {
-#ifdef RELIABLE_CLOCK
-    sprintf_irc(tbuf, TIME_T_FMT, TStime());
-    parv[1] = tbuf;
-#endif
-    for (lp = me.serv->down; lp; lp = lp->next)
-      if (cptr != lp->value.cptr && DBufLength(&lp->value.cptr->sendQ) < 8000)
-       sendto_one(lp->value.cptr, ":%s SETTIME %s", parv[0], parv[1]);
-  }
-  else
-  {
-    sprintf_irc(tbuf, TIME_T_FMT, TStime());
-    parv[1] = tbuf;
-    if (hunt_server(1, cptr, sptr, ":%s SETTIME %s %s", 2, parc, parv) !=
-       HUNTED_ISME)
-      return 0;
-  }
-
-#ifdef RELIABLE_CLOCK
-  if ((dt > 600) || (dt < -600))
-    sendto_serv_butone((aClient *)NULL,
-       ":%s WALLOPS :Bad SETTIME from %s: " TIME_T_FMT, me.name, sptr->name,
-       t);
-  if (IsUser(sptr))
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :clock is not set %ld seconds %s : "
-         "RELIABLE_CLOCK is defined", me.name, parv[0],
-         (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :clock is not set %ld seconds %s : "
-         "RELIABLE_CLOCK is defined", NumServ(&me), NumNick(sptr),
-         (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
-  }
-#else
-  sendto_ops("SETTIME from %s, clock is set %ld seconds %s",
-      sptr->name, (dt < 0) ? -dt : dt,
-      (dt < 0) ? "forwards" : "backwards");
-  TSoffset -= dt;
-  if (IsUser(sptr))
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :clock is set %ld seconds %s", me.name,
-         parv[0], (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :clock is set %ld seconds %s",
-         NumServ(&me), NumNick(sptr),
-         (dt < 0) ? -dt : dt, (dt < 0) ? "forwards" : "backwards");
-  }
-#endif
-  return 0;
-}
-
-static char *militime(char *sec, char *usec)
+char *militime(char* sec, char* usec)
 {
   struct timeval tv;
   static char timebuf[18];
 
   gettimeofday(&tv, NULL);
   if (sec && usec)
-#if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
     sprintf(timebuf, "%ld",
-       (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
-#else
-    sprintf_irc(timebuf, "%d",
-       (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
-#endif
+        (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
   else
-#if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
     sprintf(timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
-#else
-    sprintf_irc(timebuf, "%d %d", tv.tv_sec, tv.tv_usec);
-#endif
   return timebuf;
 }
 
-/*
- * m_rping  -- by Run
- *
- *    parv[0] = sender (sptr->name thus)
- * if sender is a person: (traveling towards start server)
- *    parv[1] = pinged server[mask]
- *    parv[2] = start server (current target)
- *    parv[3] = optional remark
- * if sender is a server: (traveling towards pinged server)
- *    parv[1] = pinged server (current target)
- *    parv[2] = original sender (person)
- *    parv[3] = start time in s
- *    parv[4] = start time in us
- *    parv[5] = the optional remark
- */
-int m_rping(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr;
-
-  if (!IsPrivileged(sptr))
-    return 0;
-
-  if (parc < (IsAnOper(sptr) ? (MyConnect(sptr) ? 2 : 3) : 6))
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RPING");
-    return 0;
-  }
-  if (MyUser(sptr))
-  {
-    if (parc == 2)
-      parv[parc++] = me.name;
-    else if (!(acptr = find_match_server(parv[2])))
-    {
-      parv[3] = parv[2];
-      parv[2] = me.name;
-      parc++;
-    }
-    else
-      parv[2] = acptr->name;
-    if (parc == 3)
-      parv[parc++] = "<No client start time>";
-  }
-
-  if (IsAnOper(sptr))
-  {
-    if (hunt_server(1, cptr, sptr, ":%s RPING %s %s :%s", 2, parc, parv) !=
-       HUNTED_ISME)
-      return 0;
-    if (!(acptr = find_match_server(parv[1])) || !IsServer(acptr))
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
-      return 0;
-    }
-    if (Protocol(acptr->from) < 10)
-      sendto_one(acptr, ":%s RPING %s %s %s :%s",
-         me.name, acptr->name, sptr->name, militime(NULL, NULL), parv[3]);
-    else
-      sendto_one(acptr, ":%s RPING %s %s %s :%s",
-         me.name, NumServ(acptr), sptr->name, militime(NULL, NULL), parv[3]);
-  }
-  else
-  {
-    if (hunt_server(1, cptr, sptr, ":%s RPING %s %s %s %s :%s", 1, parc, parv)
-       != HUNTED_ISME)
-      return 0;
-    sendto_one(cptr, ":%s RPONG %s %s %s %s :%s", me.name, parv[0],
-       parv[2], parv[3], parv[4], parv[5]);
-  }
-  return 0;
-}
-
-/*
- * m_rpong  -- by Run too :)
- *
- * parv[0] = sender prefix
- * parv[1] = from pinged server: start server; from start server: sender
- * parv[2] = from pinged server: sender; from start server: pinged server
- * parv[3] = pingtime in ms
- * parv[4] = client info (for instance start time)
- */
-int m_rpong(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr;
-
-  if (!IsServer(sptr))
-    return 0;
-
-  if (parc < 5)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RPING");
-    return 0;
-  }
-
-  if (!(acptr = FindClient(parv[1])))
-    return 0;
-
-  if (!IsMe(acptr))
-  {
-    if (IsServer(acptr) && parc > 5)
-    {
-      sendto_one(acptr, ":%s RPONG %s %s %s %s :%s",
-         parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
-      return 0;
-    }
-  }
-  else
-  {
-    parv[1] = parv[2];
-    parv[2] = sptr->name;
-    parv[0] = me.name;
-    parv[3] = militime(parv[3], parv[4]);
-    parv[4] = parv[5];
-    if (!(acptr = FindUser(parv[1])))
-      return 0;                        /* No bouncing between servers ! */
-  }
-
-  sendto_one(acptr, ":%s RPONG %s %s %s :%s",
-      parv[0], parv[1], parv[2], parv[3], parv[4]);
-  return 0;
-}
-
-#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
-/*
- * m_rehash
- */
-int m_rehash(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-#ifndef LOCOP_REHASH
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef OPER_REHASH
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-  sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
-  sendto_ops("%s is rehashing Server config file", parv[0]);
-#ifdef USE_SYSLOG
-  syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
-#endif
-  return rehash(cptr, (parc > 1) ? ((*parv[1] == 'q') ? 2 : 0) : 0);
-}
-#endif
-
-#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
-/*
- * m_restart
- */
-int m_restart(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc),
-    char *parv[])
-{
-#ifndef LOCOP_RESTART
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef OPER_RESTART
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-#ifdef USE_SYSLOG
-  syslog(LOG_WARNING, "Server RESTART by %s\n", get_client_name(sptr, FALSE));
-#endif
-  server_reboot();
-  return 0;
-}
-#endif
-
-/*
- * m_trace
- *
- * parv[0] = sender prefix
- * parv[1] = nick or servername
- * parv[2] = 'target' servername
- */
-int m_trace(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 int i;
-  Reg2 aClient *acptr;
-  aConfClass *cltmp;
-  char *tname;
-  int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
-  int cnt = 0, wilds, dow;
-
-  if (parc < 2 || BadPtr(parv[1]))
-  {
-    /* just "TRACE" without parameters. Must be from local client */
-    parc = 1;
-    acptr = &me;
-    tname = me.name;
-    i = HUNTED_ISME;
-  }
-  else if (parc < 3 || BadPtr(parv[2]))
-  {
-    /* No target specified. Make one before propagating. */
-    parc = 2;
-    tname = parv[1];
-    if ((acptr = find_match_server(parv[1])) ||
-       ((acptr = FindClient(parv[1])) && !MyUser(acptr)))
-    {
-      if (IsUser(acptr))
-       parv[2] = acptr->user->server->name;
-      else
-       parv[2] = acptr->name;
-      parc = 3;
-      parv[3] = NULL;
-      if ((i = hunt_server(IsServer(acptr), cptr, sptr,
-         ":%s TRACE %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
-       return 0;
-    }
-    else
-      i = HUNTED_ISME;
-  }
-  else
-  {
-    /* Got "TRACE <tname> :<target>" */
-    parc = 3;
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      acptr = find_match_server(parv[2]);
-    else
-      acptr = FindNServer(parv[2]);
-    if ((i = hunt_server(0, cptr, sptr,
-       ":%s TRACE %s :%s", 2, parc, parv)) == HUNTED_NOSUCH)
-      return 0;
-    tname = parv[1];
-  }
-
-  if (i == HUNTED_PASS)
-  {
-    if (!acptr)
-      acptr = next_client(client, tname);
-    else
-      acptr = acptr->from;
-    sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
-#ifndef GODMODE
-       version, debugmode, tname, acptr ? acptr->from->name : "<No_match>");
-#else /* GODMODE */
-       version, debugmode, tname, acptr ? acptr->from->name : "<No_match>",
-       (acptr && acptr->from->serv) ? acptr->from->serv->timestamp : 0);
-#endif /* GODMODE */
-    return 0;
-  }
-
-  doall = (parv[1] && (parc > 1)) ? !match(tname, me.name) : TRUE;
-  wilds = !parv[1] || strchr(tname, '*') || strchr(tname, '?');
-  dow = wilds || doall;
-
-  /* Don't give (long) remote listings to lusers */
-  if (dow && !MyConnect(sptr) && !IsAnOper(sptr))
-    return 0;
-
-  for (i = 0; i < MAXCONNECTIONS; i++)
-    link_s[i] = 0, link_u[i] = 0;
-
-  if (doall)
-  {
-    for (acptr = client; acptr; acptr = acptr->next)
-      if (IsUser(acptr))
-       link_u[acptr->from->fd]++;
-      else if (IsServer(acptr))
-       link_s[acptr->from->fd]++;
-  }
-
-  /* report all direct connections */
-
-  for (i = 0; i <= highest_fd; i++)
-  {
-    unsigned int conClass;
-
-    if (!(acptr = loc_clients[i]))     /* Local Connection? */
-      continue;
-    if (IsInvisible(acptr) && dow && !(MyConnect(sptr) && IsOper(sptr)) &&
-       !IsAnOper(acptr) && (acptr != sptr))
-      continue;
-    if (!doall && wilds && match(tname, acptr->name))
-      continue;
-    if (!dow && strCasediff(tname, acptr->name))
-      continue;
-    conClass = get_client_class(acptr);
-
-    switch (acptr->status)
-    {
-      case STAT_CONNECTING:
-       sendto_one(sptr, rpl_str(RPL_TRACECONNECTING),
-           me.name, parv[0], conClass, acptr->name);
-       cnt++;
-       break;
-      case STAT_HANDSHAKE:
-       sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE),
-           me.name, parv[0], conClass, acptr->name);
-       cnt++;
-       break;
-      case STAT_ME:
-       break;
-      case STAT_UNKNOWN:
-      case STAT_UNKNOWN_USER:
-       sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
-           me.name, parv[0], conClass, get_client_name(acptr, FALSE));
-       cnt++;
-       break;
-      case STAT_UNKNOWN_SERVER:
-       sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
-           me.name, parv[0], conClass, acptr->name);
-       cnt++;
-       break;
-      case STAT_USER:
-       /* Only opers see users if there is a wildcard
-          but anyone can see all the opers. */
-       if ((IsAnOper(sptr) && (MyUser(sptr) ||
-           !(dow && IsInvisible(acptr)))) || !dow || IsAnOper(acptr))
-       {
-         if (IsAnOper(acptr))
-           sendto_one(sptr, rpl_str(RPL_TRACEOPERATOR),
-               me.name, parv[0], conClass, get_client_name(acptr, FALSE), now - acptr->lasttime);
-         else
-           sendto_one(sptr, rpl_str(RPL_TRACEUSER),
-               me.name, parv[0], conClass, get_client_name(acptr, FALSE), now - acptr->lasttime);
-         cnt++;
-       }
-       break;
-       /*
-        * Connection is a server
-        *
-        * Serv <class> <nS> <nC> <name> <ConnBy> <last> <age>
-        *
-        * class        Class the server is in
-        * nS           Number of servers reached via this link
-        * nC           Number of clients reached via this link
-        * name         Name of the server linked
-        * ConnBy       Who established this link
-        * last         Seconds since we got something from this link
-        * age          Seconds this link has been alive
-        *
-        * Additional comments etc......        -Cym-<cym@acrux.net>
-        */
-
-      case STAT_SERVER:
-       if (acptr->serv->user)
-         sendto_one(sptr, rpl_str(RPL_TRACESERVER),
-             me.name, parv[0], conClass, link_s[i],
-             link_u[i], acptr->name, acptr->serv->by,
-             acptr->serv->user->username,
-             acptr->serv->user->host,
-             now - acptr->lasttime, now - acptr->serv->timestamp);
-       else
-         sendto_one(sptr, rpl_str(RPL_TRACESERVER),
-             me.name, parv[0], conClass, link_s[i],
-             link_u[i], acptr->name, *(acptr->serv->by) ?
-             acptr->serv->by : "*", "*", me.name,
-             now - acptr->lasttime, now - acptr->serv->timestamp);
-       cnt++;
-       break;
-      case STAT_LOG:
-       sendto_one(sptr, rpl_str(RPL_TRACELOG),
-           me.name, parv[0], LOGFILE, acptr->port);
-       cnt++;
-       break;
-      case STAT_PING:
-       sendto_one(sptr, rpl_str(RPL_TRACEPING), me.name,
-           parv[0], acptr->name, (acptr->acpt) ? acptr->acpt->name : "<null>");
-       break;
-      default:                 /* We actually shouldn't come here, -msa */
-       sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE), me.name, parv[0], acptr->name);
-       cnt++;
-       break;
-    }
-  }
-  /*
-   * Add these lines to summarize the above which can get rather long
-   * and messy when done remotely - Avalon
-   */
-  if (!IsAnOper(sptr) || !cnt)
-  {
-    if (!cnt)
-      /* let the user have some idea that its at the end of the trace */
-      sendto_one(sptr, rpl_str(RPL_TRACESERVER),
-         me.name, parv[0], 0, link_s[me.fd],
-         link_u[me.fd], "<No_match>", *(me.serv->by) ?
-         me.serv->by : "*", "*", me.name, 0, 0);
-    return 0;
-  }
-  for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp))
-    if (Links(cltmp) > 0)
-      sendto_one(sptr, rpl_str(RPL_TRACECLASS), me.name,
-         parv[0], ConClass(cltmp), Links(cltmp));
-  return 0;
-}
-
-/*
- *  m_close                              - added by Darren Reed Jul 13 1992.
- */
-int m_close(aClient *cptr, aClient *sptr, int UNUSED(parc), char *parv[])
-{
-  Reg1 aClient *acptr;
-  Reg2 int i;
-  int closed = 0;
-
-  if (!MyOper(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-
-  for (i = highest_fd; i; i--)
-  {
-    if (!(acptr = loc_clients[i]))
-      continue;
-    if (!IsUnknown(acptr) && !IsConnecting(acptr) && !IsHandshake(acptr))
-      continue;
-    sendto_one(sptr, rpl_str(RPL_CLOSING), me.name, parv[0],
-       get_client_name(acptr, FALSE), acptr->status);
-    exit_client(cptr, acptr, &me, "Oper Closing");
-    closed++;
-  }
-  sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
-  return 0;
-}
-
-#if defined(OPER_DIE) || defined(LOCOP_DIE)
-/*
- * m_die
- */
-int m_die(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
-{
-  Reg1 aClient *acptr;
-  Reg2 int i;
-
-#ifndef LOCOP_DIE
-  if (!MyUser(sptr) || !IsOper(sptr))
-#else
-#ifdef OPER_DIE
-  if (!MyUser(sptr) || !IsAnOper(sptr))
-#else
-  if (!MyUser(sptr) || !IsLocOp(sptr))
-#endif
-#endif
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-
-  for (i = 0; i <= highest_fd; i++)
-  {
-    if (!(acptr = loc_clients[i]))
-      continue;
-    if (IsUser(acptr))
-      sendto_one(acptr, ":%s NOTICE %s :Server Terminating. %s",
-         me.name, acptr->name, get_client_name(sptr, FALSE));
-    else if (IsServer(acptr))
-      sendto_one(acptr, ":%s ERROR :Terminated by %s",
-         me.name, get_client_name(sptr, FALSE));
-  }
-#ifdef __cplusplus
-  s_die(0);
-#else
-  s_die();
-#endif
-  return 0;
-}
-#endif
-
-static void add_gline(aClient *sptr, int ip_mask, char *host, char *comment,
-    char *user, time_t expire, int local)
-{
-  aClient *acptr;
-  aGline *agline;
-  int fd,gtype=0;
-
-#ifdef BADCHAN
-  if(*host=='#' || *host == '&' || *host == '+')
-    gtype=1;   /* BAD CHANNEL */
-#endif
-  /* Inform ops */
-  sendto_op_mask(SNO_GLINE,
-      "%s adding %s%s for %s@%s, expiring at " TIME_T_FMT ": %s", sptr->name,
-      local ? "local " : "",
-      gtype ? "BADCHAN":"GLINE", user, host, expire, comment);
-
-#ifdef GPATH
-  write_log(GPATH,
-      "# " TIME_T_FMT " %s adding %s %s for %s@%s, expiring at " TIME_T_FMT
-      ": %s\n", TStime(), sptr->name, local ? "local" : "global",
-      gtype ? "BADCHAN" : "GLINE", user, host, expire, comment);
-
-  /* this can be inserted into the conf */
-  if(!gtype)
-    write_log(GPATH, "%c:%s:%s:%s\n", ip_mask ? 'k' : 'K', host, comment, 
-      user);
-#endif /* GPATH */
-
-  agline = make_gline(ip_mask, host, comment, user, expire);
-  if (local)
-    SetGlineIsLocal(agline);
-
-#ifdef BADCHAN
-  if(gtype) return;
-#endif
-
-  for (fd = highest_fd; fd >= 0; --fd) /* get the users! */
-    if ((acptr = loc_clients[fd]) && !IsMe(acptr))
-    {
-
-      if (!acptr->user || strlen(acptr->sockhost) > (size_t)HOSTLEN ||
-         (acptr->user->username ? strlen(acptr->user->username) : 0) >
-         (size_t)HOSTLEN)
-       continue;               /* these tests right out of
-                                  find_kill for safety's sake */
-
-      if ((GlineIsIpMask(agline) ?
-         match(agline->host, inetntoa(acptr->ip)) :
-         match(agline->host, acptr->sockhost)) == 0 &&
-         (!acptr->user->username ||
-         match(agline->name, acptr->user->username) == 0))
-      {
-
-       /* ok, he was the one that got G-lined */
-       sendto_one(acptr, ":%s %d %s :*** %s.", me.name,
-           ERR_YOUREBANNEDCREEP, acptr->name, agline->reason);
-
-       /* let the ops know about my first kill */
-       sendto_op_mask(SNO_GLINE, "G-line active for %s",
-           get_client_name(acptr, FALSE));
-
-       /* and get rid of him */
-       if (sptr != acptr)
-         exit_client(sptr->from, acptr, &me, "G-lined");
-      }
-    }
-}
-
-/*
- * m_gline
- *
- * parv[0] = Send prefix
- *
- * From server:
- *
- * parv[1] = Target: server numeric
- * parv[2] = [+|-]<G-line mask>
- * parv[3] = Expiration offset
- * parv[4] = Comment
- *
- * From client:
- *
- * parv[1] = [+|-]<G-line mask>
- * parv[2] = Expiration offset
- * parv[3] = Comment
- *
- */
-int m_gline(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr = NULL;       /* Init. to avoid compiler warning. */
-
-  aGline *agline, *a2gline;
-  char *user, *host;
-  int active, ip_mask,gtype = 0;
-  time_t expire = 0;
-
-  /* Remove expired G-lines */
-  for (agline = gline, a2gline = NULL; agline; agline = agline->next)
-  {
-    if (agline->expire <= TStime())
-    {
-      free_gline(agline, a2gline);
-      agline = a2gline ? a2gline : gline;
-      if (!agline)
-       break;
-      continue;
-    }
-    a2gline = agline;
-  }
-
-#ifdef BADCHAN
-  /* Remove expired bad channels */
-  for (agline = badchan, a2gline = NULL; agline; agline = agline->next)
-  {
-    if (agline->expire <= TStime())
-    {
-      free_gline(agline, a2gline);
-      agline = a2gline ? a2gline : badchan;
-      if (!agline)
-        break;
-      continue;
-    }
-    a2gline = agline;
-  }
-#endif
-
-
-  if (IsServer(cptr))
-  {
-    if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD))
-    {
-      if (parc < 3 || (*parv[2] != '-' && (parc < 5 || *parv[4] == '\0')))
-      {
-       sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0],
-           "GLINE");
-       return 0;
-      }
-
-      if (*parv[2] == '-')     /* add mode or delete mode? */
-       active = 0;
-      else
-       active = 1;
-
-      if (*parv[2] == '+' || *parv[2] == '-')
-       parv[2]++;              /* step past mode indicator */
-
-      /* forward the message appropriately */
-      if (!strCasediff(parv[1], "*"))  /* global! */
-       sendto_serv_butone(cptr, active ? ":%s GLINE %s +%s %s :%s" :
-           ":%s GLINE %s -%s", parv[0], parv[1], parv[2], parv[3], parv[4]);
-      else if ((
-#if 1
-         /*
-          * REMOVE THIS after all servers upgraded to 2.10.01 and
-          * Uworld uses a numeric too
-          */
-         (strlen(parv[1]) != 1 && !(acptr = FindClient(parv[1])))) ||
-         (strlen(parv[1]) == 1 &&
-#endif
-         !(acptr = FindNServer(parv[1]))))
-       return 0;               /* no such server/user exists; forget it */
-      else
-#if 1
-/*
- * REMOVE THIS after all servers upgraded to 2.10.01 and
- * Uworld uses a numeric too
- */
-      if (IsServer(acptr) || !MyConnect(acptr))
-#endif
-      {
-       sendto_one(acptr, active ? ":%s GLINE %s +%s %s :%s" :
-           ":%s GLINE %s -%s", parv[0], parv[1], parv[2], parv[3], parv[4]);   /* single destination */
-       return 0;               /* only the intended  destination
-                                  should add this gline */
-      }
-
-      if (!(host = strchr(parv[2], '@')))
-      {                                /* convert user@host */
-       user = "*";             /* no @'s; assume username is '*' */
-       host = parv[2];
-      }
-      else
-      {
-       user = parv[2];
-       *(host++) = '\0';       /* break up string at the '@' */
-      }
-      ip_mask = check_if_ipmask(host); /* Store this boolean */
-#ifdef BADCHAN
-      if(*host=='#' || *host == '&' || *host == '+')
-        gtype=1;               /* BAD CHANNEL GLINE */
-#endif
-
-      for (agline = (gtype)?badchan:gline, a2gline = NULL; agline; 
-           agline = agline->next)
-      {
-       if (!strCasediff(agline->name, user)
-           && !strCasediff(agline->host, host))
-         break;
-       a2gline = agline;
-      }
-
-      if (!active && agline)
-      {                                /* removing the gline */
-       /* notify opers */
-       sendto_op_mask(SNO_GLINE, "%s removing %s for %s@%s", parv[0],
-           gtype?"BADCHAN":"GLINE",agline->name, agline->host);
-
-#ifdef GPATH
-       write_log(GPATH, "# " TIME_T_FMT " %s removing %s for %s@%s\n",
-           TStime(), parv[0], gtype?"BADCHAN":"GLINE",agline->name, 
-            agline->host);
-#endif /* GPATH */
-
-       free_gline(agline, a2gline);    /* remove the gline */
-      }
-      else if (active)
-      {                                /* must be adding a gline */
-       expire = atoi(parv[3]) + TStime();      /* expire time? */
-       if (agline && agline->expire < expire)
-       {                       /* new expire time? */
-         /* yes, notify the opers */
-         sendto_op_mask(SNO_GLINE,
-             "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
-             parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host, 
-              expire);
-
-#ifdef GPATH
-         write_log(GPATH, "# " TIME_T_FMT " %s resetting expiration time "
-             "on %s for %s@%s to " TIME_T_FMT "\n",
-             TStime(), parv[0], gtype?"BADCHAN":"GLINE",
-               agline->name, agline->host, expire);
-#endif /* GPATH */
-
-         agline->expire = expire;      /* reset the expire time */
-       }
-       else if (!agline)
-       {                       /* create gline */
-         for (agline = gtype?badchan:gline; agline; agline = agline->next)
-           if (!mmatch(agline->name, user) &&
-               (ip_mask ? GlineIsIpMask(agline) : !GlineIsIpMask(agline)) &&
-               !mmatch(agline->host, host))
-             return 0;         /* found an existing G-line that matches */
-
-         /* add the line: */
-         add_gline(sptr, ip_mask, host, parv[4], user, expire, 0);
-       }
-      }
-    }
-  }
-  else if (parc < 2 || *parv[1] == '\0')
-  {
-    /* Not enough args and a user; list glines */
-    for (agline = gline; agline; agline = agline->next)
-      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0],
-         agline->name, agline->host, agline->expire, agline->reason,
-         GlineIsActive(agline) ? (GlineIsLocal(agline) ? " (local)" : "") :
-         " (Inactive)");
-    sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
-  }
-  else
-  {
-    int priv;
-
-#ifdef LOCOP_LGLINE
-    priv = IsAnOper(cptr);
-#else
-    priv = IsOper(cptr);
-#endif
-
-    if (priv)
-    {                          /* non-oper not permitted to change things */
-      if (*parv[1] == '-')
-      {                                /* oper wants to deactivate the gline */
-       active = 0;
-       parv[1]++;
-      }
-      else if (*parv[1] == '+')
-      {                                /* oper wants to activate inactive gline */
-       active = 1;
-       parv[1]++;
-      }
-      else
-       active = -1;
-
-      if (parc > 2)
-       expire = atoi(parv[2]) + TStime();      /* oper wants to reset
-                                                  expire TS */
-    }
-    else
-      active = -1;
-
-    if (!(host = strchr(parv[1], '@')))
-    {
-      user = "*";              /* no @'s; assume username is '*' */
-      host = parv[1];
-    }
-    else
-    {
-      user = parv[1];
-      *(host++) = '\0';                /* break up string at the '@' */
-    }
-    ip_mask = check_if_ipmask(host);   /* Store this boolean */
-#ifdef BADCHAN
-    if(*host=='#' || *host == '&' || *host == '+')
-#ifndef LOCAL_BADCHAN
-     return 0;
-#else
-     gtype=1;  /* BAD CHANNEL */
-#endif
-#endif
-
-    for (agline = gtype?badchan:gline, a2gline = NULL; agline; 
-      agline = agline->next)
-    {
-      if (!mmatch(agline->name, user) &&
-         (ip_mask ? GlineIsIpMask(agline) : !GlineIsIpMask(agline)) &&
-         !mmatch(agline->host, host))
-       break;
-      a2gline = agline;
-    }
-
-    if (!agline)
-    {
-#ifdef OPER_LGLINE
-      if (priv && active && expire > now)
-      {
-       /* Add local G-line */
-       if (parc < 4 || !strchr(parv[3], ' '))
-       {
-         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
-             me.name, parv[0], "GLINE");
-         return 0;
-       }
-       add_gline(sptr, ip_mask, host, parv[3], user, expire, 1);
-      }
-      else
-#endif
-       sendto_one(cptr, err_str(ERR_NOSUCHGLINE), me.name, parv[0], user,
-           host);
-
-      return 0;
-    }
-
-    if (expire <= agline->expire)
-      expire = 0;
-
-    if ((active == -1 ||
-       (active ? GlineIsActive(agline) : !GlineIsActive(agline))) &&
-       expire == 0)
-    {
-      /* oper wants a list of one gline only */
-      sendto_one(cptr, rpl_str(RPL_GLIST), me.name, parv[0], agline->name,
-         agline->host, agline->expire, agline->reason,
-         GlineIsActive(agline) ? "" : " (Inactive)");
-      sendto_one(cptr, rpl_str(RPL_ENDOFGLIST), me.name, parv[0]);
-      return 0;
-    }
-
-    if (active != -1 &&
-       (active ? !GlineIsActive(agline) : GlineIsActive(agline)))
-    {
-      if (active)              /* reset activation on gline */
-       SetActive(agline);
-#ifdef OPER_LGLINE
-      else if (GlineIsLocal(agline))
-      {
-       /* Remove local G-line */
-       sendto_op_mask(SNO_GLINE, "%s removed local %s for %s@%s",
-           parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host);
-#ifdef GPATH
-       write_log(GPATH, "# " TIME_T_FMT
-           " %s!%s@%s removed local %s for %s@%s\n",
-           TStime(), parv[0], cptr->user->username, cptr->user->host,
-           gtype?"BADCHAN":"GLINE",
-           agline->name, agline->host);
-#endif /* GPATH */
-       free_gline(agline, a2gline);    /* remove the gline */
-       return 0;
-      }
-#endif
-      else
-       ClearActive(agline);
-    }
-    else
-      active = -1;             /* for later sendto_ops and logging functions */
-
-    if (expire)
-      agline->expire = expire; /* reset expiration time */
-
-    /* inform the operators what's up */
-    if (active != -1)
-    {                          /* changing the activation */
-      sendto_op_mask(SNO_GLINE, !expire ? "%s %sactivating %s for %s@%s" :
-         "%s %sactivating %s for %s@%s and "
-         "resetting expiration time to " TIME_T_FMT,
-         parv[0], active ? "re" : "de", gtype?"BADCHAN":"GLINE",agline->name,
-         agline->host, agline->expire);
-#ifdef GPATH
-      write_log(GPATH, !expire ? "# " TIME_T_FMT " %s!%s@%s %sactivating "
-         "%s for %s@%s\n" : "# " TIME_T_FMT " %s!%s@%s %sactivating %s "
-         "for %s@%s and resetting expiration time to " TIME_T_FMT "\n",
-         TStime(), parv[0], cptr->user->username, cptr->user->host,
-         active ? "re" : "de", gtype?"BADCHAN":"GLINE",agline->name, 
-          agline->host, agline->expire);
-#endif /* GPATH */
-
-    }
-    else if (expire)
-    {                          /* changing only the expiration */
-      sendto_op_mask(SNO_GLINE,
-         "%s resetting expiration time on %s for %s@%s to " TIME_T_FMT,
-         parv[0], gtype?"BADCHAN":"GLINE",agline->name, agline->host, 
-          agline->expire);
-#ifdef GPATH
-      write_log(GPATH, "# " TIME_T_FMT " %s!%s@%s resetting expiration "
-         "time on %s for %s@%s to " TIME_T_FMT "\n", TStime(), parv[0],
-         cptr->user->username, cptr->user->host,gtype?"BADCHAN":"GLINE",
-         agline->name, agline->host, agline->expire);
-#endif /* GPATH */
-    }
-  }
-
-  return 0;
-}
diff --git a/ircd/os_bsd.c b/ircd/os_bsd.c
new file mode 100644 (file)
index 0000000..4a43fa1
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * IRC - Internet Relay Chat, ircd/os_generic.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ */
+#include "ircd_osdep.h"
+#include "config.h"
+
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#ifdef HPUX
+#include <sys/syscall.h>
+#define getrusage(a,b) syscall(SYS_GETRUSAGE, a, b)
+#endif
+
+/*
+ * 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
+ */
+int os_get_rusage(struct Client *cptr, int uptime, EnumFn enumerator)
+{
+  char buf[256];
+#ifdef HAVE_GETRUSAGE
+  struct rusage rus;
+  time_t secs;
+
+#ifdef  hz
+#  define hzz hz
+#else
+#  ifdef HZ
+#    define hzz HZ
+#  else
+  int hzz = 1;
+#  ifdef HPUX
+  hzz = sysconf(_SC_CLK_TCK);
+#  endif
+#endif
+#endif
+
+  assert(0 != enumerator);
+  if (getrusage(RUSAGE_SELF, &rus) == -1)
+    return 0;
+
+  secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+  if (secs == 0)
+    secs = 1;
+
+  sprintf(buf, "CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
+          secs / 60, secs % 60,
+          rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
+          rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "RSS %ld ShMem %ld Data %ld Stack %ld",
+          rus.ru_maxrss,
+          rus.ru_ixrss / (uptime * hzz), rus.ru_idrss / (uptime * hzz),
+          rus.ru_isrss / (uptime * hzz));
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Swaps %ld Reclaims %ld Faults %ld",
+          rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
+  (*enumerator)(cptr, buf);
+  
+  sprintf(buf, "Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Signals %ld Context Vol. %ld Invol %ld",
+          rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
+  (*enumerator)(cptr, buf);
+
+#else /* HAVE_GETRUSAGE */
+#if HAVE_TIMES
+  struct tms tmsbuf;
+  time_t secs, mins;
+  int hzz = 1, ticpermin;
+  int umin, smin, usec, ssec;
+
+  assert(0 != enumerator);
+#ifdef HPUX
+  hzz = sysconf(_SC_CLK_TCK);
+#endif
+  ticpermin = hzz * 60;
+
+  umin = tmsbuf.tms_utime / ticpermin;
+  usec = (tmsbuf.tms_utime % ticpermin) / (float)hzz;
+  smin = tmsbuf.tms_stime / ticpermin;
+  ssec = (tmsbuf.tms_stime % ticpermin) / (float)hzz;
+  secs = usec + ssec;
+  mins = (secs / 60) + umin + smin;
+  secs %= hzz;
+
+  if (times(&tmsbuf) == -1)
+    return 0;
+  secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
+
+  sprintf(buf, "CPU Secs %d:%d User %d:%d System %d:%d", 
+          mins, secs, umin, usec, smin, ssec);
+  (*enumerator)(cptr, buf);
+#endif /* HAVE_TIMES */
+#endif /* HAVE_GETRUSAGE */
+  return 1;
+}
+
+int os_get_sockerr(int fd)
+{
+  int    err = 0;
+#if defined(SO_ERROR)
+  size_t len = sizeof(err);
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
+#endif
+  return err;
+}
+
+/*
+ * set_non_blocking
+ *
+ * Set the client connection into non-blocking mode. If your
+ * system doesn't support this, you can make this a dummy
+ * function (and get all the old problems that plagued the
+ * blocking version of IRC--not a problem if you are a
+ * lightly loaded node...)
+ */
+int os_set_nonblocking(int fd)
+{
+  int res;
+#ifndef NBLOCK_SYSV
+  int nonb = 0;
+#endif
+
+  /*
+   * NOTE: consult ALL your relevant manual pages *BEFORE* changing
+   * these ioctl's. There are quite a few variations on them,
+   * as can be seen by the PCS one. They are *NOT* all the same.
+   * Heed this well. - Avalon.
+   */
+#ifdef  NBLOCK_POSIX
+  nonb |= O_NONBLOCK;
+#endif
+#ifdef  NBLOCK_BSD
+  nonb |= O_NDELAY;
+#endif
+#ifdef  NBLOCK_SYSV
+  /* This portion of code might also apply to NeXT. -LynX */
+  res = 1;
+
+  if (ioctl(fd, FIONBIO, &res) == -1)
+    return 0;
+#else
+  if ((res = fcntl(fd, F_GETFL, 0)) == -1)
+    return 0;
+  else if (fcntl(fd, F_SETFL, res | nonb) == -1)
+    return 0;
+#endif
+  return 1;
+}
+
+
+/*
+ *  set_sock_opts
+ */
+int os_set_reuseaddr(int fd)
+{
+  size_t opt = 1;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
+                          (const char*) &opt, sizeof(opt)));
+}
+
+int os_set_sockbufs(int fd, unsigned int size)
+{
+  size_t opt = size;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 
+                          (const char*) &opt, sizeof(opt)) &&
+          0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 
+                          (const char*) &opt, sizeof(opt)));
+}
+
+int os_disable_options(int fd)
+{
+#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
+#else
+  return 1;
+#endif
+}
+
+/*
+ * Try and find the correct name to use with getrlimit() for setting the max.
+ * number of files allowed to be open by this process.
+ */
+#ifdef RLIMIT_FDMAX
+#define RLIMIT_FD_MAX   RLIMIT_FDMAX
+#else
+#ifdef RLIMIT_NOFILE
+#define RLIMIT_FD_MAX RLIMIT_NOFILE
+#else
+#ifdef RLIMIT_OPEN_MAX
+#define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+#else
+#undef RLIMIT_FD_MAX
+#endif
+#endif
+#endif
+
+int os_set_fdlimit(unsigned int max_descriptors)
+{
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX)
+  struct rlimit limit;
+
+  if (!getrlimit(RLIMIT_FD_MAX, &limit)) {
+    if (limit.rlim_max < MAXCONNECTIONS)
+      return limit.rlim_max;
+    limit.rlim_cur = limit.rlim_max;    /* make soft limit the max */
+    return setrlimit(RLIMIT_FD_MAX, &limit);
+  }
+#endif /* defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX) */
+  return 0;
+}
+
+IOResult os_recv_nonb(int fd, char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (0 < (res = recv(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (res < 0) {
+    if (EWOULDBLOCK == errno || EAGAIN == errno)
+      return IO_BLOCKED;
+    else
+      return IO_FAILURE;
+  } 
+  /*
+   * 0   == client closed the connection
+   * < 1 == error
+   */
+  return IO_FAILURE;
+}
+
+IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int length, 
+                          unsigned int* length_out, struct sockaddr_in* sin_out)
+{
+  int    res;
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != buf);
+  assert(0 != length_out);
+  assert(0 != sin_out);
+  errno = 0;
+  *length_out = 0;
+
+  res = recvfrom(fd, buf, length, 0, (struct sockaddr*) sin_out, &len);
+  if (-1 == res) {
+    if (EWOULDBLOCK == errno || ENOMEM == errno)
+      return IO_BLOCKED;
+    return IO_FAILURE;
+  }
+  *length_out = res;
+  return IO_SUCCESS;
+}
+
+IOResult os_send_nonb(int fd, const char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (-1 < (res = send(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EWOULDBLOCK == errno || EAGAIN == errno || 
+           ENOMEM == errno || ENOBUFS == errno)
+    return IO_BLOCKED;
+  return IO_FAILURE;
+}
+
+int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+{
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
+    if (errno != EINPROGRESS)
+      return 0;
+  }
+  return 1;
+}
+      
+int os_get_sockname(int fd, struct sockaddr_in* sin_out)
+{
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getsockname(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_get_peername(int fd, struct sockaddr_in* sin_out)
+{
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getpeername(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_set_listen(int fd, int backlog)
+{
+  return (0 == listen(fd, backlog));
+}
+
+
diff --git a/ircd/os_generic.c b/ircd/os_generic.c
new file mode 100644 (file)
index 0000000..7f778db
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * IRC - Internet Relay Chat, ircd/os_generic.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ */
+#include "ircd_osdep.h"
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#if 0
+#include <unistd.h>
+#endif
+
+#ifdef HPUX
+#include <sys/syscall.h>
+#define getrusage(a,b) syscall(SYS_GETRUSAGE, a, b)
+#endif
+
+/*
+ * 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
+ */
+int os_get_rusage(struct Client *cptr, int uptime, EnumFn enumerator)
+{
+  char buf[256];
+#ifdef HAVE_GETRUSAGE
+  struct rusage rus;
+  time_t secs;
+
+#ifdef  hz
+#  define hzz hz
+#else
+#  ifdef HZ
+#    define hzz HZ
+#  else
+  int hzz = 1;
+#  ifdef HPUX
+  hzz = sysconf(_SC_CLK_TCK);
+#  endif
+#endif
+#endif
+
+  assert(0 != enumerator);
+  if (getrusage(RUSAGE_SELF, &rus) == -1)
+    return 0;
+
+  secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+  if (secs == 0)
+    secs = 1;
+
+  sprintf(buf, "CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
+          secs / 60, secs % 60,
+          rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
+          rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "RSS %ld ShMem %ld Data %ld Stack %ld",
+          rus.ru_maxrss,
+          rus.ru_ixrss / (uptime * hzz), rus.ru_idrss / (uptime * hzz),
+          rus.ru_isrss / (uptime * hzz));
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Swaps %ld Reclaims %ld Faults %ld",
+          rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
+  (*enumerator)(cptr, buf);
+  
+  sprintf(buf, "Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Signals %ld Context Vol. %ld Invol %ld",
+          rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
+  (*enumerator)(cptr, buf);
+
+#else /* HAVE_GETRUSAGE */
+#if HAVE_TIMES
+  struct tms tmsbuf;
+  time_t secs, mins;
+  int hzz = 1, ticpermin;
+  int umin, smin, usec, ssec;
+
+  assert(0 != enumerator);
+#ifdef HPUX
+  hzz = sysconf(_SC_CLK_TCK);
+#endif
+  ticpermin = hzz * 60;
+
+  umin = tmsbuf.tms_utime / ticpermin;
+  usec = (tmsbuf.tms_utime % ticpermin) / (float)hzz;
+  smin = tmsbuf.tms_stime / ticpermin;
+  ssec = (tmsbuf.tms_stime % ticpermin) / (float)hzz;
+  secs = usec + ssec;
+  mins = (secs / 60) + umin + smin;
+  secs %= hzz;
+
+  if (times(&tmsbuf) == -1)
+    return 0;
+  secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
+
+  sprintf(buf, "CPU Secs %d:%d User %d:%d System %d:%d", 
+          mins, secs, umin, usec, smin, ssec);
+  (*enumerator)(cptr, buf);
+#endif /* HAVE_TIMES */
+#endif /* HAVE_GETRUSAGE */
+  return 1;
+}
+
+int os_get_sockerr(int fd)
+{
+  int    err = 0;
+#if defined(SO_ERROR)
+  size_t len = sizeof(err);
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
+#endif
+  return err;
+}
+
+/*
+ * set_non_blocking
+ *
+ * Set the client connection into non-blocking mode. If your
+ * system doesn't support this, you can make this a dummy
+ * function (and get all the old problems that plagued the
+ * blocking version of IRC--not a problem if you are a
+ * lightly loaded node...)
+ */
+int os_set_nonblocking(int fd)
+{
+  int res;
+#ifndef NBLOCK_SYSV
+  int nonb = 0;
+#endif
+
+  /*
+   * NOTE: consult ALL your relevant manual pages *BEFORE* changing
+   * these ioctl's. There are quite a few variations on them,
+   * as can be seen by the PCS one. They are *NOT* all the same.
+   * Heed this well. - Avalon.
+   */
+#ifdef  NBLOCK_POSIX
+  nonb |= O_NONBLOCK;
+#endif
+#ifdef  NBLOCK_BSD
+  nonb |= O_NDELAY;
+#endif
+#ifdef  NBLOCK_SYSV
+  /* This portion of code might also apply to NeXT. -LynX */
+  res = 1;
+
+  if (ioctl(fd, FIONBIO, &res) == -1)
+    return 0;
+#else
+  if ((res = fcntl(fd, F_GETFL, 0)) == -1)
+    return 0;
+  else if (fcntl(fd, F_SETFL, res | nonb) == -1)
+    return 0;
+#endif
+  return 1;
+}
+
+
+/*
+ *  set_sock_opts
+ */
+int os_set_reuseaddr(int fd)
+{
+  size_t opt = 1;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
+                          (const char*) &opt, sizeof(opt)));
+}
+
+int os_set_sockbufs(int fd, unsigned int size)
+{
+  size_t opt = size;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 
+                          (const char*) &opt, sizeof(opt)) &&
+          0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 
+                          (const char*) &opt, sizeof(opt)));
+}
+
+int os_disable_options(int fd)
+{
+#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
+#else
+  return 1;
+#endif
+}
+
+/*
+ * Try and find the correct name to use with getrlimit() for setting the max.
+ * number of files allowed to be open by this process.
+ */
+#ifdef RLIMIT_FDMAX
+#define RLIMIT_FD_MAX   RLIMIT_FDMAX
+#else
+#ifdef RLIMIT_NOFILE
+#define RLIMIT_FD_MAX RLIMIT_NOFILE
+#else
+#ifdef RLIMIT_OPEN_MAX
+#define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
+#else
+#undef RLIMIT_FD_MAX
+#endif
+#endif
+#endif
+
+int os_set_fdlimit(unsigned int max_descriptors)
+{
+#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX)
+  struct rlimit limit;
+
+  if (!getrlimit(RLIMIT_FD_MAX, &limit)) {
+    if (limit.rlim_max < MAXCONNECTIONS)
+      return limit.rlim_max;
+    limit.rlim_cur = limit.rlim_max;    /* make soft limit the max */
+    return setrlimit(RLIMIT_FD_MAX, &limit);
+  }
+#endif /* defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX) */
+  return 0;
+}
+
+IOResult os_recv_nonb(int fd, char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (0 < (res = recv(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (res < 0) {
+    if (EWOULDBLOCK == errno || EAGAIN == errno)
+      return IO_BLOCKED;
+    else
+      return IO_FAILURE;
+  } 
+  /*
+   * 0   == client closed the connection
+   * < 1 == error
+   */
+  return IO_FAILURE;
+}
+
+IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int length, 
+                          unsigned int* length_out, struct sockaddr_in* sin_out)
+{
+  int    res;
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != buf);
+  assert(0 != length_out);
+  assert(0 != sin_out);
+  errno = 0;
+
+  res = recvfrom(fd, buf, length, 0, (struct sockaddr*) sin_out, &len);
+  if (-1 == res) {
+    if (EWOULDBLOCK == errno || ENOMEM == errno)
+      return IO_BLOCKED;
+    return IO_FAILURE;
+  }
+  *length_out = res;
+  return IO_SUCCESS;
+}
+
+IOResult os_send_nonb(int fd, const char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (-1 < (res = send(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EWOULDBLOCK == errno || EAGAIN == errno || 
+           ENOMEM == errno || ENOBUFS == errno)
+    return IO_BLOCKED;
+  return IO_FAILURE;
+}
+
+int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+{
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
+    if (errno != EINPROGRESS)
+      return 0;
+  }
+  return 1;
+}
+      
+int os_get_sockname(int fd, struct sockaddr_in* sin_out)
+{
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getsockname(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_get_peername(int fd, struct sockaddr_in* sin_out)
+{
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getpeername(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_set_listen(int fd, int backlog)
+{
+  return (0 == listen(fd, backlog));
+}
+
+
diff --git a/ircd/os_linux.c b/ircd/os_linux.c
new file mode 100644 (file)
index 0000000..c2701d2
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * IRC - Internet Relay Chat, ircd/os_linux.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ */
+#include "ircd_osdep.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <sys/param.h>
+#if 0
+#include <unistd.h>
+#endif
+
+/*
+ * 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
+ */
+int os_get_rusage(struct Client *cptr, int uptime, EnumFn enumerator)
+{
+  char buf[256];
+  struct rusage rus;
+  struct tms tmsbuf;
+  time_t secs;
+  time_t mins;
+  int umin;
+  int smin;
+  int usec;
+  int ssec;
+  int ticpermin = HZ * 60;
+  unsigned int tick_count = uptime * HZ;
+
+  if (0 == tick_count)
+    ++tick_count;
+
+  assert(0 != enumerator);
+  if (getrusage(RUSAGE_SELF, &rus) == -1)
+    return 0;
+
+  secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+  if (secs == 0)
+    secs = 1;
+
+  sprintf(buf, "CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
+          secs / 60, secs % 60,
+          rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
+          rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "RSS %ld ShMem %ld Data %ld Stack %ld",
+          rus.ru_maxrss,
+          rus.ru_ixrss / tick_count, rus.ru_idrss / tick_count,
+          rus.ru_isrss / tick_count);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Swaps %ld Reclaims %ld Faults %ld",
+          rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
+  (*enumerator)(cptr, buf);
+  
+  sprintf(buf, "Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Signals %ld Context Vol. %ld Invol %ld",
+          rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
+  (*enumerator)(cptr, buf);
+
+  if (times(&tmsbuf) == -1)
+    return 0;
+
+  umin = tmsbuf.tms_utime / ticpermin;
+  usec = (tmsbuf.tms_utime % ticpermin) / (float)HZ;
+  smin = tmsbuf.tms_stime / ticpermin;
+  ssec = (tmsbuf.tms_stime % ticpermin) / (float)HZ;
+  secs = usec + ssec;
+  mins = (secs / 60) + umin + smin;
+  secs %= HZ;
+
+  sprintf(buf, "CPU Secs %ld:%ld User %d:%d System %d:%d", 
+          mins, secs, umin, usec, smin, ssec);
+  (*enumerator)(cptr, buf);
+  return 1;
+}
+
+int os_get_sockerr(int fd)
+{
+  int    err = 0;
+  size_t len = sizeof(err);
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
+  return err;
+}
+
+/*
+ * set_non_blocking
+ *
+ * Set the client connection into non-blocking mode. If your
+ * system doesn't support this, you can make this a dummy
+ * function (and get all the old problems that plagued the
+ * blocking version of IRC--not a problem if you are a
+ * lightly loaded node...)
+ */
+int os_set_nonblocking(int fd)
+{
+  int res = 1;
+  return (0 == ioctl(fd, FIONBIO, &res));
+}
+
+
+/*
+ *  set_sock_opts
+ */
+int os_set_reuseaddr(int fd)
+{
+  size_t opt = 1;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)));
+}
+
+int os_set_sockbufs(int fd, unsigned int size)
+{
+  size_t opt = size;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) &&
+          0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)));
+}
+
+int os_disable_options(int fd)
+{
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
+}
+
+int os_set_fdlimit(unsigned int max_descriptors)
+{
+  struct rlimit limit;
+
+  if (!getrlimit(RLIMIT_NOFILE, &limit)) {
+    if (limit.rlim_max < max_descriptors)
+      return limit.rlim_max;
+    limit.rlim_cur = limit.rlim_max;    /* make soft limit the max */
+    return setrlimit(RLIMIT_NOFILE, &limit);
+  }
+  return 0;
+}
+
+/*
+ * os_recv_nonb - non blocking read of a connection
+ * returns:
+ *  1  if data was read or socket is blocked (recoverable error)
+ *    count_out > 0 if data was read
+ *   
+ *  0  if socket closed from other end
+ *  -1 if an unrecoverable error occurred
+ */
+IOResult os_recv_nonb(int fd, char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (0 < (res = recv(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (res < 0) {
+    if (EWOULDBLOCK == errno || EAGAIN == errno)
+      return IO_BLOCKED;
+    else
+      return IO_FAILURE;
+  } 
+  /*
+   * 0   == client closed the connection
+   * < 1 == error
+   */
+  return IO_FAILURE;
+}
+
+IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int length, 
+                          unsigned int* length_out, struct sockaddr_in* sin_out)
+{
+  int    res;
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != buf);
+  assert(0 != length_out);
+  assert(0 != sin_out);
+  errno = 0;
+
+  res = recvfrom(fd, buf, length, 0, (struct sockaddr*) sin_out, &len);
+  if (-1 == res) {
+    if (EWOULDBLOCK == errno || ENOMEM == errno)
+      return IO_BLOCKED;
+    return IO_FAILURE;
+  }
+  *length_out = res;
+  return IO_SUCCESS;
+}
+
+/*
+ * os_send_nonb - non blocking read of a connection
+ * returns:
+ *  1  if data was written
+ *    count_out contains amount written
+ *   
+ *  0  if write call blocked, recoverable error
+ *  -1 if an unrecoverable error occurred
+ */
+IOResult os_send_nonb(int fd, const char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (-1 < (res = send(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EAGAIN == errno || ENOMEM == errno || ENOBUFS == errno)
+    return IO_BLOCKED;
+
+  return IO_FAILURE;
+}
+
+
+int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+{
+  if (connect(fd, (const struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
+    if (errno != EINPROGRESS)
+      return 0;
+  }
+  return 1;
+}
+      
+int os_get_sockname(int fd, struct sockaddr_in* sin_out)
+{
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getsockname(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_get_peername(int fd, struct sockaddr_in* sin_out)
+{
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getpeername(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_set_listen(int fd, int backlog)
+{
+  /*
+   * for linux 2.2 backlog is the number of connections ready to be accepted
+   * not the max syn requests, there is a kernel tweak there to set the max
+   * syn request queue length
+   */
+  return (0 == listen(fd, backlog));
+}
+
diff --git a/ircd/os_solaris.c b/ircd/os_solaris.c
new file mode 100644 (file)
index 0000000..59cdbbe
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * IRC - Internet Relay Chat, ircd/os_solaris.c
+ * Copyright (C) 1999 Thomas Helvey
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ */
+#include "ircd_osdep.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/filio.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/*
+ * 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
+ */
+int os_get_rusage(struct Client *cptr, int uptime, EnumFn enumerator)
+{
+  char buf[256];
+  struct rusage rus;
+  time_t secs;
+  int    hz = HZ;
+  int    upticks = uptime * hz;
+
+  assert(0 != enumerator);
+  if (getrusage(RUSAGE_SELF, &rus) == -1)
+    return 0;
+
+  secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+  if (secs == 0)
+    secs = 1;
+
+  sprintf(buf, "CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
+          secs / 60, secs % 60,
+          rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
+          rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "RSS %ld ShMem %ld Data %ld Stack %ld",
+          rus.ru_maxrss,
+          rus.ru_ixrss / upticks, rus.ru_idrss / upticks,
+          rus.ru_isrss / upticks);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Swaps %ld Reclaims %ld Faults %ld",
+          rus.ru_nswap, rus.ru_minflt, rus.ru_majflt);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Block in %ld out %ld", rus.ru_inblock, rus.ru_oublock);
+  (*enumerator)(cptr, buf);
+  
+  sprintf(buf, "Msg Rcv %ld Send %ld", rus.ru_msgrcv, rus.ru_msgsnd);
+  (*enumerator)(cptr, buf);
+
+  sprintf(buf, "Signals %ld Context Vol. %ld Invol %ld",
+          rus.ru_nsignals, rus.ru_nvcsw, rus.ru_nivcsw);
+  (*enumerator)(cptr, buf);
+
+  return 1;
+}
+
+int os_get_sockerr(int fd)
+{
+  int err = 0;
+  int len = sizeof(err);
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*) &err, &len);
+}
+
+/*
+ * set_non_blocking
+ *
+ * Set the client connection into non-blocking mode. If your
+ * system doesn't support this, you can make this a dummy
+ * function (and get all the old problems that plagued the
+ * blocking version of IRC--not a problem if you are a
+ * lightly loaded node...)
+ */
+int os_set_nonblocking(int fd)
+{
+  int res = 1;
+  return (0 == ioctl(fd, FIONBIO, &res));
+}
+
+/*
+ *  set_sock_opts
+ */
+int os_set_reuseaddr(int fd)
+{
+  size_t opt = 1;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
+                          (const char*) &opt, sizeof(opt)));
+}
+
+int os_set_sockbufs(int fd, unsigned int size)
+{
+  size_t opt = size;
+  return (0 == setsockopt(fd, SOL_SOCKET, SO_RCVBUF, 
+                          (const char*) &opt, sizeof(opt)) &&
+          0 == setsockopt(fd, SOL_SOCKET, SO_SNDBUF, 
+                          (const char*) &opt, sizeof(opt)));
+}
+
+int os_disable_options(int fd)
+{
+  return (0 == setsockopt(fd, IPPROTO_IP, IP_OPTIONS, NULL, 0));
+}
+
+int os_set_fdlimit(unsigned int max_descriptors)
+{
+  struct rlimit limit;
+
+  if (!getrlimit(RLIMIT_NOFILE, &limit)) {
+    if (limit.rlim_max < max_descriptors)
+      return limit.rlim_max;
+    limit.rlim_cur = limit.rlim_max;    /* make soft limit the max */
+    return setrlimit(RLIMIT_NOFILE, &limit);
+  }
+  return 0;
+}
+
+IOResult os_recv_nonb(int fd, char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (0 < (res = recv(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (res < 0) {
+    if (EAGAIN == errno || ENOBUFS == errno || 
+        ENOMEM == errno || ENOSR == errno)
+      return IO_BLOCKED;
+    else
+      return IO_FAILURE;
+  } 
+  /*
+   * 0   == client closed the connection
+   * < 1 == error
+   */
+  return IO_FAILURE;
+}
+
+IOResult os_recvfrom_nonb(int fd, char* buf, unsigned int length, 
+                          unsigned int* length_out, struct sockaddr_in* sin_out)
+{
+  int    res;
+  size_t len = sizeof(struct sockaddr_in);
+  assert(0 != buf);
+  assert(0 != length_out);
+  assert(0 != sin_out);
+  errno = 0;
+
+  res = recvfrom(fd, buf, length, 0, (struct sockaddr*) sin_out, &len);
+  if (-1 == res) {
+    if (EAGAIN == errno || ENOBUFS == errno || 
+        ENOMEM == errno || ENOSR == errno)
+      return IO_BLOCKED;
+    return IO_FAILURE;
+  }
+  *length_out = res;
+  return IO_SUCCESS;
+}
+
+IOResult os_send_nonb(int fd, const char* buf, unsigned int length, 
+                 unsigned int* count_out)
+{
+  int res;
+  assert(0 != buf);
+  assert(0 != count_out);
+  *count_out = 0;
+  errno = 0;
+
+  if (-1 < (res = send(fd, buf, length, 0))) {
+    *count_out = (unsigned) res;
+    return IO_SUCCESS;
+  }
+  else if (EAGAIN == errno || ENOBUFS == errno || 
+           ENOMEM == errno || ENOSR == errno)
+    return IO_BLOCKED;
+
+  return IO_FAILURE;
+}
+
+int os_connect_nonb(int fd, const struct sockaddr_in* sin)
+{
+  if (connect(fd, (struct sockaddr*) sin, sizeof(struct sockaddr_in))) {
+    if (errno != EINPROGRESS)
+      return 0;
+  }
+  return 1;
+}
+      
+int os_get_sockname(int fd, struct sockaddr_in* sin_out)
+{
+  int len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getsockname(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_get_peername(int fd, struct sockaddr_in* sin_out)
+{
+  int len = sizeof(struct sockaddr_in);
+  assert(0 != sin_out);
+  return (0 == getpeername(fd, (struct sockaddr*) sin_out, &len));
+}
+
+int os_set_listen(int fd, int backlog)
+{
+  return (0 == listen(fd, backlog));
+}
+
index e4ef0dc9df71d787583674f817786ccdd9a3fafa..e167f7960703a524c2f61a2490da8ee666432eb5 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
-#include "s_misc.h"
-#include "s_bsd.h"
+#include "packet.h"
+#include "client.h"
 #include "ircd.h"
-#include "msg.h"
+#include "ircd_chattr.h"
 #include "parse.h"
+#include "s_bsd.h"
+#include "s_misc.h"
 #include "send.h"
-#include "packet.h"
-#include "s_serv.h"
 
 #include <assert.h>
 
-RCSTAG_CC("$Id$");
+static void update_bytes_received(struct Client* cptr, size_t length)
+{
+  me.receiveB    += length;     /* Update bytes received */
+  cptr->receiveB += length;
+
+  if (cptr->receiveB > 1023) {
+    cptr->receiveK += (cptr->receiveB >> 10);
+    cptr->receiveB &= 0x03ff;   /* 2^10 = 1024, 3ff = 1023 */
+  }
+  if (me.receiveB > 1023) {
+    me.receiveK += (me.receiveB >> 10);
+    me.receiveB &= 0x03ff;
+  }
+}
+
+static void update_messages_received(struct Client* cptr)
+{
+  ++me.receiveM;
+  ++cptr->receiveM;
+}
 
 /*
  * dopacket
@@ -47,41 +64,22 @@ RCSTAG_CC("$Id$");
  *    with cptr of "local" variation, which contains all the
  *    necessary fields (buffer etc..)
  */
-int dopacket(aClient *cptr, char *buffer, int length)
+int server_dopacket(struct Client* cptr, const char* buffer, int length)
 {
-  Reg1 char *ch1;
-  Reg2 char *ch2;
-  register char *cptrbuf;
-  aClient *acpt = cptr->acpt;
+  const char* src;
+  char*       endp;
+  char*       client_buffer;
+  
+  assert(0 != cptr);
 
-  cptrbuf = cptr->buffer;
-  me.receiveB += length;       /* Update bytes received */
-  cptr->receiveB += length;
-  if (cptr->receiveB > 1023)
-  {
-    cptr->receiveK += (cptr->receiveB >> 10);
-    cptr->receiveB &= 0x03ff;  /* 2^10 = 1024, 3ff = 1023 */
-  }
-  if (acpt != &me)
-  {
-    acpt->receiveB += length;
-    if (acpt->receiveB > 1023)
-    {
-      acpt->receiveK += (acpt->receiveB >> 10);
-      acpt->receiveB &= 0x03ff;
-    }
-  }
-  else if (me.receiveB > 1023)
-  {
-    me.receiveK += (me.receiveB >> 10);
-    me.receiveB &= 0x03ff;
-  }
-  ch1 = cptrbuf + cptr->count;
-  ch2 = buffer;
-  while (--length >= 0)
-  {
-    register char g;
-    g = (*ch1 = *ch2++);
+  update_bytes_received(cptr, length);
+
+  client_buffer = cptr->buffer;
+  endp = client_buffer + cptr->count;
+  src = buffer;
+
+  while (length-- > 0) {
+    *endp = *src++;
     /*
      * Yuck.  Stuck.  To make sure we stay backward compatible,
      * we must assume that either CR or LF terminates the message
@@ -89,65 +87,45 @@ int dopacket(aClient *cptr, char *buffer, int length)
      * of messages, backward compatibility is lost and major
      * problems will arise. - Avalon
      */
-    if (g < '\16' && (g == '\n' || g == '\r'))
-    {
-      if (ch1 == cptrbuf)
-       continue;               /* Skip extra LF/CR's */
-      *ch1 = '\0';
-      me.receiveM += 1;                /* Update messages received */
-      cptr->receiveM += 1;
-      if (cptr->acpt != &me)
-       cptr->acpt->receiveM += 1;
-      if (IsServer(cptr))
-      {
-       if (parse_server(cptr, cptr->buffer, ch1) == CPTR_KILLED)
-         return CPTR_KILLED;
-      }
-      else if (parse_client(cptr, cptr->buffer, ch1) == CPTR_KILLED)
-       return CPTR_KILLED;
+    if (IsEol(*endp)) {
+      if (endp == client_buffer)
+        continue;               /* Skip extra LF/CR's */
+      *endp = '\0';
+
+      update_messages_received(cptr);
+
+      if (parse_server(cptr, cptr->buffer, endp) == CPTR_KILLED)
+        return CPTR_KILLED;
       /*
        *  Socket is dead so exit
        */
       if (IsDead(cptr))
-       return exit_client(cptr, cptr, &me, LastDeadComment(cptr));
-      ch1 = cptrbuf;
+        return exit_client(cptr, cptr, &me, LastDeadComment(cptr));
+      endp = client_buffer;
     }
-    else if (ch1 < cptrbuf + (sizeof(cptr->buffer) - 1))
-      ch1++;                   /* There is always room for the null */
+    else if (endp < client_buffer + BUFSIZE)
+      ++endp;                   /* There is always room for the null */
   }
-  cptr->count = ch1 - cptr->buffer;
-  return 0;
+  cptr->count = endp - cptr->buffer;
+  return 1;
 }
 
 /*
  * client_dopacket - handle client messages
  */
-int client_dopacket(aClient *cptr, size_t length)
+int client_dopacket(struct Client *cptr, size_t length)
 {
   assert(0 != cptr);
 
-  me.receiveB += length;       /* Update bytes received */
-  cptr->receiveB += length;
-
-  if (cptr->receiveB > 1023)
-  {
-    cptr->receiveK += (cptr->receiveB >> 10);
-    cptr->receiveB &= 0x03ff;  /* 2^10 = 1024, 3ff = 1023 */
-  }
-  if (me.receiveB > 1023)
-  {
-    me.receiveK += (me.receiveB >> 10);
-    me.receiveB &= 0x03ff;
-  }
-  cptr->count = 0;
-
-  ++me.receiveM;               /* Update messages received */
-  ++cptr->receiveM;
+  update_bytes_received(cptr, length);
+  update_messages_received(cptr);
 
   if (CPTR_KILLED == parse_client(cptr, cptr->buffer, cptr->buffer + length))
     return CPTR_KILLED;
   else if (IsDead(cptr))
     return exit_client(cptr, cptr, &me, LastDeadComment(cptr));
 
-  return 0;
+  return 1;
 }
+
+
index aa8ebc75837d419e7968c6b351867d5199a19a74..82c0c3af4f2278032ed6385549cb1a4e3cee77e6 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
-#include "s_serv.h"
-#include "send.h"
 #include "parse.h"
-#include "common.h"
-#include "s_bsd.h"
-#include "msg.h"
-#include "s_user.h"
-#include "s_serv.h"
+#include "client.h"
 #include "channel.h"
-#include "whowas.h"
-#include "s_ping.h"
-#include "s_conf.h"
-#include "res.h"
-#include "map.h"
+#include "handlers.h"
 #include "hash.h"
-#include "numeric.h"
 #include "ircd.h"
-#include "s_misc.h"
-#include "common.h"
-#include "s_numeric.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
+#include "map.h"
+#include "msg.h"
+#include "numeric.h"
 #include "numnicks.h"
 #include "opercmds.h"
 #include "querycmds.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_numeric.h"
+#include "s_user.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
 #include "whocmds.h"
+#include "whowas.h"
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+
+struct MessageTree {
+  char *final;
+  struct Message *msg;
+  struct MessageTree *pointers[26];
+};
+
+
+struct Message msgtab[] = {
+  {
+    MSG_PRIVATE,
+    TOK_PRIVATE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_privmsg, ms_privmsg, mo_privmsg, m_ignore }
+  },
+  {
+    MSG_NICK,
+    TOK_NICK,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_nick, m_nick, ms_nick, m_nick, m_ignore }
+  },
+  {
+    MSG_NOTICE,
+    TOK_NOTICE,
+    0, MAXPARA, MFLG_SLOW | MFLG_IGNORE, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_notice, ms_notice, mo_notice, m_ignore }
+  },
+  {
+    MSG_WALLCHOPS,
+    TOK_WALLCHOPS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_wallchops, ms_wallchops, m_wallchops, m_ignore }
+  },
+  {
+    MSG_CPRIVMSG,
+    TOK_CPRIVMSG,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_cprivmsg, m_ignore, m_cprivmsg, m_ignore }
+  },
+  {
+    MSG_CNOTICE,
+    TOK_CNOTICE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_cnotice, m_ignore, m_cnotice, m_ignore }
+  },
+  {
+    MSG_JOIN,
+    TOK_JOIN,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_join, ms_join, m_join, m_ignore }
+  },
+  {
+    MSG_MODE,
+    TOK_MODE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_mode, ms_mode, m_mode, m_ignore }
+  },
+  {
+    MSG_BURST,
+    TOK_BURST,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_burst, m_ignore, m_ignore }
+  },
+  {
+    MSG_CREATE,
+    TOK_CREATE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_create, m_ignore, m_ignore }
+  },
+  {
+    MSG_DESTRUCT,
+    TOK_DESTRUCT,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_destruct, m_ignore, m_ignore }
+  },
+  {
+    MSG_QUIT,
+    TOK_QUIT,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_quit, m_quit, ms_quit, m_quit, m_ignore }
+  },
+  {
+    MSG_PART,
+    TOK_PART,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_part, ms_part, m_part, m_ignore }
+  },
+  {
+    MSG_TOPIC,
+    TOK_TOPIC,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_topic, ms_topic, m_topic, m_ignore }
+  },
+  {
+    MSG_INVITE,
+    TOK_INVITE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_invite, ms_invite, m_invite, m_ignore }
+  },
+  {
+    MSG_KICK,
+    TOK_KICK,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_kick, ms_kick, m_kick, m_ignore }
+  },
+  {
+    MSG_WALLOPS,
+    TOK_WALLOPS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_wallops, mo_wallops, m_ignore }
+  },
+  {
+    MSG_DESYNCH,
+    TOK_DESYNCH,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_desynch, m_ignore, m_ignore }
+  },
+  {
+    MSG_PING,
+    TOK_PING,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ping, ms_ping, m_ping, m_ignore }
+  },
+  {
+    MSG_PONG,
+    TOK_PONG,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_pong, m_ignore, ms_pong, m_ignore, m_ignore }
+  },
+  {
+    MSG_ERROR,
+    TOK_ERROR,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_error, m_ignore, ms_error, m_ignore, m_ignore }
+  },
+  {
+    MSG_KILL,
+    TOK_KILL,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_kill, mo_kill, m_ignore }
+  },
+  {
+    MSG_USER,
+    TOK_USER,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_user, m_registered, m_ignore, m_registered, m_ignore }
+  },
+  {
+    MSG_AWAY,
+    TOK_AWAY,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_away, ms_away, m_away, m_ignore }
+  },
+  {
+    MSG_ISON,
+    TOK_ISON,
+    0, 1, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ison, m_ignore, m_ison, m_ignore }
+  },
+  {
+    MSG_SERVER,
+    TOK_SERVER,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { mr_server, m_registered, ms_server, m_registered, m_ignore }
+  },
+  {
+    MSG_SQUIT,
+    TOK_SQUIT,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_squit, mo_squit, m_ignore }
+  },
+  {
+    MSG_WHOIS,
+    TOK_WHOIS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_whois, m_whois, m_whois, m_ignore }
+  },
+  {
+    MSG_WHO,
+    TOK_WHO,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_who, m_ignore, m_who, m_ignore }
+  },
+  {
+    MSG_WHOWAS,
+    TOK_WHOWAS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_whowas, m_whowas, m_whowas, m_ignore }
+  },
+  {
+    MSG_LIST,
+    TOK_LIST,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_list, m_ignore, m_list, m_ignore }
+  },
+  {
+    MSG_NAMES,
+    TOK_NAMES,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_names, ms_names, m_names, m_ignore }
+  },
+  {
+    MSG_USERHOST,
+    TOK_USERHOST,
+    0, 1, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_userhost, m_ignore, m_userhost, m_ignore }
+  },
+  {
+    MSG_USERIP,
+    TOK_USERIP,
+    0, 1, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_userip, m_ignore, m_userip, m_ignore }
+  },
+  {
+    MSG_TRACE,
+    TOK_TRACE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_trace, ms_trace, mo_trace, m_ignore }
+  },
+  {
+    MSG_PASS,
+    TOK_PASS,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_pass, m_registered, m_ignore, m_registered, m_ignore }
+  },
+  {
+    MSG_LUSERS,
+    TOK_LUSERS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_lusers, ms_lusers, m_lusers, m_ignore }
+  },
+  {
+    MSG_TIME,
+    TOK_TIME,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_time, m_time, m_time, m_ignore }
+  },
+  {
+    MSG_SETTIME,
+    TOK_SETTIME,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ignore, ms_settime, mo_settime, m_ignore }
+  },
+  {
+    MSG_RPING,
+    TOK_RPING,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_rping, mo_rping, m_ignore }
+  },
+  {
+    MSG_RPONG,
+    TOK_RPONG,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_ignore, ms_rpong, m_ignore, m_ignore }
+  },
+  {
+    MSG_OPER,
+    TOK_OPER,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_oper, ms_oper, mo_oper, m_ignore }
+  },
+  {
+    MSG_CONNECT,
+    TOK_CONNECT,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_connect, mo_connect, m_ignore }
+  },
+  {
+    MSG_MAP,
+    TOK_MAP,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_map, m_ignore, m_map, m_ignore }
+  },
+  {
+    MSG_VERSION,
+    TOK_VERSION,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_version, m_version, ms_version, m_version, m_ignore }
+  },
+  {
+    MSG_STATS,
+    TOK_STATS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_stats, ms_stats, mo_stats, m_ignore }
+  },
+  {
+    MSG_LINKS,
+    TOK_LINKS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_links, ms_links, m_links, m_ignore }
+  },
+  {
+    MSG_ADMIN,
+    TOK_ADMIN,
+    0, MAXPARA, MFLG_SLOW | MFLG_UNREG, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_admin, m_admin, ms_admin, m_admin, m_ignore }
+  },
+  {
+    MSG_HELP,
+    TOK_HELP,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_help, m_ignore, m_help, m_ignore }
+  },
+  {
+    MSG_INFO,
+    TOK_INFO,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_info, ms_info, mo_info, m_ignore }
+  },
+  {
+    MSG_MOTD,
+    TOK_MOTD,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_motd, m_motd, m_motd, m_ignore }
+  },
+  {
+    MSG_CLOSE,
+    TOK_CLOSE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_close, m_ignore }
+  },
+  {
+    MSG_SILENCE,
+    TOK_SILENCE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_silence, ms_silence, m_silence, m_ignore }
+  },
+  {
+    MSG_GLINE,
+    TOK_GLINE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, ms_gline, mo_gline, m_ignore }
+  },
+  {
+    MSG_END_OF_BURST,
+    TOK_END_OF_BURST,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_end_of_burst, m_ignore, m_ignore }
+  },
+  {
+    MSG_END_OF_BURST_ACK,
+    TOK_END_OF_BURST_ACK,
+    0, MAXPARA, 1, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_ignore, m_ignore, ms_end_of_burst_ack, m_ignore, m_ignore }
+  },
+  {
+    MSG_HASH,
+    TOK_HASH,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_hash, m_hash, m_hash, m_ignore }
+  },
+  {
+    MSG_DNS,
+    TOK_DNS,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_dns, m_dns, m_dns, m_ignore }
+  },
+  {
+    MSG_REHASH,
+    TOK_REHASH,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_rehash, m_ignore }
+  },
+  {
+    MSG_RESTART,
+    TOK_RESTART,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_restart, m_ignore }
+  },
+  {
+    MSG_DIE,
+    TOK_DIE,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_unregistered, m_not_oper, m_ignore, mo_die, m_ignore }
+  },
+  {
+    MSG_PROTO,
+    TOK_PROTO,
+    0, MAXPARA, MFLG_SLOW, 0,
+    /* UNREG, CLIENT, SERVER, OPER, SERVICE */
+    { m_proto, m_proto, m_proto, m_proto, m_ignore }
+  },
+  { 0 }
+}; 
 
-RCSTAG_CC("$Id$");
-
-/* *INDENT-OFF* */
-
-aMessage msgtab[] = {
-    {CLASS_PRIVATE,    MSG_PRIVATE,    TOK_PRIVATE,    m_private,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_NICK,       MSG_NICK,       TOK_NICK,       m_nick,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_NOTICE,     MSG_NOTICE,     TOK_NOTICE,     m_notice,       0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_WALLCHOPS,  MSG_WALLCHOPS,  TOK_WALLCHOPS,  m_wallchops,    0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_CPRIVMSG,   MSG_CPRIVMSG,   TOK_CPRIVMSG,   m_cprivmsg,     0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_CNOTICE,    MSG_CNOTICE,    TOK_CNOTICE,    m_cnotice,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_JOIN,       MSG_JOIN,       TOK_JOIN,       m_join,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_MODE,       MSG_MODE,       TOK_MODE,       m_mode,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_BURST,      MSG_BURST,      TOK_BURST,      m_burst,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_CREATE,     MSG_CREATE,     TOK_CREATE,     m_create,       0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_DESTRUCT,   MSG_DESTRUCT,   TOK_DESTRUCT,   m_destruct,     0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_QUIT,       MSG_QUIT,       TOK_QUIT,       m_quit,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_PART,       MSG_PART,       TOK_PART,       m_part,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_TOPIC,      MSG_TOPIC,      TOK_TOPIC,      m_topic,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_INVITE,     MSG_INVITE,     TOK_INVITE,     m_invite,       0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_KICK,       MSG_KICK,       TOK_KICK,       m_kick,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_WALLOPS,    MSG_WALLOPS,    TOK_WALLOPS,    m_wallops,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_DESYNCH,     MSG_DESYNCH,    TOK_DESYNCH,    m_desynch,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_PING,       MSG_PING,       TOK_PING,       m_ping,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_PONG,       MSG_PONG,       TOK_PONG,       m_pong,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_ERROR,      MSG_ERROR,      TOK_ERROR,      m_error,        0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_KILL,       MSG_KILL,       TOK_KILL,       m_kill,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_USER,       MSG_USER,       TOK_USER,       m_user,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_AWAY,       MSG_AWAY,       TOK_AWAY,       m_away,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_ISON,       MSG_ISON,       TOK_ISON,       m_ison,         0, 1,           MFLG_SLOW,      0L},
-    {CLASS_SERVER,     MSG_SERVER,     TOK_SERVER,     m_server,       0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_SQUIT,      MSG_SQUIT,      TOK_SQUIT,      m_squit,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_WHOIS,      MSG_WHOIS,      TOK_WHOIS,      m_whois,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_WHO,                MSG_WHO,        TOK_WHO,        m_who,          0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_WHOWAS,     MSG_WHOWAS,     TOK_WHOWAS,     m_whowas,       0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_LIST,       MSG_LIST,       TOK_LIST,       m_list,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_NAMES,      MSG_NAMES,      TOK_NAMES,      m_names,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_USERHOST,   MSG_USERHOST,   TOK_USERHOST,   m_userhost,     0, 1,           MFLG_SLOW,      0L},
-    {CLASS_USERIP,     MSG_USERIP,     TOK_USERIP,     m_userip,       0, 1,           MFLG_SLOW,      0L},
-    {CLASS_TRACE,      MSG_TRACE,      TOK_TRACE,      m_trace,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_PASS,       MSG_PASS,       TOK_PASS,       m_pass,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_LUSERS,     MSG_LUSERS,     TOK_LUSERS,     m_lusers,       0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_TIME,       MSG_TIME,       TOK_TIME,       m_time,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_SETTIME,    MSG_SETTIME,    TOK_SETTIME,    m_settime,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_RPING,      MSG_RPING,      TOK_RPING,      m_rping,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_RPONG,      MSG_RPONG,      TOK_RPONG,      m_rpong,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_OPER,       MSG_OPER,       TOK_OPER,       m_oper,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_CONNECT,    MSG_CONNECT,    TOK_CONNECT,    m_connect,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_UPING,      MSG_UPING,      TOK_UPING,      m_uping,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_MAP,                MSG_MAP,        TOK_MAP,        m_map,          0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_VERSION,    MSG_VERSION,    TOK_VERSION,    m_version,      0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_STATS,      MSG_STATS,      TOK_STATS,      m_stats,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_LINKS,      MSG_LINKS,      TOK_LINKS,      m_links,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_ADMIN,      MSG_ADMIN,      TOK_ADMIN,      m_admin,        0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_HELP,       MSG_HELP,       TOK_HELP,       m_help,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_INFO,       MSG_INFO,       TOK_INFO,       m_info,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_MOTD,       MSG_MOTD,       TOK_MOTD,       m_motd,         0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_CLOSE,      MSG_CLOSE,      TOK_CLOSE,      m_close,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_SILENCE,    MSG_SILENCE,    TOK_SILENCE,    m_silence,      0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_GLINE,      MSG_GLINE,      TOK_GLINE,      m_gline,        0, MAXPARA,     MFLG_SLOW,      0L},
-    {CLASS_END_OF_BURST, MSG_END_OF_BURST, TOK_END_OF_BURST, m_end_of_burst, 0, MAXPARA, MFLG_SLOW,    0L},
-    {CLASS_END_OF_BURST_ACK, MSG_END_OF_BURST_ACK, TOK_END_OF_BURST_ACK, m_end_of_burst_ack, 0, MAXPARA, 1, 0L},
-    {CLASS_HASH,       MSG_HASH,       TOK_HASH,       m_hash,         0, MAXPARA,     MFLG_SLOW|MFLG_UNREG,   0L},
-    {CLASS_DNS,                MSG_DNS,        TOK_DNS,        m_dns,          0, MAXPARA,     MFLG_SLOW,      0L},
-#if defined(OPER_REHASH) || defined(LOCOP_REHASH)
-    {CLASS_REHASH,     MSG_REHASH,     TOK_REHASH,     m_rehash,       0, MAXPARA,     MFLG_SLOW,      0L},
-#endif
-#if defined(OPER_RESTART) || defined(LOCOP_RESTART)
-    {CLASS_RESTART,    MSG_RESTART,    TOK_RESTART,    m_restart,      0, MAXPARA,     MFLG_SLOW,      0L},
-#endif
-#if defined(OPER_DIE) || defined(LOCOP_DIE)
-    {CLASS_DIE,                MSG_DIE,        TOK_DIE,        m_die,          0, MAXPARA,     MFLG_SLOW,      0L},
-#endif
-    {0, (char *)0, (char *)0, (int (*)(aClient *, aClient *, int, char **))0,  0, 0, 0, 0L}
-}                                                                                                                                   ;
-/* *INDENT-ON* */
 
 #ifdef GODMODE
 extern int sdbflag;
 #endif /* GODMODE */
 
-static char *para[MAXPARA + 2];        /* leave room for prefix and null */
+static char *para[MAXPARA + 2]; /* leave room for prefix and null */
 
 /*
  * Message Tree stuff mostly written by orabidoo, with changes by Dianora.
  * Adapted to Undernet, adding token support, etc by comstud 10/06/97
  */
 
-static aMessageTree msg_tree_cmd;
-static aMessageTree msg_tree_tok;
+static struct MessageTree msg_tree_cmd;
+static struct MessageTree msg_tree_tok;
 
 /*
  * Guts of making the token tree...
  */
-static aMessage **do_msg_tree_tok(aMessageTree *mtree, char *prefix,
-    aMessage **mptr)
+static struct Message **do_msg_tree_tok(struct MessageTree *mtree, char *prefix,
+    struct Message **mptr)
 {
-  char newprefix[64];          /* Must be longer than every command name */
+  char newprefix[64];           /* Must be longer than every command name */
   int c, c2, lp;
-  aMessageTree *mtree1;
+  struct MessageTree *mtree1;
 
   lp = strlen(prefix);
   if (!lp || !strncmp((*mptr)->tok, prefix, lp))
@@ -156,11 +532,11 @@ static aMessage **do_msg_tree_tok(aMessageTree *mtree, char *prefix,
       mtree->final = (*mptr)->tok + lp;
       mtree->msg = *mptr;
       for (c = 0; c < 26; ++c)
-       mtree->pointers[c] = NULL;
+        mtree->pointers[c] = NULL;
       return mptr + 1;
     }
     /* command in this prefix */
-    if (!strCasediff((*mptr)->tok, prefix))
+    if (0 == ircd_strcmp((*mptr)->tok, prefix))
     {
       mtree->final = "";
       mtree->msg = *mptr++;
@@ -172,38 +548,41 @@ static aMessage **do_msg_tree_tok(aMessageTree *mtree, char *prefix,
     {
       if ((*mptr)->tok[lp] == c)
       {
-       mtree1 = (aMessageTree *)RunMalloc(sizeof(aMessageTree));
-       mtree1->final = NULL;
-       mtree->pointers[c - 'A'] = mtree1;
-       strcpy(newprefix, prefix);
-       newprefix[lp] = c;
-       newprefix[lp + 1] = '\0';
-       mptr = do_msg_tree_tok(mtree1, newprefix, mptr);
-       if (!*mptr || strncmp((*mptr)->tok, prefix, lp))
-       {
-         for (c2 = c + 1 - 'A'; c2 < 26; ++c2)
-           mtree->pointers[c2] = NULL;
-         return mptr;
-       }
+        mtree1 = (struct MessageTree *)MyMalloc(sizeof(struct MessageTree));
+        mtree1->final = NULL;
+        mtree->pointers[c - 'A'] = mtree1;
+        strcpy(newprefix, prefix);
+        newprefix[lp] = c;
+        newprefix[lp + 1] = '\0';
+        mptr = do_msg_tree_tok(mtree1, newprefix, mptr);
+        if (!*mptr || strncmp((*mptr)->tok, prefix, lp))
+        {
+          for (c2 = c + 1 - 'A'; c2 < 26; ++c2)
+            mtree->pointers[c2] = NULL;
+          return mptr;
+        }
       }
       else
-       mtree->pointers[c - 'A'] = NULL;
+        mtree->pointers[c - 'A'] = NULL;
     }
     return mptr;
   }
-  MyCoreDump;                  /* This should never happen */
+  /*
+   * XXX - should never be here, quick hack, this can be done better
+   */
+  assert(0);
   exit(1);
 }
 
 /*
  * Guts of making the command tree...
  */
-static aMessage *do_msg_tree_cmd(aMessageTree *mtree, char *prefix,
-    aMessage *mptr)
+static struct Message *do_msg_tree_cmd(struct MessageTree *mtree, char *prefix,
+    struct Message *mptr)
 {
-  char newprefix[64];          /* Must be longer than every command name */
+  char newprefix[64];           /* Must be longer than every command name */
   int c, c2, lp;
-  aMessageTree *mtree1;
+  struct MessageTree *mtree1;
 
   lp = strlen(prefix);
   if (!lp || !strncmp(mptr->cmd, prefix, lp))
@@ -214,11 +593,11 @@ static aMessage *do_msg_tree_cmd(aMessageTree *mtree, char *prefix,
       mtree->final = mptr->cmd + lp;
       mtree->msg = mptr;
       for (c = 0; c < 26; ++c)
-       mtree->pointers[c] = NULL;
+        mtree->pointers[c] = NULL;
       return mptr + 1;
     }
     /* command in this prefix */
-    if (!strCasediff(mptr->cmd, prefix))
+    if (0 == ircd_strcmp(mptr->cmd, prefix))
     {
       mtree->final = "";
       mtree->msg = mptr++;
@@ -230,26 +609,29 @@ static aMessage *do_msg_tree_cmd(aMessageTree *mtree, char *prefix,
     {
       if (mptr->cmd[lp] == c)
       {
-       mtree1 = (aMessageTree *)RunMalloc(sizeof(aMessageTree));
-       mtree1->final = NULL;
-       mtree->pointers[c - 'A'] = mtree1;
-       strcpy(newprefix, prefix);
-       newprefix[lp] = c;
-       newprefix[lp + 1] = '\0';
-       mptr = do_msg_tree_cmd(mtree1, newprefix, mptr);
-       if (!mptr->cmd || strncmp(mptr->cmd, prefix, lp))
-       {
-         for (c2 = c + 1 - 'A'; c2 < 26; ++c2)
-           mtree->pointers[c2] = NULL;
-         return mptr;
-       }
+        mtree1 = (struct MessageTree *)MyMalloc(sizeof(struct MessageTree));
+        mtree1->final = NULL;
+        mtree->pointers[c - 'A'] = mtree1;
+        strcpy(newprefix, prefix);
+        newprefix[lp] = c;
+        newprefix[lp + 1] = '\0';
+        mptr = do_msg_tree_cmd(mtree1, newprefix, mptr);
+        if (!mptr->cmd || strncmp(mptr->cmd, prefix, lp))
+        {
+          for (c2 = c + 1 - 'A'; c2 < 26; ++c2)
+            mtree->pointers[c2] = NULL;
+          return mptr;
+        }
       }
       else
-       mtree->pointers[c - 'A'] = NULL;
+        mtree->pointers[c - 'A'] = NULL;
     }
     return mptr;
   }
-  MyCoreDump;                  /* This should never happen */
+  /* 
+   * This should never happen
+   */
+  assert(0);
   exit(1);
 }
 
@@ -270,35 +652,35 @@ static int mtokcmp(const struct Message **m1, const struct Message **m2)
  */
 void initmsgtree(void)
 {
-  Reg1 int i;
-  Reg2 aMessage *msg = msgtab;
-  Reg3 int ii;
-  aMessage **msgtab_tok;
-  aMessage **msgtok;
+  int i;
+  struct Message *msg = msgtab;
+  int ii;
+  struct Message **msgtab_tok;
+  struct Message **msgtok;
 
   for (i = 0; msg->cmd; ++i, ++msg)
     continue;
-  qsort(msgtab, i, sizeof(aMessage),
+  qsort(msgtab, i, sizeof(struct Message),
       (int (*)(const void *, const void *))mcmdcmp);
-  msgtab_tok = (aMessage **)RunMalloc((i + 1) * sizeof(aMessage *));
+  msgtab_tok = (struct Message **)MyMalloc((i + 1) * sizeof(struct Message *));
   for (ii = 0; ii < i; ++ii)
     msgtab_tok[ii] = msgtab + ii;
-  msgtab_tok[i] = NULL;                /* Needed by `do_msg_tree_tok' */
-  qsort(msgtab_tok, i, sizeof(aMessage *),
+  msgtab_tok[i] = NULL;         /* Needed by `do_msg_tree_tok' */
+  qsort(msgtab_tok, i, sizeof(struct Message *),
       (int (*)(const void *, const void *))mtokcmp);
   msg = do_msg_tree_cmd(&msg_tree_cmd, "", msgtab);
   msgtok = do_msg_tree_tok(&msg_tree_tok, "", msgtab_tok);
-  RunFree(msgtab_tok);
+  MyFree(msgtab_tok);
 }
 
 /*
  * Generic tree parser which works for both commands and tokens.
  * Optimized by Run.
  */
-static struct Message *msg_tree_parse(register char *cmd, aMessageTree *root)
+static struct Message *msg_tree_parse(char *cmd, struct MessageTree *root)
 {
-  register aMessageTree *mtree;
-  register unsigned char r = (0xdf & (unsigned char)*cmd) - 'A';
+  struct MessageTree *mtree;
+  unsigned char r = (0xdf & (unsigned char)*cmd) - 'A';
   if (r > 25 || !(mtree = root->pointers[r]))
     return NULL;
   for (;;)
@@ -317,17 +699,17 @@ static struct Message *msg_tree_parse(register char *cmd, aMessageTree *root)
  * This is to avoid confusion with commands like /quake on clients
  * that send unknown commands directly to the server.
  */
-static struct Message *msg_tree_parse_client(register char *cmd,
-    aMessageTree *root)
+static struct Message *msg_tree_parse_client(char *cmd,
+    struct MessageTree *root)
 {
-  register aMessageTree *mtree;
-  register unsigned char q = (0xdf & (unsigned char)*cmd) - 'A';
+  struct MessageTree *mtree;
+  unsigned char q = (0xdf & (unsigned char)*cmd) - 'A';
   if (q > 25 || !(mtree = root->pointers[q]))
     return NULL;
   for (;;)
   {
     q = 0xdf & (unsigned char)*++cmd;
-    if (mtree->final && !strCasediff(mtree->final, cmd))
+    if (mtree->final && 0 == ircd_strcmp(mtree->final, cmd))
       return mtree->msg;
     if ((q -= 'A') > 25 || !(mtree = mtree->pointers[q]))
       return NULL;
@@ -339,35 +721,38 @@ static struct Message *msg_tree_parse_client(register char *cmd,
  *
  * NOTE: parse_*() should not be called recusively by any other fucntions!
  */
-int parse_client(aClient *cptr, char *buffer, char *bufend)
+int parse_client(struct Client *cptr, char *buffer, char *bufend)
 {
-  Reg1 aClient *from = cptr;
-  Reg2 char *ch, *s;
-  Reg3 int i, paramcount, noprefix = 0;
-  aMessage *mptr;
+  struct Client*  from = cptr;
+  char*           ch;
+  char*           s;
+  int             i;
+  int             paramcount;
+  int             noprefix = 0;
+  struct Message* mptr;
+  MessageHandler  handler = 0;
 
   Debug((DEBUG_DEBUG, "Parsing: %s", buffer));
-  StoreBuffer((buffer, cptr)); /* Store the buffer now, before
-                                  we start working on it */
 
   if (IsDead(cptr))
     return 0;
 
   para[0] = from->name;
-  for (ch = buffer; *ch == ' '; ch++); /* Eat leading spaces */
-  if (*ch == ':')              /* Is any client doing this ? */
+  for (ch = buffer; *ch == ' '; ch++);  /* Eat leading spaces */
+  if (*ch == ':')               /* Is any client doing this ? */
   {
-    for (++ch; *ch && *ch != ' '; ++ch);       /* Ignore sender prefix from client */
+    for (++ch; *ch && *ch != ' '; ++ch)
+      ; /* Ignore sender prefix from client */
     while (*ch == ' ')
-      ch++;                    /* Advance to command */
+      ch++;                     /* Advance to command */
   }
   else
     noprefix = 1;
   if (*ch == '\0')
   {
-    ircstp->is_empt++;
+    ServerStats->is_empt++;
     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
-       cptr->name, from->name));
+        cptr->name, from->name));
     return (-1);
   }
 
@@ -394,15 +779,14 @@ int parse_client(aClient *cptr, char *buffer, char *bufend)
     if (buffer[0] != '\0')
     {
       if (IsUser(from))
-       sendto_one(from, ":%s %d %s %s :Unknown command",
-           me.name, ERR_UNKNOWNCOMMAND, from->name, ch);
+        sendto_one(from, ":%s %d %s %s :Unknown command",
+            me.name, ERR_UNKNOWNCOMMAND, from->name, ch);
       Debug((DEBUG_ERROR, "Unknown (%s) from %s",
-         ch, get_client_name(cptr, FALSE)));
+            ch, get_client_name(cptr, HIDE_IP)));
     }
-    ircstp->is_unco++;
+    ServerStats->is_unco++;
     return (-1);
   }
-  LogMessage((cptr, mptr->msgclass));
 
   paramcount = mptr->parameters;
   i = bufend - ((s) ? s : ch);
@@ -439,57 +823,62 @@ int parse_client(aClient *cptr, char *buffer, char *bufend)
        * out *all* blanks.. --msa
        */
       while (*s == ' ')
-       *s++ = '\0';
+        *s++ = '\0';
 
       if (*s == '\0')
-       break;
+        break;
       if (*s == ':')
       {
-       /*
-        * The rest is single parameter--can
-        * include blanks also.
-        */
-       para[++i] = s + 1;
-       break;
+        /*
+         * The rest is single parameter--can
+         * include blanks also.
+         */
+        para[++i] = s + 1;
+        break;
       }
       para[++i] = s;
       if (i >= paramcount)
-       break;
+        break;
       for (; *s != ' ' && *s; s++);
     }
   }
   para[++i] = NULL;
-  mptr->count++;
-  /* The "unregistered command check" was ugly and mildly inefficient.
+  ++mptr->count;
+#if 0
+  /*
+   * The "unregistered command check" was ugly and mildly inefficient.
    * I fixed it. :)  --Shadow
    */
-  if (!IsUser(cptr) && !(mptr->flags & MFLG_UNREG))
-  {
-    sendto_one(from, ":%s %d * %s :Register first.",
-       me.name, ERR_NOTREGISTERED, ch);
+  if (!IsUser(cptr) && 0 == (mptr->flags & MFLG_UNREG)) {
+    if (0 == (mptr->flags & MFLG_IGNORE))
+      sendto_one(from, ":%s %d * %s :Register first.",
+                 me.name, ERR_NOTREGISTERED, ch);
     return -1;
   }
-  if (IsUser(cptr) &&
-#ifdef IDLE_FROM_MSG
-      mptr->func == m_private)
-#else
-      mptr->func != m_ping && mptr->func != m_pong)
 #endif
-      from->user->last = now;
+  handler = mptr->handlers[cptr->handler];
+  assert(0 != handler);
+
+#ifndef IDLE_FROM_MSG
+  if (IsUser(cptr) && handler != m_ping && handler != m_ignore)
+    from->user->last = CurrentTime;
+#endif
 
-  return (*mptr->func) (cptr, from, i, para);
+  return (*handler) (cptr, from, i, para);
 }
 
-int parse_server(aClient *cptr, char *buffer, char *bufend)
+int parse_server(struct Client *cptr, char *buffer, char *bufend)
 {
-  Reg1 aClient *from = cptr;
-  Reg2 char *ch = buffer, *s;
-  Reg3 int len, i, numeric = 0, paramcount;
-  aMessage *mptr;
+  struct Client*  from = cptr;
+  char*           ch = buffer;
+  char*           s;
+  int             len;
+  int             i;
+  int             numeric = 0;
+  int             paramcount;
+  struct Message* mptr;
 
   Debug((DEBUG_DEBUG, "Parsing: %s", buffer));
-  StoreBuffer((buffer, cptr)); /* Store the buffer now, before
-                                * we start working on it. */
 
 #ifdef GODMODE
   len = strlen(buffer);
@@ -499,7 +888,7 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
     char c = buffer[200];
     buffer[200] = 0;
     sendto_ops("RCV:%-8.8s(%.4d): \"%s...%s\"",
-       cptr->name, len, buffer, &buffer[len - 200]);
+        cptr->name, len, buffer, &buffer[len - 200]);
     buffer[200] = c;
   }
   else
@@ -539,10 +928,10 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
     if (!from)
     {
       Debug((DEBUG_NOTICE, "Unknown prefix (%s)(%s) from (%s)",
-         para[0], buffer, cptr->name));
-      ircstp->is_unpf++;
+          para[0], buffer, cptr->name));
+      ++ServerStats->is_unpf;
       while (*ch == ' ')
-       ch++;
+        ch++;
       /*
        * However, the only thing that MUST be
        * allowed to travel upstream against an
@@ -551,29 +940,27 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
        */
       if (ch[1] == 'Q')
       {
-       para[0] = cptr->name;
-       from = cptr;
+        para[0] = cptr->name;
+        from = cptr;
       }
       else
-       return 0;
+        return 0;
     }
     else if (from->from != cptr)
     {
-      ircstp->is_wrdi++;
+      ++ServerStats->is_wrdi;
       Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
-         buffer, cptr->name));
+          buffer, cptr->name));
       return 0;
     }
   }
-  else if (Protocol(cptr) > 9) /* Well, not ALWAYS, 2.9 can send no prefix */
+  else if (Protocol(cptr) > 9)  /* Well, not ALWAYS, 2.9 can send no prefix */
   {
     char numeric_prefix[6];
-    int i;
-    for (i = 0; i < 5; ++i)
-    {
-      if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i]))
-      {
-       break;
+    int  i;
+    for (i = 0; i < 5; ++i) {
+      if ('\0' == ch[i] || ' ' == (numeric_prefix[i] = ch[i])) {
+        break;
       }
     }
     numeric_prefix[i] = '\0';
@@ -584,7 +971,7 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
      */
     if (' ' == ch[1] || ' ' == ch[2])
       from = FindNServer(numeric_prefix);
-    else
+    else 
       from = findNUser(numeric_prefix);
 
     do
@@ -607,28 +994,28 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
      */
     if (!from)
     {
-      ircstp->is_unpf++;
+      ServerStats->is_unpf++;
       while (*ch == ' ')
-       ch++;
+        ch++;
       if (*ch == 'N' && (ch[1] == ' ' || ch[1] == 'I'))
-       /* Only sent a KILL for a nick change */
+        /* Only sent a KILL for a nick change */
       {
-       aClient *server;
-       /* Kill the unknown numeric prefix upstream if
-        * it's server still exists: */
-       if ((server = FindNServer(numeric_prefix)) && server->from == cptr)
-         sendto_one(cptr, "%s KILL %s :%s (Unknown numeric nick)",
-             NumServ(&me), numeric_prefix, me.name);
+        struct Client *server;
+        /* Kill the unknown numeric prefix upstream if
+         * it's server still exists: */
+        if ((server = FindNServer(numeric_prefix)) && server->from == cptr)
+          sendto_one(cptr, "%s KILL %s :%s (Unknown numeric nick)",
+                     NumServ(&me), numeric_prefix, me.name);
       }
       /*
        * Things that must be allowed to travel
        * upstream against an squit:
        */
       if (ch[1] == 'Q' || (*ch == 'D' && ch[1] == ' ') ||
-         (*ch == 'K' && ch[2] == 'L'))
-       from = cptr;
+          (*ch == 'K' && ch[2] == 'L'))
+        from = cptr;
       else
-       return 0;
+        return 0;
     }
 
     /* Let para[0] point to the name of the sender */
@@ -636,9 +1023,9 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
 
     if (from->from != cptr)
     {
-      ircstp->is_wrdi++;
+      ServerStats->is_wrdi++;
       Debug((DEBUG_NOTICE, "Fake direction: Message (%s) coming from (%s)",
-         buffer, cptr->name));
+          buffer, cptr->name));
       return 0;
     }
   }
@@ -647,9 +1034,9 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
     ch++;
   if (*ch == '\0')
   {
-    ircstp->is_empt++;
+    ServerStats->is_empt++;
     Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
-       cptr->name, from->name));
+        cptr->name, from->name));
     return (-1);
   }
 
@@ -660,14 +1047,14 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
    * numerics must have parameters and thus a space after the command
    * code. -avalon
    */
-  s = strchr(ch, ' ');         /* s -> End of the command code */
+  s = strchr(ch, ' ');          /* s -> End of the command code */
   len = (s) ? (s - ch) : 0;
-  if (len == 3 && isDigit(*ch))
+  if (len == 3 && IsDigit(*ch))
   {
     numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + (*(ch + 2) - '0');
     paramcount = MAXPARA;
-    ircstp->is_num++;
-    mptr = NULL;               /* Init. to avoid stupid compiler warning :/ */
+    ServerStats->is_num++;
+    mptr = NULL;                /* Init. to avoid stupid compiler warning :/ */
   }
   else
   {
@@ -690,10 +1077,10 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
      */
     mptr = msg_tree_parse(ch, &msg_tree_tok);
 
-#if 1                          /* for 2.10.0/2.10.10 */
+#if 1                           /* for 2.10.0/2.10.10 */
     /*
      * This code supports 2.9 and 2.10.0 sending long commands.
-     * It makes more calls to strCasediff() than the above
+     * It makes more calls to ircd_strcmp() than the above
      * so it will be somewhat slower.
      */
     if (!mptr)
@@ -716,14 +1103,13 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
 #ifdef DEBUGMODE
       if (buffer[0] != '\0')
       {
-       Debug((DEBUG_ERROR, "Unknown (%s) from %s",
-           ch, get_client_name(cptr, FALSE)));
+        Debug((DEBUG_ERROR, "Unknown (%s) from %s",
+              ch, get_client_name(cptr, HIDE_IP)));
       }
 #endif
-      ircstp->is_unco++;
+      ServerStats->is_unco++;
       return (-1);
     }
-    LogMessage((cptr, mptr->msgclass));
 
     paramcount = mptr->parameters;
     i = bufend - ((s) ? s : ch);
@@ -751,22 +1137,22 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
        * out *all* blanks.. --msa
        */
       while (*s == ' ')
-       *s++ = '\0';
+        *s++ = '\0';
 
       if (*s == '\0')
-       break;
+        break;
       if (*s == ':')
       {
-       /*
-        * The rest is single parameter--can
-        * include blanks also.
-        */
-       para[++i] = s + 1;
-       break;
+        /*
+         * The rest is single parameter--can
+         * include blanks also.
+         */
+        para[++i] = s + 1;
+        break;
       }
       para[++i] = s;
       if (i >= paramcount)
-       break;
+        break;
       for (; *s != ' ' && *s; s++);
     }
   }
@@ -775,5 +1161,5 @@ int parse_server(aClient *cptr, char *buffer, char *bufend)
     return (do_numeric(numeric, (*buffer != ':'), cptr, from, i, para));
   mptr->count++;
 
-  return (*mptr->func) (cptr, from, i, para);
+  return (*mptr->handlers[cptr->handler]) (cptr, from, i, para);
 }
index c31d0d0bac242fe5602859942b6280c1b386171b..95c9b9138116be9130bf2ac6100d2fe20e7f99ec 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "sys.h"
-#include <sys/stat.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stdlib.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include "h.h"
-#include "struct.h"
-#include "parse.h"
-#include "send.h"
-#include "s_err.h"
-#include "numeric.h"
-#include "ircd.h"
-#include "s_user.h"
-#include "version.h"
-#include "s_bsd.h"
-#include "s_misc.h"
-#include "match.h"
-#include "s_serv.h"
-#include "msg.h"
-#include "channel.h"
-#include "numnicks.h"
-#include "userload.h"
-#include "s_conf.h"
-#include "support.h"
-#include "querycmds.h"
-
-RCSTAG_CC("$Id$");
-
-/*
- * m_functions execute protocol messages on this server:
- *
- *   cptr    is always NON-NULL, pointing to a *LOCAL* client
- *           structure (with an open socket connected!). This
- *           identifies the physical socket where the message
- *           originated (or which caused the m_function to be
- *           executed--some m_functions may call others...).
- *
- *   sptr    is the source of the message, defined by the
- *           prefix part of the message if present. If not
- *           or prefix not found, then sptr==cptr.
- *
- *           (!IsServer(cptr)) => (cptr == sptr), because
- *           prefixes are taken *only* from servers...
- *
- *           (IsServer(cptr))
- *                   (sptr == cptr) => the message didn't
- *                   have the prefix.
- *
- *                   (sptr != cptr && IsServer(sptr) means
- *                   the prefix specified servername. (?)
- *
- *                   (sptr != cptr && !IsServer(sptr) means
- *                   that message originated from a remote
- *                   user (not local).
- *
- *           combining
- *
- *           (!IsServer(sptr)) means that, sptr can safely
- *           taken as defining the target structure of the
- *           message in this server.
- *
- *   *Always* true (if 'parse' and others are working correct):
- *
- *   1)      sptr->from == cptr  (note: cptr->from == cptr)
- *
- *   2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
- *           *cannot* be a local connection, unless it's
- *           actually cptr!). [MyConnect(x) should probably
- *           be defined as (x == x->from) --msa ]
- *
- *   parc    number of variable parameter strings (if zero,
- *           parv is allowed to be NULL)
- *
- *   parv    a NULL terminated list of parameter pointers,
- *
- *                   parv[0], sender (prefix string), if not present
- *                           this points to an empty string.
- *                   parv[1]...parv[parc-1]
- *                           pointers to additional parameters
- *                   parv[parc] == NULL, *always*
- *
- *           note:   it is guaranteed that parv[0]..parv[parc-1] are all
- *                   non-NULL pointers.
- */
-
-/*
- * m_version
- *
- *   parv[0] = sender prefix
- *   parv[1] = remote server
- */
-int m_version(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 aClient *acptr;
-
-  if (MyConnect(sptr) && parc > 1)
-  {
-    if (!(acptr = find_match_server(parv[1])))
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
-      return 0;
-    }
-    parv[1] = acptr->name;
-  }
-
-  if (hunt_server(0, cptr, sptr, ":%s VERSION :%s", 1, parc, parv) ==
-      HUNTED_ISME)
-    sendto_one(sptr, rpl_str(RPL_VERSION),
-       me.name, parv[0], version, debugmode, me.name, serveropts);
-
-  return 0;
-}
-
-/*
- * m_info
- *
- * parv[0] = sender prefix
- * parv[1] = servername
- */
-int m_info(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  const char **text = infotext;
-
-  if (hunt_server(1, cptr, sptr, ":%s INFO :%s", 1, parc, parv) == HUNTED_ISME)
-  {
-    while (text[2])
-    {
-      if (!IsOper(sptr))
-       sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text);
-      text++;
-    }
-    if (IsOper(sptr))
-    {
-      while (*text)
-       sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], *text++);
-      sendto_one(sptr, rpl_str(RPL_INFO), me.name, parv[0], "");
-    }
-    sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
-       me.name, RPL_INFO, parv[0], creation, generation);
-    sendto_one(sptr, ":%s %d %s :On-line since %s",
-       me.name, RPL_INFO, parv[0], myctime(me.firsttime));
-    sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
-  }
-  return 0;
-}
-
-/*
- * m_links
  *
- * parv[0] = sender prefix
- * parv[1] = servername mask
- *
- * or
- *
- * parv[0] = sender prefix
- * parv[1] = server to query
- * parv[2] = servername mask
- */
-int m_links(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  char *mask;
-  aClient *acptr;
-
-  if (parc > 2)
-  {
-    if (hunt_server(1, cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv) !=
-       HUNTED_ISME)
-      return 0;
-    mask = parv[2];
-  }
-  else
-    mask = parc < 2 ? NULL : parv[1];
-
-  for (acptr = client, collapse(mask); acptr; acptr = acptr->next)
-  {
-    if (!IsServer(acptr) && !IsMe(acptr))
-      continue;
-    if (!BadPtr(mask) && match(mask, acptr->name))
-      continue;
-    sendto_one(sptr, rpl_str(RPL_LINKS),
-       me.name, parv[0], acptr->name, acptr->serv->up->name,
-#ifndef GODMODE
-       acptr->hopcount, acptr->serv->prot,
-#else /* GODMODE */
-       acptr->hopcount, acptr->serv->prot, acptr->serv->timestamp,
-       NumServ(acptr),
-#endif /* GODMODE */
-       (acptr->info[0] ? acptr->info : "(Unknown Location)"));
-  }
-
-  sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
-      BadPtr(mask) ? "*" : mask);
-  return 0;
-}
-
-/*
- * m_help
- *
- * parv[0] = sender prefix
+ * $Id$
  */
-int m_help(aClient *UNUSED(cptr), aClient *sptr, int UNUSED(parc), char *parv[])
-{
-  int i;
+#include "querycmds.h"
 
-  for (i = 0; msgtab[i].cmd; i++)
-    sendto_one(sptr, ":%s NOTICE %s :%s", me.name, parv[0], msgtab[i].cmd);
-  return 0;
-}
+#include <string.h>
 
 /* Counters of client/servers etc. */
-struct lusers_st nrof;
+struct UserStatistics UserStats;
 
 void init_counters(void)
 {
-  memset(&nrof, 0, sizeof(nrof));
-  nrof.servers = 1;
-}
-
-/*
- * m_lusers
- *
- * parv[0] = sender
- * parv[1] = ignored
- * parv[2] = server to query
- */
-int m_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  if (parc > 2)
-    if (hunt_server(1, cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv) !=
-       HUNTED_ISME)
-      return 0;
-
-  sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
-      nrof.clients - nrof.inv_clients, nrof.inv_clients, nrof.servers);
-  if (nrof.opers)
-    sendto_one(sptr, rpl_str(RPL_LUSEROP), me.name, parv[0], nrof.opers);
-  if (nrof.unknowns > 0)
-    sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN), me.name, parv[0],
-       nrof.unknowns);
-  if (nrof.channels > 0)
-    sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS), me.name, parv[0],
-       nrof.channels);
-  sendto_one(sptr, rpl_str(RPL_LUSERME), me.name, parv[0], nrof.local_clients,
-      nrof.local_servers);
-
-  if (MyUser(sptr) || Protocol(cptr) < 10)
-    sendto_one(sptr,
-       ":%s NOTICE %s :Highest connection count: %d (%d clients)",
-       me.name, parv[0], max_connection_count, max_client_count);
-  else
-    sendto_one(sptr,
-       "%s NOTICE %s%s :Highest connection count: %d (%d clients)",
-       NumServ(&me), NumNick(sptr), max_connection_count, max_client_count);
-
-  return 0;
-}
-
-/*
- * m_admin
- *
- * parv[0] = sender prefix
- * parv[1] = servername
- */
-int m_admin(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aConfItem *aconf;
-
-  if (MyConnect(sptr) && parc > 1)
-  {
-    aClient *acptr;
-    if (!(acptr = find_match_server(parv[1])))
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name, parv[0], parv[1]);
-      return 0;
-    }
-    parv[1] = acptr->name;
-  }
-  if (hunt_server(0, cptr, sptr, ":%s ADMIN :%s", 1, parc, parv) != HUNTED_ISME)
-    return 0;
-  if ((aconf = find_admin()))
-  {
-    sendto_one(sptr, rpl_str(RPL_ADMINME), me.name, parv[0], me.name);
-    sendto_one(sptr, rpl_str(RPL_ADMINLOC1), me.name, parv[0], aconf->host);
-    sendto_one(sptr, rpl_str(RPL_ADMINLOC2), me.name, parv[0], aconf->passwd);
-    sendto_one(sptr, rpl_str(RPL_ADMINEMAIL), me.name, parv[0], aconf->name);
-  }
-  else
-    sendto_one(sptr, err_str(ERR_NOADMININFO), me.name, parv[0], me.name);
-  return 0;
+  memset(&UserStats, 0, sizeof(UserStats));
+  UserStats.servers = 1;
 }
 
-/*
- * m_motd
- *
- * parv[0] - sender prefix
- * parv[1] - servername
- *
- * modified 30 mar 1995 by flux (cmlambertus@ucdavis.edu)
- * T line patch - display motd based on hostmask
- * modified again 7 sep 97 by Ghostwolf with code and ideas 
- * stolen from comstud & Xorath.  All motd files are read into
- * memory in read_motd() in s_conf.c
- *
- * When NODEFAULTMOTD is defined, then it is possible that
- * sptr == NULL, which means that this function is called from
- * register_user.
- */
-int m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  struct tm *tm = &motd_tm;    /* Default: Most general case */
-  atrecord *ptr;
-  int count;
-  register aMotdItem *temp;
-
-#ifdef NODEFAULTMOTD
-  int no_motd;
-
-  if (sptr)
-  {
-    no_motd = 0;
-#endif
-    if (hunt_server(0, cptr, sptr, ":%s MOTD :%s", 1, parc,
-       parv) != HUNTED_ISME)
-      return 0;
-#ifdef NODEFAULTMOTD
-  }
-  else
-  {
-    sptr = cptr;
-    no_motd = 1;
-  }
-#endif
-
-  /*
-   * Find out if this is a remote query or if we have a T line for our hostname
-   */
-  if (IsServer(cptr))
-  {
-    tm = NULL;                 /* Remote MOTD */
-    temp = rmotd;
-  }
-  else
-  {
-    for (ptr = tdata; ptr; ptr = ptr->next)
-    {
-      if (!match(ptr->hostmask, cptr->sockhost))
-       break;
-    }
-    if (ptr)
-    {
-      temp = ptr->tmotd;
-      tm = &ptr->tmotd_tm;
-    }
-    else
-      temp = motd;
-  }
-  if (temp == NULL)
-  {
-    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
-    return 0;
-  }
-#ifdef NODEFAULTMOTD
-  if (!no_motd)
-  {
-#endif
-    if (tm)                    /* Not remote? */
-    {
-      sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
-      sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_MOTD,
-         parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
-         tm->tm_hour, tm->tm_min);
-      count = 100;
-    }
-    else
-      count = 3;
-    for (; temp; temp = temp->next)
-    {
-      sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], temp->line);
-      if (--count == 0)
-       break;
-    }
-#ifdef NODEFAULTMOTD
-  }
-  else
-  {
-    sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
-    sendto_one(sptr, ":%s %d %s :%s", me.name, RPL_MOTD, parv[0],
-       "\ 2Type /MOTD to read the AUP before continuing using this service.\ 2");
-    sendto_one(sptr,
-       ":%s %d %s :The message of the day was last changed: %d/%d/%d", me.name,
-       RPL_MOTD, parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year);
-  }
-#endif
-  sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
-  return 0;
-}
index 5905c807b62b536e026ef7558ffda86c50f4c251..0e727c3d4e07a254eae2aeb1c60391a04362b646 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
+#include "random.h"
+#include "config.h"
 #include <stdlib.h>
 #include <stdio.h>
-#include "random.h"
+#include <sys/time.h>
 
-RCSTAG_CC("$Id$");
 
 char localkey[9] = RANDOM_SEED;
 
@@ -48,7 +49,7 @@ char localkey[9] = RANDOM_SEED;
 
 /* This is the central step in the MD5 algorithm. */
 #define MD5STEP(f, w, x, y, z, data, s) \
-       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+        ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
 
 /*
  * The core of the MD5 algorithm, this alters an existing MD5 hash to
index 806bbec6c5966e9e3e7c1dae2221fb4c6911a3d1..aa340710b2254046ad6756e340525beb5c02fc36 100644 (file)
@@ -1,63 +1,96 @@
 /*
- * ircd/res.c (C)opyright 1992, 1993, 1994 Darren Reed. All rights reserved.
- * This file may not be distributed without the author's prior permission in
- * any shape or form. The author takes no responsibility for any damage or
- * loss of property which results from the use of this software.  Distribution
- * of this file must include this notice.
+ * src/res.c (C)opyright 1992 Darren Reed. All rights reserved.
+ * This file may not be distributed without the author's permission in any
+ * shape or form. The author takes no responsibility for any damage or loss
+ * of property which results from the use of this software.
+ *
+ * $Id$
+ *
+ * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
+ *     added callbacks and reference counting of returned hostents.
+ *     --Bleep (Thomas Helvey <tomh@inxpress.net>)
  */
-
+#include "res.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_string.h"
+#include "numeric.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "sprintf_irc.h"
+#include "struct.h"
+#include "support.h"
 #include "sys.h"
-#include <signal.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
 #include <sys/socket.h>
-#if HAVE_UNISTD_H
+#include <fcntl.h>
 #include <unistd.h>
-#endif
-#include <netinet/in.h>
-#include <arpa/inet.h>
+
 #include <arpa/nameser.h>
 #include <resolv.h>
-/* dn_skipname is really an internal function,
-   we shouldn't be using it in res.c */
-#if !defined(dn_skipname) && !defined(__dn_skipname)
-extern int dn_skipname(const unsigned char *, const unsigned char *);
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <limits.h>
+#if (CHAR_BIT != 8)
+#error this code needs to be able to address individual octets 
 #endif
-#include "h.h"
-#include "res.h"
-#include "struct.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_misc.h"
-#include "s_bsd.h"
-#include "ircd.h"
-#include "s_ping.h"
-#include "support.h"
-#include "common.h"
-#include "sprintf_irc.h"
 
-RCSTAG_CC("$Id$");
+/*
+ * Some systems do not define INADDR_NONE (255.255.255.255)
+ * INADDR_NONE is actually a valid address, but it should never
+ * be returned from any nameserver.
+ * NOTE: The bit pattern for INADDR_NONE and INADDR_ANY (0.0.0.0) should be 
+ * the same on all hosts so we shouldn't need to use htonl or ntohl to
+ * compare or set the values.
+ */ 
+#ifndef INADDR_NONE
+#define INADDR_NONE ((unsigned int) 0xffffffff)
+#endif
 
-#define MAXPACKET      1024
+#define MAXPACKET       1024  /* rfc sez 512 but we expand names so ... */
+#define RES_MAXALIASES  35    /* maximum aliases allowed */
+#define RES_MAXADDRS    35    /* maximum addresses allowed */
 
-#define RES_MAXADDRS   35
-#define RES_MAXALIASES 35
+/*
+ * macros used to calulate offsets into fixed query buffer
+ */
+#define ALIAS_BLEN (size_t) ((RES_MAXALIASES + 1) * sizeof(char*))
+#define ADDRS_BLEN (size_t) ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
 
-#define ALIASBLEN ((RES_MAXALIASES + 1) * sizeof(char *))
-#define ADDRSBLEN ((RES_MAXADDRS + 1) * sizeof(struct in_addr *))
-#define ADDRSDLEN (RES_MAXADDRS * sizeof(struct in_addr))
-#define ALIASDLEN (MAXPACKET)
-#define MAXGETHOSTLEN (ALIASBLEN + ADDRSBLEN + ADDRSDLEN + ALIASDLEN)
+#define ADDRS_OFFSET  (size_t) (ALIAS_BLEN + ADDRS_BLEN)
+#define ADDRS_DLEN    (size_t) (RES_MAXADDRS * sizeof(struct in_addr))
+#define NAMES_OFFSET  (size_t) (ADDRS_OFFSET + ADDRS_DLEN)
+#define MAXGETHOSTLEN (size_t) (NAMES_OFFSET + MAXPACKET)
 
-#define AR_TTL         600     /* TTL in seconds for dns cache entries */
+#define AR_TTL          600   /* TTL in seconds for dns cache entries */
 
-#define ARES_CACSIZE   512
-#define MAXCACHED      2048
+/*
+ * the following values should be prime
+ */
+#define ARES_CACSIZE    307
+#define MAXCACHED       281
 
-#ifndef INT16SZ
-#define INT16SZ 2
-#endif
-#ifndef INT32SZ
-#define INT32SZ 4
-#endif
+/*
+ * RFC 1104/1105 wasn't very helpful about what these fields
+ * should be named, so for now, we'll just name them this way.
+ * we probably should look at what named calls them or something.
+ */
+#define TYPE_SIZE       (size_t) 2
+#define CLASS_SIZE      (size_t) 2
+#define TTL_SIZE        (size_t) 4
+#define RDLENGTH_SIZE   (size_t) 2
+#define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
 
 /*
  * Building the Hostent
@@ -71,16 +104,16 @@ RCSTAG_CC("$Id$");
  * allocated:
  *
  *          +-------------------------------+
- * buf:     | h_aliases pointer array       | Max size: ALIASBLEN;
+ * buf:     | h_aliases pointer array       | Max size: ALIAS_BLEN;
  *          | NULL                          | contains `char *'s
  *          |-------------------------------|
- *          | h_addr_list pointer array     | Max size: ADDRSBLEN;
+ *          | h_addr_list pointer array     | Max size: ADDRS_BLEN;
  *          | NULL                          | contains `struct in_addr *'s
  *          |-------------------------------|
- *          | h_addr_list addresses         | Max size: ADDRSDLEN;
+ *          | h_addr_list addresses         | Max size: ADDRS_DLEN;
  *          |                               | contains `struct in_addr's
  *          |-------------------------------|
- *          | storage for hostname strings  | Max size: ALIASDLEN;
+ *          | storage for hostname strings  | Max size: ALIAS_DLEN;
  *          +-------------------------------+ contains `char's
  *
  *  For requests the size of the h_aliases, and h_addr_list pointer
@@ -117,943 +150,1058 @@ RCSTAG_CC("$Id$");
  */
 
 typedef struct Hostent {
-  struct hostent h;
-  char *buf;
+  struct hostent h;      /* the hostent struct we are passing around */
+  char*          buf;    /* buffer for data pointed to from hostent */
 } aHostent;
 
-typedef struct reslist {
-  int id;
-  int sent;                    /* number of requests sent */
-  int srch;
-  time_t ttl;
-  char type;
-  char retries;                        /* retry counter */
-  char sends;                  /* number of sends (>1 means resent) */
-  char resend;                 /* send flag. 0 == dont resend */
-  time_t sentat;
-  time_t timeout;
-  struct in_addr addr;
-  char *name;
-  struct reslist *next;
-  Link cinfo;
-  aHostent he;
-} ResRQ;
-
-typedef struct cache {
-  time_t expireat;
-  time_t ttl;
-  aHostent he;
-  struct cache *hname_next, *hnum_next, *list_next;
-} aCache;
-
-typedef struct cachetable {
-  aCache *num_list;
-  aCache *name_list;
-} CacheTable;
-
-extern int resfd;              /* defined in s_bsd.c */
-
-static char hostbuf[HOSTLEN + 1];
-static char dot[] = ".";
-static int incache = 0;
-static CacheTable hashtable[ARES_CACSIZE];
-static aCache *cachetop = NULL;
-static ResRQ *last, *first;
-
-static void rem_cache(aCache *);
-static void rem_request(ResRQ *);
-static int do_query_name(Link *, char *, ResRQ *);
-static int do_query_number(Link *, struct in_addr *, ResRQ *);
-static void resend_query(ResRQ *);
-static int proc_answer(ResRQ *, HEADER *, unsigned char *, unsigned char *);
-static int query_name(char *, int, int, ResRQ *);
-static aCache *make_cache(ResRQ *);
-static aCache *find_cache_name(char *);
-static aCache *find_cache_number(ResRQ *, struct in_addr *);
-static int add_request(ResRQ *);
-static ResRQ *make_request(Link *);
-static int send_res_msg(char *, int, int);
-static ResRQ *find_id(int);
-static int hash_number(unsigned char *);
-static void update_list(ResRQ *, aCache *);
-static int hash_name(const char *);
-
-static struct cacheinfo {
-  int ca_adds;
-  int ca_dels;
-  int ca_expires;
-  int ca_lookups;
-  int ca_na_hits;
-  int ca_nu_hits;
-  int ca_updates;
+struct ResRequest {
+  struct ResRequest* next;
+  int                id;
+  int                sent;          /* number of requests sent */
+  time_t             ttl;
+  char               type;
+  char               retries;       /* retry counter */
+  char               sends;         /* number of sends (>1 means resent) */
+  char               resend;        /* send flag. 0 == dont resend */
+  time_t             sentat;
+  time_t             timeout;
+  struct in_addr     addr;
+  char*              name;
+  struct DNSQuery    query;         /* query callback for this request */
+  aHostent           he;
+};
+
+struct CacheEntry {
+  struct CacheEntry* hname_next;
+  struct CacheEntry* hnum_next;
+  struct CacheEntry* list_next;
+  time_t             expireat;
+  time_t             ttl;
+  struct Hostent     he;
+  struct DNSReply    reply;
+};
+
+struct CacheTable {
+  struct CacheEntry* num_list;
+  struct CacheEntry* name_list;
+};
+
+
+int ResolverFileDescriptor    = -1;   /* GLOBAL - used in s_bsd.c */
+
+static time_t nextDNSCheck    = 0;
+static time_t nextCacheExpire = 1;
+
+/*
+ * Keep a spare file descriptor open. res_init calls fopen to read the
+ * resolv.conf file. If ircd is hogging all the file descriptors below 256,
+ * on systems with crippled FILE structures this will cause wierd bugs.
+ * This is definitely needed for Solaris which uses an unsigned char to
+ * hold the file descriptor.  --Dianora
+ */ 
+static int                spare_fd = -1;
+
+static int                cachedCount = 0;
+static struct CacheTable  hashtable[ARES_CACSIZE];
+static struct CacheEntry* cacheTop;
+static struct ResRequest* requestListHead;   /* head of resolver request list */
+static struct ResRequest* requestListTail;   /* tail of resolver request list */
+
+
+static void     add_request(struct ResRequest* request);
+static void     rem_request(struct ResRequest* request);
+static struct ResRequest*   make_request(const struct DNSQuery* query);
+static void     rem_cache(struct CacheEntry*);
+static void     do_query_name(const struct DNSQuery* query, 
+                              const char* name, 
+                              struct ResRequest* request);
+static void     do_query_number(const struct DNSQuery* query,
+                                const struct in_addr*, 
+                                struct ResRequest* request);
+static void     query_name(const char* name, 
+                           int query_class, 
+                           int query_type, 
+                           struct ResRequest* request);
+static void     resend_query(struct ResRequest* request);
+static struct CacheEntry*  make_cache(struct ResRequest* request);
+static struct CacheEntry*  find_cache_name(const char* name);
+static struct CacheEntry*  find_cache_number(struct ResRequest* request, 
+                                             const char* addr);
+static struct ResRequest*   find_id(int);
+
+static  struct cacheinfo {
+  int  ca_adds;
+  int  ca_dels;
+  int  ca_expires;
+  int  ca_lookups;
+  int  ca_na_hits;
+  int  ca_nu_hits;
+  int  ca_updates;
 } cainfo;
 
-static struct resinfo {
-  int re_errors;
-  int re_nu_look;
-  int re_na_look;
-  int re_replies;
-  int re_requests;
-  int re_resends;
-  int re_sent;
-  int re_timeouts;
-  int re_shortttl;
-  int re_unkrep;
+static  struct  resinfo {
+  int  re_errors;
+  int  re_nu_look;
+  int  re_na_look;
+  int  re_replies;
+  int  re_requests;
+  int  re_resends;
+  int  re_sent;
+  int  re_timeouts;
+  int  re_shortttl;
+  int  re_unkrep;
 } reinfo;
 
-int init_resolver(void)
-{
-  int on = 1;
-  int fd = -1;
 
-  memset(&reinfo, 0, sizeof(reinfo));
-  memset(&cainfo, 0, sizeof(cainfo));
-  memset(hashtable, 0, sizeof(hashtable));
+/*
+ * From bind 8.3, these aren't declared in earlier versions of bind
+ */
+extern u_short  _getshort(const u_char *);
+extern u_int    _getlong(const u_char *);
+/*
+ * int
+ * res_isourserver(ina)
+ *      looks up "ina" in _res.ns_addr_list[]
+ * returns:
+ *      0  : not found
+ *      >0 : found
+ * author:
+ *      paul vixie, 29may94
+ */
+static int
+res_ourserver(const struct __res_state* statp, const struct sockaddr_in *inp) 
+{
+  struct sockaddr_in ina;
+  int ns;
+
+  ina = *inp;
+  for (ns = 0;  ns < statp->nscount;  ns++) {
+    const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
+
+    if (srv->sin_family == ina.sin_family &&
+         srv->sin_port == ina.sin_port &&
+         (srv->sin_addr.s_addr == INADDR_ANY ||
+          srv->sin_addr.s_addr == ina.sin_addr.s_addr))
+             return (1);
+  }
+  return (0);
+}
 
-  first = last = NULL;
+/*
+ * start_resolver - do everything we need to read the resolv.conf file
+ * and initialize the resolver file descriptor if needed
+ */
+static void start_resolver(void)
+{
+  Debug((DEBUG_DNS, "Resolver: start_resolver"));
+  /*
+   * close the spare file descriptor so res_init can read resolv.conf
+   * successfully. Needed on Solaris
+   */
+  if (spare_fd > -1)
+    close(spare_fd);
 
-  /* res_init() always returns 0 */
-  (void)res_init();
+  res_init();      /* res_init always returns 0 */
+  /*
+   * make sure we have a valid file descriptor below 256 so we can
+   * do this again. Needed on Solaris
+   */
+  spare_fd = open("/dev/null",O_RDONLY,0);
+  if ((spare_fd < 0) || (spare_fd > 255)) {
+    char sparemsg[80];
+    sprintf_irc(sparemsg, "invalid spare_fd %d", spare_fd);
+    server_restart(sparemsg);
+  }
 
-  if (!_res.nscount)
-  {
+  if (!_res.nscount) {
     _res.nscount = 1;
     _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
   }
-#ifdef DEBUGMODE
-  _res.options |= RES_DEBUG;
-#endif
-
-  alarm(2);
-  fd = socket(AF_INET, SOCK_DGRAM, 0);
-  alarm(0);
-  if (fd < 0)
-  {
-    if (errno == EMFILE || errno == ENOBUFS)
-    {
-      /*
-       * Only try this one more time, if we can't create the resolver
-       * socket at initialization time, it's pointless to continue.
-       */
-      alarm(2);
-      if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
-      {
-       alarm(0);
-       Debug((DEBUG_ERROR, "init_resolver: socket: No more sockets"));
-       return -1;
-      }
-      alarm(0);
-    }
-    else
-    {
-      Debug((DEBUG_ERROR, "init_resolver: socket: %s", strerror(errno)));
-      return -1;
+  _res.options |= RES_NOALIASES;
+
+  if (ResolverFileDescriptor < 0) {
+    ResolverFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
+    if (-1 == ResolverFileDescriptor) {
+      report_error("Resolver: error creating socket for %s: %s", 
+                   me.name, errno);
+      return;
     }
+    if (!os_set_nonblocking(ResolverFileDescriptor))
+      report_error("Resolver: error setting non-blocking for %s: %s", 
+                   me.name, errno);
   }
-  setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (OPT_TYPE *)&on, sizeof(on));
-  return fd;
 }
 
-static int add_request(ResRQ *new_request)
+/*
+ * init_resolver - initialize resolver and resolver library
+ */
+int init_resolver(void)
 {
-  if (!new_request)
-    return -1;
-  if (!first)
-    first = last = new_request;
-  else
-  {
-    last->next = new_request;
-    last = new_request;
-  }
-  new_request->next = NULL;
-  reinfo.re_requests++;
-  return 0;
+  Debug((DEBUG_DNS, "Resolver: init_resolver"));
+#ifdef  LRAND48
+  srand48(CurrentTime);
+#endif
+  memset(&cainfo,   0, sizeof(cainfo));
+  memset(hashtable, 0, sizeof(hashtable));
+  memset(&reinfo,   0, sizeof(reinfo));
+
+  requestListHead = requestListTail = NULL;
+
+  errno = h_errno = 0;
+  start_resolver();
+  Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s",
+         ResolverFileDescriptor, errno, h_errno, strerror(errno)));
+  return ResolverFileDescriptor;
 }
 
 /*
- * Remove a request from the list. This must also free any memory that has
- * been allocated for temporary storage of DNS results.
+ * restart_resolver - flush the cache, reread resolv.conf, reopen socket
  */
-static void rem_request(ResRQ *old_request)
+void restart_resolver(void)
 {
-  ResRQ **rptr;
-  ResRQ *r2ptr = NULL;
+  /* flush_cache();  flush the dns cache */
+  start_resolver();
+}
 
-  if (old_request)
-  {
-    for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next)
-    {
-      if (*rptr == old_request)
-      {
-       *rptr = old_request->next;
-       if (last == old_request)
-         last = r2ptr;
-       break;
+/*
+ * add_local_domain - Add the domain to hostname, if it is missing
+ * (as suggested by eps@TOASTER.SFSU.EDU)
+ */
+void add_local_domain(char* hname, size_t size)
+{
+  assert(0 != hname);
+  /* 
+   * try to fix up unqualified names 
+   */
+  if ((_res.options & RES_DEFNAMES) && !strchr(hname, '.')) {
+    if (_res.defdname[0]) {
+      size_t len = strlen(hname);
+      if ((strlen(_res.defdname) + len + 2) < size) {
+        hname[len++] = '.';
+        strcpy(hname + len, _res.defdname);
       }
     }
-    Debug((DEBUG_DNS, "rem_request:Remove %p at %p %p",
-       old_request, *rptr, r2ptr));
-
-    if (old_request->he.buf)
-      RunFree(old_request->he.buf);
-    if (old_request->name)
-      RunFree(old_request->name);
-    RunFree(old_request);
   }
 }
 
 /*
- * Create a DNS request record for the server.
+ * add_request - place a new request in the request list
  */
-static ResRQ *make_request(Link *lp)
+static void add_request(struct ResRequest* request)
 {
-  ResRQ *nreq;
+  assert(0 != request);
+  if (!requestListHead)
+    requestListHead = requestListTail = request;
+  else {
+    requestListTail->next = request;
+    requestListTail = request;
+  }
+  request->next = NULL;
+  ++reinfo.re_requests;
+}
 
-  if ((nreq = (ResRQ *)RunMalloc(sizeof(ResRQ))) == NULL)
-    return NULL;
-  memset(nreq, 0, sizeof(ResRQ));
-  nreq->sentat = now;
-  nreq->retries = 3;
-  nreq->resend = 1;
-  nreq->srch = -1;
-  if (lp)
-    memcpy(&nreq->cinfo, lp, sizeof(Link));
-  else
-    memset(&nreq->cinfo, 0, sizeof(Link));
-  nreq->timeout = 4;           /* start at 4 and exponential inc. */
-  nreq->addr.s_addr = INADDR_NONE;
-
-  nreq->he.h.h_addrtype = AF_INET;
-  nreq->he.h.h_length = sizeof(struct in_addr);
-  add_request(nreq);
-  return nreq;
+/*
+ * rem_request - remove a request from the list. 
+ * This must also free any memory that has been allocated for 
+ * temporary storage of DNS results.
+ */
+static void rem_request(struct ResRequest* request)
+{
+  struct ResRequest** current;
+  struct ResRequest*  prev = NULL;
+
+  assert(0 != request);
+  for (current = &requestListHead; *current; ) {
+    if (*current == request) {
+      *current = request->next;
+      if (requestListTail == request)
+        requestListTail = prev;
+      break;
+    } 
+    prev    = *current;
+    current = &(*current)->next;
+  }
+  MyFree(request->he.buf);
+  MyFree(request->name);
+  MyFree(request);
 }
 
 /*
- * Remove queries from the list which have been there too long without
- * being resolved.
+ * make_request - Create a DNS request record for the server.
  */
-time_t timeout_query_list(void)
+static struct ResRequest* make_request(const struct DNSQuery* query)
 {
-  ResRQ *rptr;
-  ResRQ *r2ptr;
-  time_t next = 0;
-  time_t tout = 0;
-  aClient *cptr;
-
-  Debug((DEBUG_DNS, "timeout_query_list at %s", myctime(now)));
-  for (rptr = first; rptr; rptr = r2ptr)
-  {
-    r2ptr = rptr->next;
-    tout = rptr->sentat + rptr->timeout;
-    if (now >= tout)
-    {
-      if (--rptr->retries <= 0)
-      {
-       Debug((DEBUG_DNS, "timeout %p now " TIME_T_FMT " cptr %p",
-           rptr, now, rptr->cinfo.value.cptr));
-       reinfo.re_timeouts++;
-       cptr = rptr->cinfo.value.cptr;
-       switch (rptr->cinfo.flags)
-       {
-         case ASYNC_CLIENT:
-           ClearDNS(cptr);
-           if (!DoingAuth(cptr))
-             SetAccess(cptr);
-           break;
-         case ASYNC_PING:
-           sendto_ops("Host %s unknown", rptr->name);
-           end_ping(cptr);
-           break;
-         case ASYNC_CONNECT:
-           sendto_ops("Host %s unknown", rptr->name);
-           break;
-       }
-       rem_request(rptr);
-       rptr = NULL;
-       continue;
+  struct ResRequest* request;
+  assert(0 != query);
+  request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
+  memset(request, 0, sizeof(struct ResRequest));
+
+  request->sentat           = CurrentTime;
+  request->retries          = 3;
+  request->resend           = 1;
+  request->timeout          = 5;    /* start at 5 per RFC1123 */
+  request->addr.s_addr      = INADDR_NONE;
+  request->he.h.h_addrtype  = AF_INET;
+  request->he.h.h_length    = sizeof(struct in_addr);
+  request->query.vptr       = query->vptr;
+  request->query.callback   = query->callback;
+
+#if defined(NULL_POINTER_NOT_ZERO)
+  request->next             = NULL;
+  request->he.buf           = NULL;
+  request->he.h.h_name      = NULL;
+  request->he.h.h_aliases   = NULL;
+  request->he.h.h_addr_list = NULL;
+#endif
+  add_request(request);
+  return request;
+}
+
+/*
+ * timeout_query_list - Remove queries from the list which have been 
+ * there too long without being resolved.
+ */
+static time_t timeout_query_list(time_t now)
+{
+  struct ResRequest* request;
+  struct ResRequest* next_request = 0;
+  time_t             next_time    = 0;
+  time_t             timeout      = 0;
+
+  Debug((DEBUG_DNS, "Resolver: timeout_query_list at %s", myctime(now)));
+  for (request = requestListHead; request; request = next_request) {
+    next_request = request->next;
+    timeout = request->sentat + request->timeout;
+    if (timeout < now) {
+      if (--request->retries <= 0) {
+        ++reinfo.re_timeouts;
+        (*request->query.callback)(request->query.vptr, 0);
+        rem_request(request);
+        continue;
       }
-      else
-      {
-       rptr->sentat = now;
-       rptr->timeout += rptr->timeout;
-       resend_query(rptr);
-       tout = now + rptr->timeout;
-       Debug((DEBUG_DNS, "r %p now " TIME_T_FMT " retry %d c %p",
-           rptr, now, rptr->retries, rptr->cinfo.value.cptr));
+      else {
+        request->sentat = now;
+        request->timeout += request->timeout;
+        resend_query(request);
       }
     }
-    if (!next || tout < next)
-      next = tout;
+    if (!next_time || timeout < next_time) {
+      next_time = timeout;
+    }
   }
-  Debug((DEBUG_DNS, "Next timeout_query_list() at %s, %ld",
-      myctime((next > now) ? next : (now + AR_TTL)),
-      (next > now) ? (next - now) : AR_TTL));
-  return (next > now) ? next : (now + AR_TTL);
+  return (next_time > now) ? next_time : (now + AR_TTL);
 }
 
 /*
- * del_queries
- *
- * Called by the server to cleanup outstanding queries for
- * which there no longer exist clients or conf lines.
+ * expire_cache - removes entries from the cache which are older 
+ * than their expiry times. returns the time at which the server 
+ * should next poll the cache.
  */
-void del_queries(char *cp)
+static time_t expire_cache(time_t now)
 {
-  ResRQ *rptr, *r2ptr;
+  struct CacheEntry* cp;
+  struct CacheEntry* cp_next;
+  time_t             expire = 0;
+
+  Debug((DEBUG_DNS, "Resolver: expire_cache at %s", myctime(now)));
+  for (cp = cacheTop; cp; cp = cp_next) {
+    cp_next = cp->list_next;
+    if (cp->expireat < now) {
+      ++cainfo.ca_expires;
+      rem_cache(cp);
+    }
+    else if (!expire || expire > cp->expireat)
+      expire = cp->expireat;
+  }
+  return (expire > now) ? expire : (now + AR_TTL);
+}
 
-  for (rptr = first; rptr; rptr = r2ptr)
-  {
-    r2ptr = rptr->next;
-    if (cp == rptr->cinfo.value.cp)
-      rem_request(rptr);
+/*
+ * timeout_resolver - check request list and cache for expired entries
+ */
+time_t timeout_resolver(time_t now)
+{
+  if (nextDNSCheck < now)
+    nextDNSCheck = timeout_query_list(now);
+  if (nextCacheExpire < now)
+    nextCacheExpire = expire_cache(now);
+  return IRCD_MIN(nextDNSCheck, nextCacheExpire);
+}
+
+
+/*
+ * delete_resolver_queries - cleanup outstanding queries 
+ * for which there no longer exist clients or conf lines.
+ */
+void delete_resolver_queries(const void* vptr)
+{
+  struct ResRequest* request;
+  struct ResRequest* next_request;
+
+  for (request = requestListHead; request; request = next_request) {
+    next_request = request->next;
+    if (vptr == request->query.vptr)
+      rem_request(request);
   }
 }
 
 /*
- * send_res_msg
- *
- * sends msg to all nameservers found in the "_res" structure.
+ * send_res_msg - sends msg to all nameservers found in the "_res" structure.
  * This should reflect /etc/resolv.conf. We will get responses
  * which arent needed but is easier than checking to see if nameserver
- * isnt present. Returns number of messages successfully sent to
+ * isnt present. Returns number of messages successfully sent to 
  * nameservers or -1 if no successful sends.
  */
-static int send_res_msg(char *msg, int len, int rcount)
+static int send_res_msg(const u_char* msg, int len, int rcount)
 {
   int i;
-  int sent = 0, max;
+  int sent = 0;
+  int max_queries = IRCD_MIN(_res.nscount, rcount);
 
-  if (!msg)
-    return -1;
+  assert(0 != msg);
+  /*
+   * RES_PRIMARY option is not implemented
+   * if (_res.options & RES_PRIMARY || 0 == max_queries)
+   */
+  if (0 == max_queries)
+    max_queries = 1;
 
-  max = MIN(_res.nscount, rcount);
-  if (_res.options & RES_PRIMARY)
-    max = 1;
-  if (!max)
-    max = 1;
+  Debug((DEBUG_DNS, "Resolver: sendto %d", max_queries));
 
-  for (i = 0; i < max; ++i)
-  {
-    _res.nsaddr_list[i].sin_family = AF_INET;
-    if (sendto(resfd, msg, len, 0, (struct sockaddr *)&(_res.nsaddr_list[i]),
-       sizeof(struct sockaddr)) == len)
-    {
-      reinfo.re_sent++;
-      sent++;
+  for (i = 0; i < max_queries; i++) {
+    if (sendto(ResolverFileDescriptor, msg, len, 0, 
+               (struct sockaddr*) &(_res.nsaddr_list[i]),
+               sizeof(struct sockaddr_in)) == len) {
+      ++reinfo.re_sent;
+      ++sent;
     }
     else
-      Debug((DEBUG_ERROR, "s_r_m:sendto: %s on %d", strerror(errno), resfd));
+      ircd_log(L_ERROR, "Resolver: send failed %s", strerror(errno));
   }
-  return (sent) ? sent : -1;
+  return sent;
 }
 
 /*
- * find a dns request id (id is determined by dn_mkquery)
+ * find_id - find a dns request id (id is determined by dn_mkquery)
  */
-static ResRQ *find_id(int id)
+static struct ResRequest* find_id(int id)
 {
-  ResRQ *rptr;
+  struct ResRequest* request;
 
-  for (rptr = first; rptr; rptr = rptr->next)
-    if (rptr->id == id)
-      return rptr;
+  for (request = requestListHead; request; request = request->next) {
+    if (request->id == id)
+      return request;
+  }
   return NULL;
 }
 
 /*
- * add_local_domain
- *
- * Add the domain to hostname, if it is missing
- * (as suggested by eps@TOASTER.SFSU.EDU)
+ * gethost_byname - get host address from name
  */
-void add_local_domain(char *hname, int size)
+struct DNSReply* gethost_byname(const char* name, 
+                               const struct DNSQuery* query)
 {
-  /* try to fix up unqualified names */
-  if (!strchr(hname, '.'))
-  {
-    if (_res.defdname[0] && size > 0)
-    {
-      strcat(hname, ".");
-      strncat(hname, _res.defdname, size - 1);
-    }
-  }
-}
+  struct CacheEntry* cp;
+  assert(0 != name);
 
-struct hostent *gethost_byname(char *name, Link *lp)
-{
-  aCache *cp;
-
-  reinfo.re_na_look++;
+  Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
+  ++reinfo.re_na_look;
   if ((cp = find_cache_name(name)))
-    return &cp->he.h;
-  if (lp)
-    do_query_name(lp, name, NULL);
+    return &(cp->reply);
+
+  do_query_name(query, name, NULL);
+  nextDNSCheck = 1;
   return NULL;
 }
 
-struct hostent *gethost_byaddr(struct in_addr *addr, Link *lp)
+/*
+ * gethost_byaddr - get host name from address
+ */
+struct DNSReply* gethost_byaddr(const char* addr,
+                                const struct DNSQuery* query)
 {
-  aCache *cp;
+  struct CacheEntry *cp;
+
+  assert(0 != addr);
+
+  Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
 
-  reinfo.re_nu_look++;
+  ++reinfo.re_nu_look;
   if ((cp = find_cache_number(NULL, addr)))
-    return &cp->he.h;
-  if (!lp)
-    return NULL;
-  do_query_number(lp, addr, NULL);
+    return &(cp->reply);
+
+  do_query_number(query, (const struct in_addr*) addr, NULL);
+  nextDNSCheck = 1;
   return NULL;
 }
 
-static int do_query_name(Link *lp, char *name, ResRQ *rptr)
+/*
+ * do_query_name - nameserver lookup name
+ */
+static void do_query_name(const struct DNSQuery* query, 
+                          const char* name, struct ResRequest* request)
 {
-  char hname[HOSTLEN + 1];
-  int len;
-
-  strncpy(hname, name, sizeof(hname) - 1);
-  hname[sizeof(hname) - 1] = 0;
-  len = strlen(hname);
-
-  if (rptr && !strchr(hname, '.') && _res.options & RES_DEFNAMES)
-  {
-    strncat(hname, dot, sizeof(hname) - len - 1);
-    len++;
-    strncat(hname, _res.defdname, sizeof(hname) - len - 1);
-  }
+  char  hname[HOSTLEN + 1];
+  assert(0 != name);
 
+  ircd_strncpy(hname, name, HOSTLEN);
+  hname[HOSTLEN] = '\0';
+#if 0
   /*
-   * Store the name passed as the one to lookup and generate other host
-   * names to pass onto the nameserver(s) for lookups.
+   * removed, this is incorrect for anything it's used for
    */
-  if (!rptr)
-  {
-    if ((rptr = make_request(lp)) == NULL)
-      return -1;
-    rptr->type = T_A;
-    rptr->name = (char *)RunMalloc(strlen(name) + 1);
-    strcpy(rptr->name, name);
+  add_local_domain(hname, HOSTLEN);
+#endif
+
+  if (!request) {
+    request       = make_request(query);
+    request->type = T_A;
+    request->name = (char*) MyMalloc(strlen(hname) + 1);
+    strcpy(request->name, hname);
   }
-  return (query_name(hname, C_IN, T_A, rptr));
+  query_name(hname, C_IN, T_A, request);
 }
 
 /*
- * Use this to do reverse IP# lookups.
+ * do_query_number - Use this to do reverse IP# lookups.
  */
-static int do_query_number(Link *lp, struct in_addr *numb, ResRQ *rptr)
+static void do_query_number(const struct DNSQuery* query, 
+                            const struct in_addr* addr,
+                            struct ResRequest* request)
 {
-  char ipbuf[32];
-  Reg2 unsigned char *cp = (unsigned char *)&numb->s_addr;
+  char  ipbuf[32];
+  const unsigned char* cp;
 
+  assert(0 != addr);
+  cp = (const unsigned char*) &addr->s_addr;
   sprintf_irc(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
-      (unsigned int)(cp[3]), (unsigned int)(cp[2]),
-      (unsigned int)(cp[1]), (unsigned int)(cp[0]));
+              (unsigned int)(cp[3]), (unsigned int)(cp[2]),
+              (unsigned int)(cp[1]), (unsigned int)(cp[0]));
 
-  if (!rptr)
-  {
-    if ((rptr = make_request(lp)) == NULL)
-      return -1;
-    rptr->type = T_PTR;
-    rptr->addr.s_addr = numb->s_addr;
+  if (!request) {
+    request              = make_request(query);
+    request->type        = T_PTR;
+    request->addr.s_addr = addr->s_addr;
   }
-  return (query_name(ipbuf, C_IN, T_PTR, rptr));
+  query_name(ipbuf, C_IN, T_PTR, request);
 }
 
 /*
- * generate a query based on class, type and name.
+ * query_name - generate a query based on class, type and name.
  */
-static int query_name(char *name, int q_class, int type, ResRQ *rptr)
+static void query_name(const char* name, int query_class,
+                       int type, struct ResRequest* request)
 {
-  struct timeval tv;
   char buf[MAXPACKET];
-  int r, s, k = 0;
-  HEADER *hptr;
+  int  request_len = 0;
 
-  Debug((DEBUG_DNS, "query_name: na %s cl %d ty %d", name, q_class, type));
+  assert(0 != name);
+  assert(0 != request);
+
+  Debug((DEBUG_DNS, "Resolver: query_name: %s %d %d", name, query_class, type));
   memset(buf, 0, sizeof(buf));
-  r = res_mkquery(QUERY, name, q_class, type, NULL, 0, NULL,
-      (unsigned char *)buf, sizeof(buf));
-  if (r <= 0)
-  {
-    h_errno = NO_RECOVERY;
-    return r;
-  }
-  hptr = (HEADER *) buf;
-  gettimeofday(&tv, NULL);
-  do
-  {
-    /* htons/ntohs can be assembler macros, which cannot
-       be nested. Thus two lines.   -Vesa */
-    unsigned short int nstmp = ntohs(hptr->id) + k
-       + (unsigned short int)(tv.tv_usec & 0xffff);
-    hptr->id = htons(nstmp);
-    k++;
-  }
-  while (find_id(ntohs(hptr->id)));
-  rptr->id = ntohs(hptr->id);
-  rptr->sends++;
-  s = send_res_msg(buf, r, rptr->sends);
-  if (s == -1)
-  {
-    h_errno = TRY_AGAIN;
-    return -1;
+  if ((request_len = res_mkquery(QUERY, name, query_class, type, 
+                                 NULL, 0, NULL, buf, sizeof(buf))) > 0) {
+    HEADER* header = (HEADER*) buf;
+#ifndef LRAND48
+    int            k = 0;
+    struct timeval tv;
+#endif
+    /*
+     * generate a unique id
+     * NOTE: we don't have to worry about converting this to and from
+     * network byte order, the nameserver does not interpret this value
+     * and returns it unchanged
+     */
+#ifdef LRAND48
+    do {
+      header->id = (header->id + lrand48()) & 0xffff;
+    } while (find_id(header->id));
+#else
+    gettimeofday(&tv, NULL);
+    do {
+      header->id = (header->id + k + tv.tv_usec) & 0xffff;
+      ++k;
+    } while (find_id(header->id));
+#endif /* LRAND48 */
+    request->id = header->id;
+    ++request->sends;
+    Debug((DEBUG_DNS, "Resolver: query_name %d: %s %d %d", request->id, 
+          name, query_class, type));
+    request->sent += send_res_msg(buf, request_len, request->sends);
   }
-  else
-    rptr->sent += s;
-  return 0;
 }
 
-static void resend_query(ResRQ *rptr)
+static void resend_query(struct ResRequest* request)
 {
-  if (rptr->resend == 0)
+  assert(0 != request);
+
+  if (request->resend == 0)
     return;
-  reinfo.re_resends++;
-  switch (rptr->type)
-  {
-    case T_PTR:
-      do_query_number(NULL, &rptr->addr, rptr);
-      break;
-    case T_A:
-      do_query_name(NULL, rptr->name, rptr);
-      break;
-    default:
-      break;
+  ++reinfo.re_resends;
+  switch(request->type) {
+  case T_PTR:
+    do_query_number(NULL, &request->addr, request);
+    break;
+  case T_A:
+    do_query_name(NULL, request->name, request);
+    break;
+  default:
+    break;
   }
-  return;
 }
 
 /*
- * proc_answer
- *
- * Process name server reply.
+ * proc_answer - process name server reply
+ * build a hostent struct in the passed request
  */
-static int proc_answer(ResRQ *rptr, HEADER * hptr, unsigned char *buf,
-    unsigned char *eob)
+static int proc_answer(struct ResRequest* request, HEADER* header,
+                       u_char* buf, u_char* eob)
 {
-  unsigned char *cp = buf + sizeof(HEADER);
-  char **alias;
-  char **addr;
-  char *p;                     /* pointer to strings */
-  char *a;                     /* pointer to address list */
-  char *endp;                  /* end of our buffer */
-  struct hostent *hp = &rptr->he.h;
-  int addr_class, type, dlen, ans = 0, n;
-  int addr_count = 0;
-  int alias_count = 0;
-
+  char   hostbuf[HOSTLEN + 1]; /* working buffer */
+  u_char* current;             /* current position in buf */
+  char** alias;                /* alias list */
+  char** addr;                 /* address list */
+  char*  name;                 /* pointer to name string */
+  char*  address;              /* pointer to address */
+  char*  endp;                 /* end of our buffer */
+  int    query_class;          /* answer class */
+  int    type;                 /* answer type */
+  int    rd_length;            /* record data length */
+  int    answer_count = 0;     /* answer counter */
+  int    n;                    /* temp count */
+  int    addr_count  = 0;      /* number of addresses in hostent */
+  int    alias_count = 0;      /* number of aliases in hostent */
+  struct hostent* hp;          /* hostent getting filled */
+
+  assert(0 != request);
+  assert(0 != header);
+  assert(0 != buf);
+  assert(0 != eob);
+  
+  current = buf + sizeof(HEADER);
+  hp = &(request->he.h);
   /*
-   * Lazy allocation of rptr->he.buf, we don't allocate a buffer
-   * unless there's something to put in it.
+   * lazy allocation of request->he.buf, we don't allocate a buffer
+   * unless there is something to put in it.
    */
-  if (!rptr->he.buf)
-  {
-    if ((rptr->he.buf = (char *)RunMalloc(MAXGETHOSTLEN)) == NULL)
-      return 0;
-    /* 
-     * Array of alias list pointers starts at beginning of buf 
-     */
-    rptr->he.h.h_aliases = (char **)rptr->he.buf;
-    rptr->he.h.h_aliases[0] = NULL;
-    /* 
-     * Array of address list pointers starts after alias list pointers.
-     * The actual addresses follow the address list pointers.
+  if (!request->he.buf) {
+    request->he.buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
+    request->he.buf[MAXGETHOSTLEN] = '\0';
+    /*
+     * array of alias list pointers starts at beginning of buf
      */
-    rptr->he.h.h_addr_list = (char **)(rptr->he.buf + ALIASBLEN);
-    a = (char *)rptr->he.h.h_addr_list + ADDRSBLEN;
+    hp->h_aliases = (char**) request->he.buf;
+    hp->h_aliases[0] = NULL;
     /*
-       * don't copy the host address to the beginning of h_addr_list
-       * make it just a little bit harder for the script kiddies
+     * array of address list pointers starts after alias list pointers
+     * the actual addresses follow the the address list pointers
+     */ 
+    hp->h_addr_list = (char**)(request->he.buf + ALIAS_BLEN);
+    /*
+     * don't copy the host address to the beginning of h_addr_list
      */
-    rptr->he.h.h_addr_list[0] = NULL;
+    hp->h_addr_list[0] = NULL;
   }
-  endp = &rptr->he.buf[MAXGETHOSTLEN];
-
-  /* find the end of the address list */
+  endp = request->he.buf + MAXGETHOSTLEN;
+  /*
+   * find the end of the address list
+   */
   addr = hp->h_addr_list;
-  while (*addr)
-  {
+  while (*addr) {
     ++addr;
     ++addr_count;
   }
-  /* make 'a' point to the first available empty address slot */
-  a = (char *)hp->h_addr_list + ADDRSBLEN +
-      (addr_count * sizeof(struct in_addr));
-
-  /* find the end of the alias list */
+  /*
+   * make address point to first available address slot
+   */
+  address = request->he.buf + ADDRS_OFFSET +
+                    (sizeof(struct in_addr) * addr_count);
+  /*
+   * find the end of the alias list
+   */
   alias = hp->h_aliases;
-  while (*alias)
-  {
+  while (*alias) {
     ++alias;
     ++alias_count;
   }
-  /* make p point to the first available space in rptr->buf */
-  if (alias_count > 0)
-  {
-    p = (char *)hp->h_aliases[alias_count - 1];
-    p += (strlen(p) + 1);
+  /*
+   * make name point to first available space in request->buf
+   */
+  if (alias_count > 0) {
+    name = hp->h_aliases[alias_count - 1];
+    name += (strlen(name) + 1);
   }
   else if (hp->h_name)
-    p = (char *)(hp->h_name + strlen(hp->h_name) + 1);
+    name = hp->h_name + strlen(hp->h_name) + 1;
   else
-    p = (char *)rptr->he.h.h_addr_list + ADDRSBLEN + ADDRSDLEN;
-
+    name = request->he.buf + ADDRS_OFFSET + ADDRS_DLEN;
   /*
-   * Skip past query's
-   */
-#ifdef SOL2                    /* brain damaged compiler (Solaris2) it seems */
-  for (; hptr->qdcount > 0; hptr->qdcount--)
-#else
-  while (hptr->qdcount-- > 0)
-#endif
-  {
-    if ((n = dn_skipname(cp, eob)) == -1)
+   * skip past queries
+   */ 
+  while (header->qdcount-- > 0) {
+    if ((n = dn_skipname(current, eob)) < 0)
       break;
-    else
-      cp += (n + QFIXEDSZ);
+    current += (n + QFIXEDSZ);
   }
   /*
-   * Proccess each answer sent to us blech.
+   * process each answer sent to us blech.
    */
-  while (hptr->ancount-- > 0 && cp && cp < eob && p < endp)
-  {
-    if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) <= 0)
-    {
-      Debug((DEBUG_DNS, "dn_expand failed"));
-      break;
+  while (header->ancount-- > 0 && current < eob && name < endp) {
+    n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
+    if (n <= 0) {
+      /*
+       * no more answers left
+       */
+      return answer_count;
     }
+    hostbuf[HOSTLEN] = '\0';
+    /* 
+     * With Address arithmetic you have to be very anal
+     * this code was not working on alpha due to that
+     * (spotted by rodder/jailbird/dianora)
+     */
+    current += (size_t) n;
 
-    cp += n;
-    /* XXX magic numbers, this checks for truncated packets */
-    if ((cp + INT16SZ + INT16SZ + INT32SZ + INT16SZ) >= eob)
+    if (!((current + ANSWER_FIXED_SIZE) < eob))
       break;
 
-    /*
-     * I have no idea why - maybe a bug in the linker? But _getshort
-     * and _getlong don't work anymore.  So lets do it ourselfs:
-     * --Run
-     */
+    type = _getshort(current);
+    current += TYPE_SIZE;
 
-    type = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
-    cp += INT16SZ;
-    addr_class = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
-    cp += INT16SZ;
-    rptr->ttl =
-       ((u_int32_t) cp[0] << 24) | ((u_int32_t) cp[1] << 16) | ((u_int32_t)
-       cp[2] << 8) | ((u_int32_t) cp[3]);
-    cp += INT32SZ;
-    dlen = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
-    cp += INT16SZ;
-
-    rptr->type = type;
-
-    /* check for bad dlen */
-    if ((cp + dlen) > eob)
-      break;
+    query_class = _getshort(current);
+    current += CLASS_SIZE;
+
+    request->ttl = _getlong(current);
+    current += TTL_SIZE;
+
+    rd_length = _getshort(current);
+    current += RDLENGTH_SIZE;
 
     /* 
-     * Add default domain name to returned host name if host name
-     * doesn't contain any dot separators.
-     * Name server never returns with trailing '.'
+     * Wait to set request->type until we verify this structure 
      */
-    if (!strchr(hostbuf, '.') && (_res.options & RES_DEFNAMES))
-    {
-      strcat(hostbuf, dot);
-      strncat(hostbuf, _res.defdname, HOSTLEN - strlen(hostbuf));
-      hostbuf[HOSTLEN] = 0;
-    }
+#if 0
+    add_local_domain(hostbuf, HOSTLEN);
+#endif
+
+    switch(type) {
+    case T_A:
+      /*
+       * check for invalid rd_length or too many addresses
+       */
+      if (rd_length != sizeof(struct in_addr))
+        return answer_count;
+      if (++addr_count < RES_MAXADDRS) {
+        if (answer_count == 1)
+          hp->h_addrtype = (query_class == C_IN) ?  AF_INET : AF_UNSPEC;
+
+        memcpy(address, current, sizeof(struct in_addr));
+        *addr++ = address;
+        *addr = 0;
+        address += sizeof(struct in_addr);
+
+        if (!hp->h_name) {
+          strcpy(name, hostbuf);
+          hp->h_name = name;
+          name += strlen(name) + 1;
+        }
+        Debug((DEBUG_DNS, "Resolver: A %s for %s", 
+               ircd_ntoa((char*) hp->h_addr_list[addr_count - 1]), hostbuf));
+      }
+      current += rd_length;
+      ++answer_count;
+      break;
+    case T_PTR:
+      n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
+      if (n < 0) {
+        /*
+         * broken message
+         */
+        return 0;
+      }
+      else if (n == 0) {
+        /*
+         * no more answers left
+         */
+        return answer_count;
+      }
+      /*
+       * This comment is based on analysis by Shadowfax, Wohali and johan, 
+       * not me.  (Dianora) I am only commenting it.
+       *
+       * dn_expand is guaranteed to not return more than sizeof(hostbuf)
+       * but do all implementations of dn_expand also guarantee
+       * buffer is terminated with null byte? Lets not take chances.
+       *  -Dianora
+       */
+      hostbuf[HOSTLEN] = '\0';
+      current += (size_t) n;
 
-    switch (type)
-    {
-      case T_A:
-       /* check for invalid dlen or too many addresses */
-       if (dlen != sizeof(struct in_addr) || ++addr_count >= RES_MAXADDRS)
-         break;
-       if (ans == 1)
-         hp->h_addrtype = (addr_class == C_IN) ? AF_INET : AF_UNSPEC;
-
-       memcpy(a, cp, sizeof(struct in_addr));
-       *addr++ = a;
-       *addr = 0;
-       a += sizeof(struct in_addr);
-
-       if (!hp->h_name)
-       {
-         strncpy(p, hostbuf, endp - p);
-         hp->h_name = p;
-         p += (strlen(p) + 1);
-       }
-       cp += dlen;
-       Debug((DEBUG_DNS, "got ip # %s for %s",
-           inetntoa(*((struct in_addr *)hp->h_addr_list[addr_count - 1])),
-           hostbuf));
-       ans++;
-       break;
-      case T_PTR:
-       if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) < 0)
-       {
-         cp = NULL;
-         break;
-       }
-       cp += n;
-       Debug((DEBUG_DNS, "got host %s", hostbuf));
-       /*
-        * Copy the returned hostname into the host name or alias field if
-        * there is a known hostname already.
-        */
-       if (hp->h_name)
-       {
-         if (++alias_count >= RES_MAXALIASES)
-           break;
-         strncpy(p, hostbuf, endp - p);
-         endp[-1] = 0;
-         *alias++ = p;
-         *alias = NULL;
-       }
-       else
-       {
-         strncpy(p, hostbuf, endp - p);
-         hp->h_name = p;
-       }
-       p += (strlen(p) + 1);
-       ans++;
-       break;
-      case T_CNAME:
-       cp += dlen;
-       Debug((DEBUG_DNS, "got cname %s", hostbuf));
-       if (++alias_count >= RES_MAXALIASES)
-         break;
-       strncpy(p, hostbuf, endp - p);
-       endp[-1] = 0;
-       *alias++ = p;
-       *alias = NULL;
-       p += (strlen(p) + 1);
-       ans++;
-       break;
-      default:
-       Debug((DEBUG_DNS, "proc_answer: type:%d for:%s", type, hostbuf));
-       break;
+      Debug((DEBUG_DNS, "Resolver: PTR %s", hostbuf));
+      /*
+       * copy the returned hostname into the host name
+       * ignore duplicate ptr records
+       */
+      if (!hp->h_name) {
+        strcpy(name, hostbuf);
+        hp->h_name = name;
+        name += strlen(name) + 1;
+      }
+      ++answer_count;
+      break;
+    case T_CNAME:
+      Debug((DEBUG_DNS, "Resolver: CNAME %s", hostbuf));
+      if (++alias_count < RES_MAXALIASES) {
+        ircd_strncpy(name, hostbuf, endp - name);
+        *alias++ = name;
+        *alias   = 0;
+        name += strlen(name) + 1;
+      }
+      current += rd_length;
+      ++answer_count;
+      break;
+    default :
+      Debug((DEBUG_DNS,"Resolver: proc_answer type: %d for: %s", type, hostbuf));
+      break;
     }
   }
-  return ans;
+  return answer_count;
 }
 
 /*
- * Read a dns reply from the nameserver and process it.
+ * resolver_read - read a dns reply from the nameserver and process it.
+ * return 0 if nothing was read from the socket, otherwise return 1
  */
-struct hostent *get_res(char *lp)
+int resolver_read(void)
 {
-  static unsigned char buf[sizeof(HEADER) + MAXPACKET];
-  Reg1 HEADER *hptr;
-  Reg2 ResRQ *rptr = NULL;
-  aCache *cp = NULL;
+  u_char             buf[sizeof(HEADER) + MAXPACKET];
+  HEADER*            header       = 0;
+  struct ResRequest* request      = 0;
+  struct CacheEntry* cp           = 0;
+  unsigned int       rc           = 0;
+  int                answer_count = 0;
   struct sockaddr_in sin;
-  int a, max;
-  size_t rc, len = sizeof(sin);
-
-  alarm(4);
-  rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len);
-  alarm(0);
 
-  if (rc <= sizeof(HEADER))
-    return NULL;
+  Debug((DEBUG_DNS, "Resolver: read"));
+  if (IO_SUCCESS != os_recvfrom_nonb(ResolverFileDescriptor,
+                                     buf, sizeof(buf), &rc, &sin)) {
+    return 0;
+  }
+  if (rc < sizeof(HEADER)) {
+    Debug((DEBUG_DNS, "Resolver: short reply %d: %s", rc, strerror(errno)));
+    return 0;
+  }
   /*
-   * Convert DNS reply reader from Network byte order to CPU byte order.
+   * convert DNS reply reader from Network byte order to CPU byte order.
    */
-  hptr = (HEADER *) buf;
-  hptr->id = ntohs(hptr->id);
-  hptr->ancount = ntohs(hptr->ancount);
-  hptr->qdcount = ntohs(hptr->qdcount);
-  hptr->nscount = ntohs(hptr->nscount);
-  hptr->arcount = ntohs(hptr->arcount);
-#ifdef DEBUG
-  Debug((DEBUG_NOTICE, "get_res:id = %d rcode = %d ancount = %d",
-      hptr->id, hptr->rcode, hptr->ancount));
-#endif
-  reinfo.re_replies++;
+  header = (HEADER*) buf;
+  /* header->id = ntohs(header->id); */
+  header->ancount = ntohs(header->ancount);
+  header->qdcount = ntohs(header->qdcount);
+  header->nscount = ntohs(header->nscount);
+  header->arcount = ntohs(header->arcount);
+  ++reinfo.re_replies;
   /*
-   * Response for an id which we have already received an answer for
+   * response for an id which we have already received an answer for
    * just ignore this response.
    */
-  if ((rptr = find_id(hptr->id)) == NULL)
-  {
-    Debug((DEBUG_DNS, "find_id %d failed", hptr->id));
-    return NULL;
+  if (0 == (request = find_id(header->id))) {
+    Debug((DEBUG_DNS, "Resolver: can't find request id: %d", header->id));
+    return 1;
   }
   /*
-   * Check against possibly fake replies
+   * check against possibly fake replies
    */
-  max = MIN(_res.nscount, rptr->sends);
-  if (!max)
-    max = 1;
-
-  for (a = 0; a < max; a++)
-  {
-    if (!_res.nsaddr_list[a].sin_addr.s_addr ||
-       !memcmp((char *)&sin.sin_addr, (char *)&_res.nsaddr_list[a].sin_addr,
-       sizeof(struct in_addr)))
-      break;
-  }
-  if (a == max)
-  {
-    reinfo.re_unkrep++;
-    Debug((DEBUG_DNS, "got response from unknown ns"));
-    goto getres_err;
+  if (!res_ourserver(&_res, &sin)) {
+    Debug((DEBUG_DNS, "Resolver: fake reply from: %s",
+           (const char*) &sin.sin_addr));
+    ++reinfo.re_unkrep;
+    return 1;
   }
 
-  if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
-  {
-    switch (hptr->rcode)
-    {
-      case NXDOMAIN:
-       h_errno = TRY_AGAIN;
-       break;
-      case SERVFAIL:
-       h_errno = TRY_AGAIN;
-       break;
-      case NOERROR:
-       h_errno = NO_DATA;
-       break;
-      case FORMERR:
-      case NOTIMP:
-      case REFUSED:
-      default:
-       h_errno = NO_RECOVERY;
-       break;
-    }
-    reinfo.re_errors++;
-    /*
-     * If a bad error was returned, we stop here and dont send
-     * send any more (no retries granted).
-     */
-    if (h_errno != TRY_AGAIN)
-    {
-      Debug((DEBUG_DNS, "Fatal DNS error %d for %d", h_errno, hptr->rcode));
-      rptr->resend = 0;
-      rptr->retries = 0;
-    }
-    goto getres_err;
+  if ((header->rcode != NOERROR) || (header->ancount == 0)) {
+    ++reinfo.re_errors;
+    if (SERVFAIL == header->rcode)
+      resend_query(request);
+    else {
+      /*
+       * If a bad error was returned, we stop here and dont send
+       * send any more (no retries granted).
+       * Isomer: Perhaps we should return these error messages back to
+       *         the client?
+       */
+#ifdef DEBUGMODE
+      switch (header->rcode) {
+        case NOERROR:
+          Debug((DEBUG_DNS, "Fatal DNS error: No Error"));
+          break;
+        case FORMERR:
+          Debug((DEBUG_DNS, "Fatal DNS error: Format Error"));
+          break;
+        case SERVFAIL:
+          Debug((DEBUG_DNS, "Fatal DNS error: Server Failure"));
+          break;
+        case NXDOMAIN:
+          Debug((DEBUG_DNS, "DNS error: Non Existant Domain"));
+          break;
+        case NOTIMP:
+          Debug((DEBUG_DNS, "Fatal DNS error: Not Implemented"));
+          break;
+        case REFUSED:
+          Debug((DEBUG_DNS, "Fatal DNS error: Query Refused"));
+          break;
+        default:
+          Debug((DEBUG_DNS, "Unassigned fatal DNS error: %i", header->rcode));
+          break;
+      }
+#endif /* DEBUGMODE */
+      (*request->query.callback)(request->query.vptr, 0);
+      rem_request(request);
+    } 
+    return 1;
   }
-  /* 
-   * If this fails we didn't get a buffer to hold the hostent or
-   * there was an error decoding the received packet, try it again
-   * and hope it works the next time.
+  /*
+   * If this fails there was an error decoding the received packet, 
+   * try it again and hope it works the next time.
    */
-  a = proc_answer(rptr, hptr, buf, &buf[rc]);
-  Debug((DEBUG_DNS, "get_res:Proc answer = %d", a));
-
-  if (a && rptr->type == T_PTR)
-  {
-    struct hostent *hp2 = NULL;
-
-    if (BadPtr(rptr->he.h.h_name))     /* Kludge!      960907/Vesa */
-      goto getres_err;
-
-    Debug((DEBUG_DNS, "relookup %s <-> %s", rptr->he.h.h_name,
-       inetntoa(rptr->addr)));
-    /*
-     * Lookup the 'authoritive' name that we were given for the
-     * ip#.  By using this call rather than regenerating the
-     * type we automatically gain the use of the cache with no
-     * extra kludges.
-     */
-    if ((hp2 = gethost_byname((char *)rptr->he.h.h_name, &rptr->cinfo)))
-    {
-      if (lp)
-       memcpy(lp, &rptr->cinfo, sizeof(Link));
+  answer_count = proc_answer(request, header, buf, buf + rc);
+  if (answer_count) {
+    if (T_PTR == request->type) {
+      struct DNSReply* reply = NULL;
+      if (0 == request->he.h.h_name) {
+        /*
+         * got a PTR response with no name, something bogus is happening
+         * don't bother trying again, the client address doesn't resolve 
+         */
+        (*request->query.callback)(request->query.vptr, reply);
+        rem_request(request); 
+        return 1;
+      }
+      Debug((DEBUG_DNS, "relookup %s <-> %s",
+             request->he.h.h_name, ircd_ntoa((char*) &request->addr)));
+      /*
+       * Lookup the 'authoritive' name that we were given for the
+       * ip#.  By using this call rather than regenerating the
+       * type we automatically gain the use of the cache with no
+       * extra kludges.
+       */
+      reply = gethost_byname(request->he.h.h_name, &request->query);
+      if (0 == reply) {
+        /*
+         * If name wasn't found, a request has been queued and it will
+         * be the last one queued.  This is rather nasty way to keep
+         * a host alias with the query. -avalon
+         */
+        MyFree(requestListTail->he.buf);
+        requestListTail->he.buf = request->he.buf;
+        request->he.buf = 0;
+        memcpy(&requestListTail->he.h, &request->he.h, sizeof(struct hostent));
+      }
+      else
+        (*request->query.callback)(request->query.vptr, reply);
+      rem_request(request);
+    }
+    else {
+      /*
+       * got a name and address response, client resolved
+       * XXX - Bug found here by Dianora -
+       * make_cache() occasionally returns a NULL pointer when a
+       * PTR returned a CNAME, cp was not checked before so the
+       * callback was being called with a value of 0x2C != NULL.
+       */
+      cp = make_cache(request);
+      (*request->query.callback)(request->query.vptr,
+                                 (cp) ? &cp->reply : 0);
+      rem_request(request);
     }
+  }
+  else if (!request->sent) {
     /*
-     * If name wasn't found, a request has been queued and it will
-     * be the last one queued.  This is rather nasty way to keep
-     * a host alias with the query. -avalon
+     * XXX - we got a response for a query we didn't send with a valid id?
+     * this should never happen, bail here and leave the client unresolved
      */
-    else if (*rptr->he.h.h_aliases)
-    {
-      if (last->he.buf)
-       RunFree(last->he.buf);
-      last->he.buf = rptr->he.buf;
-      rptr->he.buf = NULL;
-      memcpy(&last->he.h, &rptr->he.h, sizeof(struct hostent));
-    }
-    rem_request(rptr);
-    return hp2;
+    (*request->query.callback)(request->query.vptr, 0);
+    rem_request(request);
   }
+  return 1;
+}
 
-  if (a > 0)
-  {
-    if (lp)
-      memcpy(lp, &rptr->cinfo, sizeof(Link));
-    cp = make_cache(rptr);
-    Debug((DEBUG_DNS, "get_res:cp=%p rptr=%p (made)", cp, rptr));
-    rem_request(rptr);
+/*
+ * resolver_read_multiple - process up to count reads
+ */
+void resolver_read_multiple(int count)
+{
+  int i = 0;
+  for ( ; i < count; ++i) {
+    if (0 == resolver_read())
+      return;
   }
-  else if (!rptr->sent)
-    rem_request(rptr);
-  return cp ? &cp->he.h : NULL;
+}
+
+static size_t calc_hostent_buffer_size(const struct hostent* hp)
+{
+  char** p;
+  size_t count = 0;
+  assert(0 != hp);
 
-getres_err:
   /*
-   * Reprocess an error if the nameserver didnt tell us to "TRY_AGAIN".
+   * space for name
    */
-  if (rptr)
-  {
-    if (h_errno != TRY_AGAIN)
-    {
-      /*
-       * If we havent tried with the default domain and its
-       * set, then give it a try next.
-       */
-      if (_res.options & RES_DEFNAMES && ++rptr->srch == 0)
-      {
-       rptr->retries = _res.retry;
-       rptr->sends = 0;
-       rptr->resend = 1;
-       resend_query(rptr);
-      }
-      else
-       resend_query(rptr);
-    }
-    else if (lp)
-      memcpy(lp, &rptr->cinfo, sizeof(Link));
-  }
-  return NULL;
+  count += (strlen(hp->h_name) + 1);
+  /*
+   * space for aliases
+   */
+  for (p = hp->h_aliases; *p; ++p)
+    count += (strlen(*p) + 1 + sizeof(char*));
+  /*
+   * space for addresses
+   */
+  for (p = hp->h_addr_list; *p; ++p)
+    count += (hp->h_length + sizeof(char*));
+  /*
+   * space for 2 nulls to terminate h_aliases and h_addr_list 
+   */
+  count += (2 * sizeof(char*));
+  return count;
 }
 
+
 /*
- * Duplicate a hostent struct, allocate only enough memory for
+ * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
  * the data we're putting in it.
  */
-static int dup_hostent(aHostent *new_hp, struct hostent *hp)
+static void dup_hostent(aHostent* new_hp, struct hostent* hp)
 {
-  char *p;
-  char **ap;
-  char **pp;
-  int alias_count = 0;
-  int addr_count = 0;
+  char*  p;
+  char** ap;
+  char** pp;
+  int    alias_count = 0;
+  int    addr_count = 0;
   size_t bytes_needed = 0;
 
-  if (!new_hp || !hp)
-    return 0;
+  assert(0 != new_hp);
+  assert(0 != hp);
 
   /* how much buffer do we need? */
   bytes_needed += (strlen(hp->h_name) + 1);
 
   pp = hp->h_aliases;
-  while (*pp)
-  {
-    bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
+  while (*pp) {
+    bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
     ++alias_count;
   }
   pp = hp->h_addr_list;
-  while (*pp++)
-  {
-    bytes_needed += (hp->h_length + sizeof(void *));
+  while (*pp++) {
+    bytes_needed += (hp->h_length + sizeof(char*));
     ++addr_count;
   }
   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
-  bytes_needed += (2 * sizeof(void *));
+  bytes_needed += (2 * sizeof(char*));
 
   /* Allocate memory */
-  if ((new_hp->buf = (char *)RunMalloc(bytes_needed)) == NULL)
-    return -1;
+  new_hp->buf = (char*) MyMalloc(bytes_needed);
 
   new_hp->h.h_addrtype = hp->h_addrtype;
   new_hp->h.h_length = hp->h_length;
@@ -1061,8 +1209,8 @@ static int dup_hostent(aHostent *new_hp, struct hostent *hp)
   /* first write the address list */
   pp = hp->h_addr_list;
   ap = new_hp->h.h_addr_list =
-      (char **)(new_hp->buf + ((alias_count + 1) * sizeof(void *)));
-  p = (char *)ap + ((addr_count + 1) * sizeof(void *));
+      (char**)(new_hp->buf + ((alias_count + 1) * sizeof(char*)));
+  p = (char*)ap + ((addr_count + 1) * sizeof(char*));
   while (*pp)
   {
     *ap++ = p;
@@ -1077,88 +1225,76 @@ static int dup_hostent(aHostent *new_hp, struct hostent *hp)
 
   /* last write the alias list */
   pp = hp->h_aliases;
-  ap = new_hp->h.h_aliases = (char **)new_hp->buf;
-  while (*pp)
-  {
+  ap = new_hp->h.h_aliases = (char**) new_hp->buf;
+  while (*pp) {
     *ap++ = p;
     strcpy(p, *pp++);
     p += (strlen(p) + 1);
   }
   *ap = 0;
-
-  return 0;
 }
 
 /*
- * Add records to a Hostent struct in place.
+ * update_hostent - Add records to a Hostent struct in place.
  */
-static int update_hostent(aHostent *hp, char **addr, char **alias)
+static void update_hostent(aHostent* hp, char** addr, char** alias)
 {
-  char *p;
-  char **ap;
-  char **pp;
-  int alias_count = 0;
-  int addr_count = 0;
-  char *buf = NULL;
+  char*  p;
+  char** ap;
+  char** pp;
+  int    alias_count = 0;
+  int    addr_count = 0;
+  char*  buf = NULL;
   size_t bytes_needed = 0;
 
   if (!hp || !hp->buf)
-    return -1;
+    return;
 
   /* how much buffer do we need? */
   bytes_needed = strlen(hp->h.h_name) + 1;
   pp = hp->h.h_aliases;
-  while (*pp)
-  {
-    bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
+  while (*pp) {
+    bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
     ++alias_count;
   }
-  if (alias)
-  {
+  if (alias) {
     pp = alias;
-    while (*pp)
-    {
-      bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
+    while (*pp) {
+      bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
       ++alias_count;
     }
   }
   pp = hp->h.h_addr_list;
-  while (*pp++)
-  {
-    bytes_needed += (hp->h.h_length + sizeof(void *));
+  while (*pp++) {
+    bytes_needed += (hp->h.h_length + sizeof(char*));
     ++addr_count;
   }
-  if (addr)
-  {
+  if (addr) {
     pp = addr;
-    while (*pp++)
-    {
-      bytes_needed += (hp->h.h_length + sizeof(void *));
+    while (*pp++) {
+      bytes_needed += (hp->h.h_length + sizeof(char*));
       ++addr_count;
     }
   }
   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
-  bytes_needed += 2 * sizeof(void *);
+  bytes_needed += 2 * sizeof(char*);
 
   /* Allocate memory */
-  if ((buf = (char *)RunMalloc(bytes_needed)) == NULL)
-    return -1;
+  buf = (char*) MyMalloc(bytes_needed);
+  assert(0 != buf);
 
   /* first write the address list */
   pp = hp->h.h_addr_list;
   ap = hp->h.h_addr_list =
-      (char **)(buf + ((alias_count + 1) * sizeof(void *)));
-  p = (char *)ap + ((addr_count + 1) * sizeof(void *));
-  while (*pp)
-  {
+      (char**)(buf + ((alias_count + 1) * sizeof(char*)));
+  p = (char*)ap + ((addr_count + 1) * sizeof(char*));
+  while (*pp) {
     memcpy(p, *pp++, hp->h.h_length);
     *ap++ = p;
     p += hp->h.h_length;
   }
-  if (addr)
-  {
-    while (*addr)
-    {
+  if (addr) {
+    while (*addr) {
       memcpy(p, *addr++, hp->h.h_length);
       *ap++ = p;
       p += hp->h.h_length;
@@ -1173,17 +1309,14 @@ static int update_hostent(aHostent *hp, char **addr, char **alias)
 
   /* last write the alias list */
   pp = hp->h.h_aliases;
-  ap = hp->h.h_aliases = (char **)buf;
-  while (*pp)
-  {
+  ap = hp->h.h_aliases = (char**) buf;
+  while (*pp) {
     strcpy(p, *pp++);
     *ap++ = p;
     p += (strlen(p) + 1);
   }
-  if (alias)
-  {
-    while (*alias)
-    {
+  if (alias) {
+    while (*alias) {
       strcpy(p, *alias++);
       *ap++ = p;
       p += (strlen(p) + 1);
@@ -1193,151 +1326,146 @@ static int update_hostent(aHostent *hp, char **addr, char **alias)
   /* release the old buffer */
   p = hp->buf;
   hp->buf = buf;
-  RunFree(p);
-  return 0;
+  MyFree(p);
 }
 
-static int hash_number(unsigned char *ip)
+/*
+ * hash_number - IP address hash function
+ */
+static int hash_number(const unsigned char* ip)
 {
-  unsigned int hashv = 0;
-
   /* could use loop but slower */
-  hashv += (int)*ip++;
-  hashv += hashv + (int)*ip++;
-  hashv += hashv + (int)*ip++;
-  hashv += hashv + (int)*ip++;
+  unsigned int hashv;
+  const u_char* p = (const u_char*) ip;
+
+  assert(0 != p);
+
+  hashv = *p++;
+  hashv += hashv + *p++;
+  hashv += hashv + *p++;
+  hashv += hashv + *p;
   hashv %= ARES_CACSIZE;
-  return (hashv);
+  return hashv;
 }
 
-static int hash_name(const char *name)
+/*
+ * hash_name - hostname hash function
+ */
+static int hash_name(const char* name)
 {
   unsigned int hashv = 0;
+  const u_char* p = (const u_char*) name;
 
-  for (; *name && *name != '.'; name++)
-    hashv += *name;
+  assert(0 != p);
+
+  for (; *p && *p != '.'; ++p)
+    hashv += *p;
   hashv %= ARES_CACSIZE;
-  return (hashv);
+  return hashv;
 }
 
 /*
- * Add a new cache item to the queue and hash table.
+ * add_to_cache - Add a new cache item to the queue and hash table.
  */
-static aCache *add_to_cache(aCache *ocp)
+static struct CacheEntry* add_to_cache(struct CacheEntry* ocp)
 {
-  aCache *cp = NULL;
-  int hashv;
+  int  hashv;
 
-  Debug((DEBUG_DNS,
-      "add_to_cache:ocp %p he %p name %p addrl %p 0 %p",
-      ocp, &ocp->he, ocp->he.h.h_name, ocp->he.h.h_addr_list,
-      ocp->he.h.h_addr_list[0]));
+  assert(0 != ocp);
 
-  ocp->list_next = cachetop;
-  cachetop = ocp;
+  ocp->list_next = cacheTop;
+  cacheTop = ocp;
 
   hashv = hash_name(ocp->he.h.h_name);
+
   ocp->hname_next = hashtable[hashv].name_list;
   hashtable[hashv].name_list = ocp;
 
-  hashv = hash_number((unsigned char *)ocp->he.h.h_addr_list[0]);
+  hashv = hash_number(ocp->he.h.h_addr);
+
   ocp->hnum_next = hashtable[hashv].num_list;
   hashtable[hashv].num_list = ocp;
 
-  Debug((DEBUG_DNS, "add_to_cache:added %s[%p] cache %p.",
-      ocp->he.h.h_name, ocp->he.h.h_addr_list[0], ocp));
-  Debug((DEBUG_DNS,
-      "add_to_cache:h1 %d h2 %#x lnext %p namnext %p numnext %p",
-      hash_name(ocp->he.h.h_name), hashv, ocp->list_next,
-      ocp->hname_next, ocp->hnum_next));
-
   /*
    * LRU deletion of excessive cache entries.
    */
-  if (++incache > MAXCACHED)
-  {
-    for (cp = cachetop; cp->list_next; cp = cp->list_next);
-    rem_cache(cp);
+  if (++cachedCount > MAXCACHED) {
+    struct CacheEntry* cp;
+    struct CacheEntry* cp_next;
+    for (cp = ocp->list_next; cp; cp = cp_next) {
+      cp_next = cp->list_next;
+      rem_cache(cp);
+    }
   }
-  cainfo.ca_adds++;
-
+  ++cainfo.ca_adds;
   return ocp;
 }
 
 /*
- * update_list
- *
- * Does not alter the cache structure passed. It is assumed that
+ * update_list - does not alter the cache structure passed. It is assumed that
  * it already contains the correct expire time, if it is a new entry. Old
  * entries have the expirey time updated.
- */
-static void update_list(ResRQ *rptr, aCache *cp)
+*/
+static void update_list(struct ResRequest* request, struct CacheEntry* cachep)
 {
-  aCache **cpp;
-  char *s;
-  char **ap;
-  const char *t;
-  int i, j;
-  static char *addrs[RES_MAXADDRS + 1];
-  static char *aliases[RES_MAXALIASES + 1];
+#if 0
+  struct CacheEntry** cpp;
+#endif
+  struct CacheEntry*  cp = cachep;
+  char*    s;
+  char*    t;
+  int      i;
+  int      j;
+  char**   ap;
+  char*    addrs[RES_MAXADDRS + 1];
+  char*    aliases[RES_MAXALIASES + 1];
 
   /*
-   * Search for the new cache item in the cache list by hostname.
+   * search for the new cache item in the cache list by hostname.
    * If found, move the entry to the top of the list and return.
    */
-  cainfo.ca_updates++;
-
-  for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next))
-  {
+  ++cainfo.ca_updates;
+#if 0
+  for (cpp = &cacheTop; *cpp; cpp = &((*cpp)->list_next)) {
     if (cp == *cpp)
       break;
   }
   if (!*cpp)
     return;
   *cpp = cp->list_next;
-  cp->list_next = cachetop;
-  cachetop = cp;
-  if (!rptr)
-    return;
+  cp->list_next = cacheTop;
+  cacheTop = cp;
+#endif
 
-  Debug((DEBUG_DNS, "u_l:cp %p na %p al %p ad %p",
-      cp, cp->he.h.h_name, cp->he.h.h_aliases, cp->he.h.h_addr_list[0]));
-  Debug((DEBUG_DNS, "u_l:rptr %p h_n %p", rptr, rptr->he.h.h_name));
+  if (!request)
+    return;
   /*
    * Compare the cache entry against the new record.  Add any
    * previously missing names for this entry.
    */
-
   *aliases = 0;
   ap = aliases;
-  for (i = 0, s = (char *)rptr->he.h.h_name; s; s = rptr->he.h.h_aliases[i++])
-  {
-    for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++])
-    {
-      if (!strCasediff(t, s))
-       break;
+  for (i = 0, s = request->he.h.h_name; s; s = request->he.h.h_aliases[i++]) {
+    for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++]) {
+      if (0 == ircd_strcmp(t, s))
+        break;
     }
-    if (!t)
-    {
+    if (!t) {
       *ap++ = s;
       *ap = 0;
     }
   }
-
   /*
    * Do the same again for IP#'s.
    */
   *addrs = 0;
   ap = addrs;
-  for (i = 0; (s = rptr->he.h.h_addr_list[i]); i++)
-  {
-    for (j = 0; (t = cp->he.h.h_addr_list[j]); j++)
-    {
+  for (i = 0; (s = request->he.h.h_addr_list[i]); i++) {
+    for (j = 0; (t = cp->he.h.h_addr_list[j]); j++) {
       if (!memcmp(t, s, sizeof(struct in_addr)))
-       break;
+        break;
     }
-    if (!t)
-    {
+    if (!t) {
       *ap++ = s;
       *ap = 0;
     }
@@ -1346,48 +1474,41 @@ static void update_list(ResRQ *rptr, aCache *cp)
     update_hostent(&cp->he, addrs, aliases);
 }
 
-static aCache *find_cache_name(char *name)
+/*
+ * find_cache_name - find name in nameserver cache
+ */
+static struct CacheEntry* find_cache_name(const char* name)
 {
-  aCache *cp;
-  const char *s;
-  int hashv;
-  int i;
+  struct CacheEntry* cp;
+  char*   s;
+  int     hashv;
+  int     i;
 
+  assert(0 != name);
   hashv = hash_name(name);
 
   cp = hashtable[hashv].name_list;
-  Debug((DEBUG_DNS, "find_cache_name:find %s : hashv = %d", name, hashv));
 
-  for (; cp; cp = cp->hname_next)
-  {
-    for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++])
-    {
-      if (strCasediff(s, name) == 0)
-      {
-       cainfo.ca_na_hits++;
-       update_list(0, cp);
-       return cp;
+  for (; cp; cp = cp->hname_next) {
+    for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++]) {
+      if (0 == ircd_strcmp(s, name)) {
+        ++cainfo.ca_na_hits;
+        return cp;
       }
     }
   }
 
-  for (cp = cachetop; cp; cp = cp->list_next)
-  {
+  for (cp = cacheTop; cp; cp = cp->list_next) {
     /*
-     * If no aliases or the hash value matches, we've already
+     * if no aliases or the hash value matches, we've already
      * done this entry and all possiblilities concerning it.
      */
-    if (!*cp->he.h.h_aliases)
-      continue;
-    if (hashv == hash_name(cp->he.h.h_name))
+    if (!cp->he.h.h_name || hashv == hash_name(cp->he.h.h_name))
       continue;
-    for (i = 0; (s = cp->he.h.h_aliases[i]); ++i)
-    {
-      if (!strCasediff(name, s))
-      {
-       cainfo.ca_na_hits++;
-       update_list(0, cp);
-       return cp;
+    for (i = 0, s = cp->he.h.h_aliases[i]; s; s = cp->he.h.h_aliases[++i]) {
+      if (0 == ircd_strcmp(name, s)) {
+        ++cainfo.ca_na_hits;
+        return cp;
       }
     }
   }
@@ -1395,284 +1516,243 @@ static aCache *find_cache_name(char *name)
 }
 
 /*
- * Find a cache entry by ip# and update its expire time
+ * find_cache_number - find a cache entry by ip# and update its expire time
  */
-static aCache *find_cache_number(ResRQ *rptr, struct in_addr *numb)
+static struct CacheEntry* find_cache_number(struct ResRequest* request,
+                                            const char* addr)
 {
-  Reg1 aCache *cp;
-  Reg2 int hashv, i;
-
-  hashv = hash_number((unsigned char *)numb);
+  struct CacheEntry* cp;
+  int     hashv;
+  int     i;
 
+  assert(0 != addr);
+  hashv = hash_number(addr);
   cp = hashtable[hashv].num_list;
-  Debug((DEBUG_DNS, "find_cache_number:find %s[%08x]: hashv = %d",
-      inetntoa(*numb), ntohl(numb->s_addr), hashv));
 
-  for (; cp; cp = cp->hnum_next)
-  {
-    for (i = 0; cp->he.h.h_addr_list[i]; ++i)
-    {
-      if (!memcmp(cp->he.h.h_addr_list[i], (char *)numb,
-         sizeof(struct in_addr)))
-      {
-       cainfo.ca_nu_hits++;
-       update_list(rptr, cp);
-       return cp;
+  for (; cp; cp = cp->hnum_next) {
+    for (i = 0; cp->he.h.h_addr_list[i]; ++i) {
+      if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
+        ++cainfo.ca_nu_hits;
+        return cp;
       }
     }
   }
-
-  for (cp = cachetop; cp; cp = cp->list_next)
-  {
+  for (cp = cacheTop; cp; cp = cp->list_next) {
     /*
-     * Single address entry...would have been done by hashed search above...
-     */
-    if (!cp->he.h.h_addr_list[1])
-      continue;
-    /*
-     * If the first IP# has the same hashnumber as the IP# we
+     * single address entry...would have been done by hashed
+     * search above...
+     * if the first IP# has the same hashnumber as the IP# we
      * are looking for, its been done already.
      */
-    if (hashv == hash_number((unsigned char *)cp->he.h.h_addr_list[0]))
+    if (!cp->he.h.h_addr_list[1] || 
+        hashv == hash_number(cp->he.h.h_addr_list[0]))
       continue;
-    for (i = 1; cp->he.h.h_addr_list[i]; ++i)
-    {
-      if (!memcmp(cp->he.h.h_addr_list[i], (char *)numb,
-         sizeof(struct in_addr)))
-      {
-       cainfo.ca_nu_hits++;
-       update_list(rptr, cp);
-       return cp;
+    for (i = 1; cp->he.h.h_addr_list[i]; ++i) {
+      if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
+        ++cainfo.ca_nu_hits;
+        return cp;
       }
     }
   }
   return NULL;
 }
 
-static aCache *make_cache(ResRQ *rptr)
+static struct CacheEntry* make_cache(struct ResRequest* request)
 {
-  aCache *cp;
-  int i;
-  struct hostent *hp = &rptr->he.h;
+  struct CacheEntry* cp;
+  int     i;
+  struct hostent* hp;
+  assert(0 != request);
 
+  hp = &request->he.h;
   /*
-   * Shouldn't happen but it just might...
+   * shouldn't happen but it just might...
    */
+  assert(0 != hp->h_name);
+  assert(0 != hp->h_addr_list[0]);
   if (!hp->h_name || !hp->h_addr_list[0])
     return NULL;
   /*
    * Make cache entry.  First check to see if the cache already exists
    * and if so, return a pointer to it.
    */
-  for (i = 0; hp->h_addr_list[i]; ++i)
-  {
-    if ((cp = find_cache_number(rptr, (struct in_addr *)hp->h_addr_list[i])))
+  for (i = 0; hp->h_addr_list[i]; ++i) {
+    if ((cp = find_cache_number(request, hp->h_addr_list[i]))) {
+      update_list(request, cp);
       return cp;
+    }
   }
-
   /*
-   * A matching entry wasnt found in the cache so go and make one up.
-   */
-  if ((cp = (aCache *)RunMalloc(sizeof(aCache))) == NULL)
-    return NULL;
-  memset(cp, 0, sizeof(aCache));
-  dup_hostent(&cp->he, hp);
+   * a matching entry wasnt found in the cache so go and make one up.
+   */ 
+  cp = (struct CacheEntry*) MyMalloc(sizeof(struct CacheEntry));
+  assert(0 != cp);
 
-  if (rptr->ttl < 600)
-  {
-    reinfo.re_shortttl++;
-    cp->ttl = 600;
+  memset(cp, 0, sizeof(struct CacheEntry));
+  dup_hostent(&cp->he, hp);
+  cp->reply.hp = &cp->he.h;
+  /*
+   * hmmm... we could time out the cache after 10 minutes regardless
+   * would that be reasonable since we don't save the reply?
+   */ 
+  if (request->ttl < AR_TTL) {
+    ++reinfo.re_shortttl;
+    cp->ttl = AR_TTL;
   }
   else
-    cp->ttl = rptr->ttl;
-  cp->expireat = now + cp->ttl;
-  Debug((DEBUG_INFO, "make_cache:made cache %p", cp));
+    cp->ttl = request->ttl;
+  cp->expireat = CurrentTime + cp->ttl;
   return add_to_cache(cp);
 }
 
 /*
- * rem_cache
- *
- * Delete a cache entry from the cache structures and lists and return
- * all memory used for the cache back to the memory pool.
+ * rem_cache - delete a cache entry from the cache structures 
+ * and lists and return all memory used for the cache back to the memory pool.
  */
-static void rem_cache(aCache *ocp)
+static void rem_cache(struct CacheEntry* ocp)
 {
-  aCache **cp;
-  struct hostent *hp = &ocp->he.h;
-  int hashv;
-  aClient *cptr;
+  struct CacheEntry** cp;
+  int                 hashv;
+  struct hostent*     hp;
+  assert(0 != ocp);
 
-  Debug((DEBUG_DNS, "rem_cache: ocp %p hp %p l_n %p aliases %p",
-      ocp, hp, ocp->list_next, hp->h_aliases));
 
-  /*
-   * Cleanup any references to this structure by destroying the pointer.
-   */
-  for (hashv = highest_fd; hashv >= 0; --hashv)
-  {
-    if ((cptr = loc_clients[hashv]) && (cptr->hostp == hp))
-      cptr->hostp = NULL;
+  if (0 < ocp->reply.ref_count) {
+    if (ocp->expireat < CurrentTime) {
+      ocp->expireat = CurrentTime + AR_TTL;
+      Debug((DEBUG_DNS, "Resolver: referenced cache entry not removed for: %s",
+            ocp->he.h.h_name));
+    }
+    return;
   }
   /*
-   * Remove cache entry from linked list.
+   * remove cache entry from linked list
    */
-  for (cp = &cachetop; *cp; cp = &((*cp)->list_next))
-  {
-    if (*cp == ocp)
-    {
+  for (cp = &cacheTop; *cp; cp = &((*cp)->list_next)) {
+    if (*cp == ocp) {
       *cp = ocp->list_next;
       break;
     }
   }
+  hp = &ocp->he.h;
   /*
-   * Remove cache entry from hashed name lists.
+   * remove cache entry from hashed name list
    */
+  assert(0 != hp->h_name);
   hashv = hash_name(hp->h_name);
 
-  Debug((DEBUG_DNS, "rem_cache: h_name %s hashv %d next %p first %p",
-      hp->h_name, hashv, ocp->hname_next, hashtable[hashv].name_list));
-
-  for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next))
-  {
-    if (*cp == ocp)
-    {
+  for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next)) {
+    if (*cp == ocp) {
       *cp = ocp->hname_next;
       break;
     }
   }
   /*
-   * Remove cache entry from hashed number list
+   * remove cache entry from hashed number list
    */
-  hashv = hash_number((unsigned char *)hp->h_addr_list[0]);
+  hashv = hash_number(hp->h_addr);
+  assert(-1 < hashv);
 
-  Debug((DEBUG_DNS, "rem_cache: h_addr %s hashv %d next %p first %p",
-      inetntoa(*((struct in_addr *)hp->h_addr_list[0])), hashv,
-      ocp->hnum_next, hashtable[hashv].num_list));
-  for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next))
-  {
-    if (*cp == ocp)
-    {
+  for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next)) {
+    if (*cp == ocp) {
       *cp = ocp->hnum_next;
       break;
     }
   }
-
-  if (ocp->he.buf)
-    RunFree(ocp->he.buf);
-  RunFree((char *)ocp);
-
-  incache--;
-  cainfo.ca_dels++;
+  /*
+   * free memory used to hold the various host names and the array
+   * of alias pointers.
+   */
+  MyFree(ocp->he.buf);
+  MyFree(ocp);
+  --cachedCount;
+  ++cainfo.ca_dels;
 }
 
-/*
- * Removes entries from the cache which are older than their expirey times.
- * returns the time at which the server should next poll the cache.
- */
-time_t expire_cache(void)
+void flush_resolver_cache(void)
 {
-  Reg1 aCache *cp, *cp2;
-  Reg2 time_t next = 0;
-
-  for (cp = cachetop; cp; cp = cp2)
-  {
-    cp2 = cp->list_next;
-
-    if (now >= cp->expireat)
-    {
-      cainfo.ca_expires++;
-      rem_cache(cp);
-    }
-    else if (!next || next > cp->expireat)
-      next = cp->expireat;
-  }
-  return (next > now) ? next : (now + AR_TTL);
+  /*
+   * stubbed - iterate cache and remove everything that isn't referenced
+   */
 }
 
 /*
- * Remove all dns cache entries.
+ * m_dns - dns status query
  */
-void flush_cache(void)
+int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
 {
-  Reg1 aCache *cp;
-
-  while ((cp = cachetop))
-    rem_cache(cp);
-}
-
-int m_dns(aClient *cptr, aClient *sptr, int UNUSED(parc), char *parv[])
-{
-  aCache *cp;
-  int i;
-  struct hostent *h;
-
-  if (parv[1] && *parv[1] == 'l')
-  {
-    if (!IsAnOper(cptr))
-    {
-      return 0;
-    }
-    for (cp = cachetop; cp; cp = cp->list_next)
-    {
-      h = &cp->he.h;
+#if !defined(NDEBUG)
+  struct CacheEntry* cp;
+  int     i;
+  struct hostent* hp;
+
+  if (parv[1] && *parv[1] == 'l') {
+    for(cp = cacheTop; cp; cp = cp->list_next) {
+      hp = &cp->he.h;
       sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
-         parv[0], (int)(cp->expireat - now), (int)cp->ttl,
-         h->h_name, inetntoa(*((struct in_addr *)h->h_addr_list[0])));
-      for (i = 0; h->h_aliases[i]; i++)
-       sendto_one(sptr, "NOTICE %s : %s = %s (CN)",
-           parv[0], h->h_name, h->h_aliases[i]);
-      for (i = 1; h->h_addr_list[i]; i++)
-       sendto_one(sptr, "NOTICE %s : %s = %s (IP)", parv[0],
-           h->h_name, inetntoa(*((struct in_addr *)h->h_addr_list[i])));
+                 parv[0], cp->expireat - CurrentTime, cp->ttl,
+                 hp->h_name, ircd_ntoa(hp->h_addr));
+      for (i = 0; hp->h_aliases[i]; i++)
+        sendto_one(sptr,"NOTICE %s : %s = %s (CN)",
+                   parv[0], hp->h_name, hp->h_aliases[i]);
+      for (i = 1; hp->h_addr_list[i]; i++)
+        sendto_one(sptr,"NOTICE %s : %s = %s (IP)",
+                   parv[0], hp->h_name, ircd_ntoa(hp->h_addr_list[i]));
     }
     return 0;
   }
-  sendto_one(sptr, "NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
-      sptr->name, cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
-      cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits,
-      cainfo.ca_updates);
-  sendto_one(sptr, "NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
-      sptr->name, reinfo.re_errors, reinfo.re_nu_look,
-      reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
-  sendto_one(sptr, "NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
-      reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
-      reinfo.re_resends, reinfo.re_timeouts);
+  if (parv[1] && *parv[1] == 'd') {
+    sendto_one(sptr, "NOTICE %s :ResolverFileDescriptor = %d", 
+               parv[0], ResolverFileDescriptor);
+    return 0;
+  }
+  sendto_one(sptr,"NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
+             sptr->name,
+             cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
+             cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits, 
+             cainfo.ca_updates);
+  
+  sendto_one(sptr,"NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
+             sptr->name, reinfo.re_errors, reinfo.re_nu_look,
+             reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
+  sendto_one(sptr,"NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
+             reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
+             reinfo.re_resends, reinfo.re_timeouts);
+#endif
   return 0;
 }
 
-size_t cres_mem(aClient *sptr)
+unsigned long cres_mem(struct Client* sptr)
 {
-  aCache *c = cachetop;
-  struct hostent *h;
-  int i;
-  size_t nm = 0, im = 0, sm = 0, ts = 0;
-
-  for (; c; c = c->list_next)
-  {
-    sm += sizeof(*c);
-    h = &c->he.h;
-    for (i = 0; h->h_addr_list[i]; i++)
-    {
-      im += sizeof(char *);
-      im += sizeof(struct in_addr);
-    }
-    im += sizeof(char *);
-    for (i = 0; h->h_aliases[i]; i++)
-    {
-      nm += sizeof(char *);
-      nm += strlen(h->h_aliases[i]);
-    }
-    nm += i - 1;
-    nm += sizeof(char *);
-    if (h->h_name)
-      nm += strlen(h->h_name);
+  struct CacheEntry* entry;
+  struct ResRequest* request;
+  size_t cache_mem     = 0;
+  int    cache_count   = 0;
+  size_t request_mem   = 0;
+  int    request_count = 0;
+
+  for (entry = cacheTop; entry; entry = entry->list_next) {
+    cache_mem += sizeof(struct CacheEntry);
+    cache_mem += calc_hostent_buffer_size(&entry->he.h); 
+    ++cache_count;
   }
-  ts = ARES_CACSIZE * sizeof(CacheTable);
-  sendto_one(sptr, ":%s %d %s :RES table " SIZE_T_FMT,
-      me.name, RPL_STATSDEBUG, sptr->name, ts);
-  sendto_one(sptr, ":%s %d %s :Structs " SIZE_T_FMT
-      " IP storage " SIZE_T_FMT " Name storage " SIZE_T_FMT,
-      me.name, RPL_STATSDEBUG, sptr->name, sm, im, nm);
-  return ts + sm + im + nm;
+  for (request = requestListHead; request; request = request->next) {
+    request_mem += sizeof(struct ResRequest);
+    if (request->name)
+      request_mem += strlen(request->name) + 1; 
+    if (request->he.buf)
+      request_mem += MAXGETHOSTLEN + 1;
+    ++request_count;
+  }
+  if (cachedCount != cache_count) {
+    sendto_one(sptr, 
+               ":%s %d %s :Resolver: cache count mismatch: %d != %d",
+               me.name, RPL_STATSDEBUG, sptr->name, cachedCount, cache_count);
+    assert(cachedCount == cache_count);
+  }
+  sendto_one(sptr, ":%s %d %s :Resolver: cache %d(%d) requests %d(%d)",
+             me.name, RPL_STATSDEBUG, sptr->name, cache_count, cache_mem,
+             request_count, request_mem);
+  return cache_mem + request_mem;
 }
+
index 7baf8bcc517f4d553a7839c5fabd2a5d4a7a641f..5c4d76d34db2a9d44bf4479cef3ed613fc31c04c 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
+#include "runmalloc.h"
+#include "client.h"
+#include "ircd.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "s_debug.h"
+#include "send.h"
+#include "struct.h"
 #include "sys.h"
 
-#ifdef DEBUGMALLOC
+#include <assert.h>
 #include <stdlib.h>
-#include "h.h"
+#include <string.h>
 
-RCSTAG_CC("$Id$");
+#if defined(DEBUGMALLOC)
 
 #define MALLOC_HASHTABLE_SIZE 16384
 #define MallocHash(x) \
@@ -49,13 +58,13 @@ typedef struct {
 #endif
 } location_st;
 
-#define LOCSIZE 1024           /* Maximum of 256 different locations */
+#define LOCSIZE 1024            /* Maximum of 256 different locations */
 static location_st location[LOCSIZE];
-static unsigned int locations; /* Counter */
+static unsigned int locations;  /* Counter */
 
 static unsigned int find_location(const char *filename, int line)
 {
-  register unsigned int hash;
+  unsigned int hash;
   hash = line & 0xff;
   while (location[hash].filename && (location[hash].line != line ||
       location[hash].filename != filename))
@@ -70,32 +79,27 @@ static unsigned int find_location(const char *filename, int line)
   }
   return hash;
 }
-#endif
+#endif /* MEMLEAKSTATS */
 
 #ifdef MEMMAGICNUMS
 /* The size of this struct should be a multiple of 4 bytes, just in case... */
 typedef struct {
-#ifdef MEMMAGICNUMS
   unsigned int prefix_magicnumber;
-#endif
 } prefix_blk_st;
 
-#define SIZEOF_PREFIX sizeof(prefix_blk_st)
-#else
-typedef void prefix_blk_st;
-#define SIZEOF_PREFIX 0
-#endif
-
-#ifdef MEMMAGICNUMS
 typedef struct {
   unsigned int postfix_magicnumber;
 } postfix_blk_st;
 
 #define SIZEOF_POSTFIX sizeof(postfix_blk_st)
+#define SIZEOF_PREFIX sizeof(prefix_blk_st)
 #define HAS_POSTFIX
-#else
+
+#else /* !MEMMAGICNUMS */
+typedef void prefix_blk_st;
+#define SIZEOF_PREFIX 0
 #define SIZEOF_POSTFIX 0
-#endif
+#endif /* MEMMAGICNUMS */
 
 typedef struct hash_entry_st {
   struct hash_entry_st *next;
@@ -107,8 +111,8 @@ typedef struct hash_entry_st {
   unsigned int location;
 #ifdef MEMTIMESTATS
   time_t when;
-#endif
-#endif
+#endif /* MEMTIMESTATS */
+#endif /* MEMLEAKSTATS */
 } hash_entry_st;
 
 #define memblkp(prefix_ptr) \
@@ -120,26 +124,18 @@ typedef struct hash_entry_st {
 
 static hash_entry_st *hashtable[MALLOC_HASHTABLE_SIZE];
 #ifdef MEMSIZESTATS
-static size_t mem_size = 0;    /* Number of allocated bytes  */
-static unsigned int alloc_cnt = 0;     /* Number of allocated blocks */
+static size_t mem_size = 0;     /* Number of allocated bytes  */
+static unsigned int alloc_cnt = 0;      /* Number of allocated blocks */
 #endif
 
 #ifdef MEMLEAKSTATS
-#include "struct.h"
-#include "send.h"
-#include "numeric.h"
-#include "s_err.h"
-#include "ircd.h"
-#include "s_serv.h"
-#include "numnicks.h"
-
-void report_memleak_stats(aClient *sptr, int parc, char *parv[])
+void report_memleak_stats(struct Client *sptr, int parc, char *parv[])
 {
   unsigned int hash;
   location_st *loc = location;
 
 #ifdef MEMTIMESTATS
-  time_t till = now;
+  time_t till = CurrentTime;
   time_t from = me.since;
   if (parc > 3)
   {
@@ -151,50 +147,50 @@ void report_memleak_stats(aClient *sptr, int parc, char *parv[])
     if (parc > 4)
       from += atoi(parv[4]);
     for (start = &hashtable[0];
-       start < &hashtable[MALLOC_HASHTABLE_SIZE]; ++start)
+        start < &hashtable[MALLOC_HASHTABLE_SIZE]; ++start)
     {
       hash_entry_st *hash_entry;
       for (hash_entry = *start; hash_entry; hash_entry = hash_entry->next)
-       if (hash_entry->when >= from && hash_entry->when <= till)
-       {
+        if (hash_entry->when >= from && hash_entry->when <= till)
+        {
 #ifdef MEMSIZESTATS
-         tmp_loc[hash_entry->location].size += hash_entry->size;
+          tmp_loc[hash_entry->location].size += hash_entry->size;
 #endif
-         tmp_loc[hash_entry->location].number_of_allocations++;
-       }
+          tmp_loc[hash_entry->location].number_of_allocations++;
+        }
     }
     loc = tmp_loc;
     if (MyUser(sptr) || Protocol(sptr->from) < 10)
       sendto_one(sptr, ":%s NOTICE %s :Memory allocated between " TIME_T_FMT
-         " (server start + %s s) and " TIME_T_FMT " (now - %s s):",
-         me.name, parv[0], from, parc > 4 ? parv[4] : "0", till,
-         parc > 3 ? parv[3] : "0");
+          " (server start + %s s) and " TIME_T_FMT " (CurrentTime - %s s):",
+          me.name, parv[0], from, parc > 4 ? parv[4] : "0", till,
+          parc > 3 ? parv[3] : "0");
     else
       sendto_one(sptr, "%s NOTICE %s%s :Memory allocated between " TIME_T_FMT
-         " (server start + %s s) and " TIME_T_FMT " (now - %s s):",
-         NumServ(&me), NumNick(sptr), from, parc > 4 ? parv[4] : "0", till,
-         parc > 3 ? parv[3] : "0");
+          " (server start + %s s) and " TIME_T_FMT " (CurrentTime - %s s):",
+          NumServ(&me), NumNick(sptr), from, parc > 4 ? parv[4] : "0", till,
+          parc > 3 ? parv[3] : "0");
   }
-#endif
+#endif /* MEMTIMESTATS */
   for (hash = 0; hash < LOCSIZE; ++hash)
     if (loc[hash].number_of_allocations > 0)
       sendto_one(sptr, rpl_str(RPL_STATMEM), me.name, parv[0],
-         loc[hash].number_of_allocations,
-         location[hash].line, location[hash].filename
+          loc[hash].number_of_allocations,
+          location[hash].line, location[hash].filename
 #ifdef MEMSIZESTATS
-         , loc[hash].size
+          , loc[hash].size
 #endif
-         );
+          );
 }
 
 void *RunMalloc_memleak(size_t size, int line, const char *filename)
-#else
-void *RunMalloc(size_t size)
-#endif
+#else   /* !MEMLEAKSTATS */
+void *MyMalloc(size_t size)
+#endif  /* MEMLEAKSTATS */
 {
-  register prefix_blk_st *ptr;
-  register hash_entry_st *hash_entry;
-  register hash_entry_st **hashtablep;
+  prefix_blk_st *ptr;
+  hash_entry_st *hash_entry;
+  hash_entry_st **hashtablep;
 
 #ifdef HAS_POSTFIX
   size += 3;
@@ -207,8 +203,8 @@ void *RunMalloc(size_t size)
   {
     if (ptr)
       free(ptr);
-    Debug((DEBUG_FATAL, "Out of memory !"));
-    return NULL;
+    (*noMemHandler)();
+    return 0;
   }
 
   hashtablep = &hashtable[MallocHash(ptr)];
@@ -217,11 +213,11 @@ void *RunMalloc(size_t size)
   hash_entry->ptr = ptr;
 #ifdef MEMLEAKSTATS
 #ifdef MEMTIMESTATS
-  hash_entry->when = now;
+  hash_entry->when = CurrentTime;
 #endif
   location[(hash_entry->location =
       find_location(filename, line))].number_of_allocations++;
-#endif
+#endif /* MEMLEAKSTATS */
 #ifdef MEMSIZESTATS
   hash_entry->size = size;
 #ifdef MEMLEAKSTATS
@@ -229,13 +225,13 @@ void *RunMalloc(size_t size)
 #endif
   mem_size += size;
   ++alloc_cnt;
-#endif
+#endif /* MEMSIZESTATS */
 #ifdef MEMMAGICNUMS
   ptr->prefix_magicnumber = MAGIC_PREFIX;
   postfixp(memblkp(ptr), size)->postfix_magicnumber = MAGIC_POSTFIX;
 #endif
 
-  Debug((DEBUG_DEBUG, "RunMalloc(%u) = %p", size, memblkp(ptr)));
+  Debug((DEBUG_MALLOC, "MyMalloc(%u) = %p", size, memblkp(ptr)));
 
   return memblkp(ptr);
 }
@@ -244,37 +240,38 @@ void *RunMalloc(size_t size)
 void *RunCalloc_memleak(size_t nmemb, size_t size,
     int line, const char *filename)
 #else
-void *RunCalloc(size_t nmemb, size_t size)
-#endif
+void *MyCalloc(size_t nmemb, size_t size)
+#endif /* MEMLEAKSTATS */
 {
   void *ptr;
   size *= nmemb;
 #ifdef MEMLEAKSTATS
   if ((ptr = RunMalloc_memleak(size, line, filename)))
 #else
-  if ((ptr = RunMalloc(size)))
-#endif
+  if ((ptr = MyMalloc(size)))
+#endif /* MEMLEAKSTATS */
     memset(ptr, 0, size);
   return ptr;
 }
 
-int RunFree_test(void *memblk_ptr)
+int MyFree_test(void *memblk_ptr)
 {
-  register prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
-  register hash_entry_st *hash_entry;
+  prefix_blk_st* prefix_ptr = prefixp(memblk_ptr);
+  hash_entry_st* hash_entry;
   for (hash_entry = hashtable[MallocHash(prefix_ptr)];
       hash_entry && hash_entry->ptr != prefix_ptr;
       hash_entry = hash_entry->next);
   return hash_entry ? 1 : 0;
 }
 
-void RunFree(void *memblk_ptr)
+void MyFree(void* memblk_ptr)
 {
-  register prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
-  register hash_entry_st *hash_entry, *prev_hash_entry = NULL;
+  prefix_blk_st* prefix_ptr = prefixp(memblk_ptr);
+  hash_entry_st* hash_entry;
+  hash_entry_st* prev_hash_entry = NULL;
   unsigned int hash = MallocHash(prefix_ptr);
 
-  Debug((DEBUG_DEBUG, "RunFree(%p)", memblk_ptr));
+  Debug((DEBUG_MALLOC, "MyFree(%p)", memblk_ptr));
 
   if (!memblk_ptr)
     return;
@@ -285,23 +282,24 @@ void RunFree(void *memblk_ptr)
   if (!hash_entry)
   {
     Debug((DEBUG_FATAL, "FREEING NON MALLOC PTR !!!"));
-    MyCoreDump;
+    assert(0 != hash_entry);
   }
 #ifdef MEMMAGICNUMS
   if (prefix_ptr->prefix_magicnumber != MAGIC_PREFIX)
   {
     Debug((DEBUG_FATAL, "MAGIC_PREFIX CORRUPT !"));
-    MyCoreDump;
+    assert(MAGIC_PREFIX == prefix_ptr->prefix_magicnumber);
   }
   prefix_ptr->prefix_magicnumber = 12345678;
   if (postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber
       != MAGIC_POSTFIX)
   {
     Debug((DEBUG_FATAL, "MAGIC_POSTFIX CORRUPT !"));
-    MyCoreDump;
+    assert(MAGIC_POSTFIX == 
+           postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber);
   }
   postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber = 87654321;
-#endif
+#endif /* MEMMAGICNUMS */
 
   if (prev_hash_entry)
     prev_hash_entry->next = hash_entry->next;
@@ -320,18 +318,9 @@ void RunFree(void *memblk_ptr)
 #endif
 #ifdef DEBUGMODE
   /* Put 0xfefefefe.. in freed memory */
-#ifndef memset
   memset(prefix_ptr, 0xfe, hash_entry->size + SIZEOF_PREFIX);
-#else
-  {
-    register char *p = prefix_ptr;
-    size_t len = hash_entry->size + SIZEOF_PREFIX;
-    for (; len; --len)
-      *p++ = 0xfe;
-  }
-#endif
-#endif
-#endif
+#endif /* DEBUGMODE */
+#endif /* MEMSIZESTATS */
 
   free(hash_entry);
   free(prefix_ptr);
@@ -341,24 +330,24 @@ void RunFree(void *memblk_ptr)
 void *RunRealloc_memleak(void *memblk_ptr, size_t size,
     int line, const char *filename)
 #else
-void *RunRealloc(void *memblk_ptr, size_t size)
-#endif
+void *MyRealloc(void *memblk_ptr, size_t size)
+#endif /* MEMLEAKSTATS */
 {
-  register prefix_blk_st *ptr;
-  register prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
-  register hash_entry_st *hash_entry, *prev_hash_entry = NULL;
-  register hash_entry_st **hashtablep;
+  prefix_blk_st *ptr;
+  prefix_blk_st *prefix_ptr = prefixp(memblk_ptr);
+  hash_entry_st *hash_entry, *prev_hash_entry = NULL;
+  hash_entry_st **hashtablep;
   unsigned int hash;
 
   if (!memblk_ptr)
 #ifdef MEMLEAKSTATS
     return RunMalloc_memleak(size, line, filename);
 #else
-    return RunMalloc(size);
-#endif
+    return MyMalloc(size);
+#endif /* MEMLEAKSTATS */
   if (!size)
   {
-    RunFree(memblk_ptr);
+    MyFree(memblk_ptr);
     return NULL;
   }
 
@@ -368,22 +357,23 @@ void *RunRealloc(void *memblk_ptr, size_t size)
   if (!hash_entry)
   {
     Debug((DEBUG_FATAL, "REALLOCATING NON MALLOC PTR !!!"));
-    MyCoreDump;
+    assert(0 != hash_entry);
   }
 
 #ifdef MEMMAGICNUMS
   if (prefix_ptr->prefix_magicnumber != MAGIC_PREFIX)
   {
     Debug((DEBUG_FATAL, "MAGIC_PREFIX CORRUPT !"));
-    MyCoreDump;
+    assert(MAGIC_PREFIX == prefix_ptr->prefix_magicnumber);
   }
   if (postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber
       != MAGIC_POSTFIX)
   {
     Debug((DEBUG_FATAL, "MAGIC_POSTFIX CORRUPT !"));
-    MyCoreDump;
+    assert(MAGIC_POSTFIX ==
+           postfixp(memblk_ptr, hash_entry->size)->postfix_magicnumber);
   }
-#endif
+#endif /* MEMMAGICNUMS */
 
 #ifdef HAS_POSTFIX
   size += 3;
@@ -397,15 +387,15 @@ void *RunRealloc(void *memblk_ptr, size_t size)
   location[hash_entry->location].number_of_allocations--;
 #ifdef MEMSIZESTATS
   location[hash_entry->location].size -= hash_entry->size;
-#endif
-#endif
+#endif /* MEMSIZESTATS */
+#endif /* MEMLEAKSTATS */
 
   if (!(ptr =
       (prefix_blk_st *) realloc(prefix_ptr,
       SIZEOF_PREFIX + size + SIZEOF_POSTFIX)))
   {
-    Debug((DEBUG_FATAL, "RunRealloc: Out of memory :"));
-    return NULL;
+    (*noMemHandler)();
+    return 0;
   }
 
   if (prev_hash_entry)
@@ -419,23 +409,23 @@ void *RunRealloc(void *memblk_ptr, size_t size)
   hash_entry->ptr = ptr;
 #ifdef MEMLEAKSTATS
 #ifdef MEMTIMESTATS
-  hash_entry->when = now;
+  hash_entry->when = CurrentTime;
 #endif
   location[(hash_entry->location =
       find_location(filename, line))].number_of_allocations++;
-#endif
+#endif /* MEMLEAKSTATS */
 #ifdef MEMSIZESTATS
   mem_size += size - hash_entry->size;
   hash_entry->size = size;
 #ifdef MEMLEAKSTATS
   location[hash_entry->location].size += size;
 #endif
-#endif
+#endif /* MEMSIZESTATS */
 #ifdef MEMMAGICNUMS
   postfixp(memblkp(ptr), size)->postfix_magicnumber = MAGIC_POSTFIX;
 #endif
 
-  Debug((DEBUG_DEBUG, ": RunRealloc(%p, %u) = %p",
+  Debug((DEBUG_MALLOC, ": MyRealloc(%p, %u) = %p",
       memblk_ptr, size, memblkp(ptr)));
 
   return memblkp(ptr);
@@ -451,6 +441,6 @@ size_t get_mem_size(void)
 {
   return mem_size;
 }
-#endif
+#endif /* MEMSIZESTATS */
 
-#endif /* DEBUGMALLOC */
+#endif /* !defined(DEBUGMALLOC) */
index 44f45eaa9779724240f39bddd6e7235e7e335d1d..acb2663caf94ec10142a6c9a49086dc4d7c25b79 100644 (file)
-/*
- * IRC - Internet Relay Chat, ircd/s_auth.c
- * Copyright (C) 1992 Darren Reed
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/s_auth.c
+ *   Copyright (C) 1992 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or (at your option)
- * any later version.
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ *   $Id$
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Changes:
+ *   July 6, 1999 - Rewrote most of the code here. When a client connects
+ *     to the server and passes initial socket validation checks, it
+ *     is owned by this module (auth) which returns it to the rest of the
+ *     server when dns and auth queries are finished. Until the client is
+ *     released, the server does not know it exists and does not process
+ *     any messages from it.
+ *     --Bleep  Thomas Helvey <tomh@inxpress.net>
  */
-
-#include "sys.h"
-#include <sys/socket.h>
-#if HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-#if HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef UNIXPORT
-#include <sys/un.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HPUX
-#include <arpa/inet.h>
-#endif /* HPUX */
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include "h.h"
+#include "s_auth.h"
+#include "client.h"
+#include "IPcheck.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "numeric.h"
+#include "querycmds.h"
 #include "res.h"
-#include "struct.h"
-#include "common.h"
-#include "send.h"
 #include "s_bsd.h"
+#include "s_debug.h"
 #include "s_misc.h"
-#include "support.h"
-#include "ircd.h"
-#include "s_auth.h"
+#include "send.h"
 #include "sprintf_irc.h"
+#include "struct.h"
+#include "sys.h"               /* TRUE bleah */
 
-RCSTAG_CC("$Id$");
+#include <netdb.h>             /* struct hostent */
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
 
 /*
- * start_auth
- *
- * Flag the client to show that an attempt to contact the ident server on
- * the client's host.  The connect and subsequently the socket are all put
- * into 'non-blocking' mode.  Should the connect or any later phase of the
- * identifing process fail, it is aborted and the user is given a username
- * of "unknown".
+ * a bit different approach
+ * this replaces the original sendheader macros
+ */
+static struct {
+  const char* message;
+  size_t      length;
+} HeaderMessages [] = {
+  /* 123456789012345678901234567890123456789012345678901234567890 */
+  { "NOTICE AUTH :*** Looking up your hostname\r\n",       43 },
+  { "NOTICE AUTH :*** Found your hostname\r\n",            38 },
+  { "NOTICE AUTH :*** Found your hostname, cached\r\n",    46 },
+  { "NOTICE AUTH :*** Couldn't look up your hostname\r\n", 49 },
+  { "NOTICE AUTH :*** Checking Ident\r\n",                 33 },
+  { "NOTICE AUTH :*** Got ident response\r\n",             37 },
+  { "NOTICE AUTH :*** No ident response\r\n",              36 },
+  { "NOTICE AUTH :*** Your forward and reverse DNS do not match, " \
+    "ignoring hostname.\r\n",                              80 }
+};
+
+typedef enum {
+  REPORT_DO_DNS,
+  REPORT_FIN_DNS,
+  REPORT_FIN_DNSC,
+  REPORT_FAIL_DNS,
+  REPORT_DO_ID,
+  REPORT_FIN_ID,
+  REPORT_FAIL_ID,
+  REPORT_IP_MISMATCH
+} ReportType;
+
+#define sendheader(c, r) \
+   send((c)->fd, HeaderMessages[(r)].message, HeaderMessages[(r)].length, 0)
+
+struct AuthRequest* AuthPollList = 0; /* GLOBAL - auth queries pending io */
+static struct AuthRequest* AuthIncompleteList = 0;
+
+/*
+ * make_auth_request - allocate a new auth request
+ */
+static struct AuthRequest* make_auth_request(struct Client* client)
+{
+  struct AuthRequest* auth = 
+               (struct AuthRequest*) MyMalloc(sizeof(struct AuthRequest));
+  assert(0 != auth);
+  memset(auth, 0, sizeof(struct AuthRequest));
+  auth->fd      = -1;
+  auth->client  = client;
+  auth->timeout = CurrentTime + CONNECTTIMEOUT;
+  return auth;
+}
+
+/*
+ * free_auth_request - cleanup auth request allocations
+ */
+void free_auth_request(struct AuthRequest* auth)
+{
+  if (-1 < auth->fd)
+    close(auth->fd);
+  MyFree(auth);
+}
+
+/*
+ * unlink_auth_request - remove auth request from a list
+ */
+static void unlink_auth_request(struct AuthRequest* request,
+                                struct AuthRequest** list)
+{
+  if (request->next)
+    request->next->prev = request->prev;
+  if (request->prev)
+    request->prev->next = request->next;
+  else
+    *list = request->next;
+}
+
+/*
+ * link_auth_request - add auth request to a list
+ */
+static void link_auth_request(struct AuthRequest* request,
+                              struct AuthRequest** list)
+{
+  request->prev = 0;
+  request->next = *list;
+  if (*list)
+    (*list)->prev = request;
+  *list = request;
+}
+
+/*
+ * release_auth_client - release auth client from auth system
+ * this adds the client into the local client lists so it can be read by
+ * the main io processing loop
  */
-void start_auth(aClient *cptr)
+static void release_auth_client(struct Client* client)
+{
+  assert(0 != client);
+  client->lasttime = client->since = CurrentTime;
+  if (client->fd > HighestFd)
+    HighestFd = client->fd;
+  LocalClientArray[client->fd] = client;
+
+  add_client_to_list(client);
+  Debug((DEBUG_INFO, "Auth: release_auth_client %s@%s[%s]",
+         client->username, client->sockhost, client->sock_ip));
+}
+static void auth_kill_client(struct AuthRequest* auth)
 {
-  struct sockaddr_in sock;
-  int err;
-
-  Debug((DEBUG_NOTICE, "start_auth(%p) fd %d status %d",
-      cptr, cptr->fd, cptr->status));
-
-  alarm(2);
-  cptr->authfd = socket(AF_INET, SOCK_STREAM, 0);
-  err = errno;
-  alarm(0);
-
-  if (cptr->authfd < 0)
-  {
-#ifdef USE_SYSLOG
-    syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
-       get_client_name(cptr, FALSE));
+  assert(0 != auth);
+
+  unlink_auth_request(auth, (IsDoingAuth(auth)) ? &AuthPollList : &AuthIncompleteList);
+
+  if (IsDNSPending(auth))
+    delete_resolver_queries(auth);
+  IPcheck_disconnect(auth->client);
+  Count_unknowndisconnects(UserStats);
+  free_client(auth->client);
+  free_auth_request(auth);
+}
+
+/*
+ * auth_dns_callback - called when resolver query finishes
+ * if the query resulted in a successful search, hp will contain
+ * a non-null pointer, otherwise hp will be null.
+ * set the client on it's way to a connection completion, regardless
+ * of success of failure
+ */
+static void auth_dns_callback(void* vptr, struct DNSReply* reply)
+{
+  struct AuthRequest* auth = (struct AuthRequest*) vptr;
+
+  assert(0 != auth);
+  /*
+   * need to do this here so auth_kill_client doesn't
+   * try have the resolver delete the query it's about
+   * to delete anyways. --Bleep
+   */
+  ClearDNSPending(auth);
+
+  if (reply) {
+    const struct hostent* hp = reply->hp;
+    int i;
+    assert(0 != hp);
+    /*
+     * Verify that the host to ip mapping is correct both ways and that
+     * the ip#(s) for the socket is listed for the host.
+     */
+    for (i = 0; hp->h_addr_list[i]; ++i) {
+      if (0 == memcmp(hp->h_addr_list[i], &auth->client->ip,
+                      sizeof(struct in_addr)))
+         break;
+    }
+    if (!hp->h_addr_list[i]) {
+      if (IsUserPort(auth->client))
+        sendheader(auth->client, REPORT_IP_MISMATCH);
+      sendto_op_mask(SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%s]",
+                     auth->client->sock_ip, hp->h_name, 
+                     ircd_ntoa(hp->h_addr_list[0]));
+#if defined(KILL_IPMISMATCH)
+      auth_kill_client(auth);
+      return;
 #endif
-    Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
-       get_client_name(cptr, FALSE), strerror(get_sockerr(cptr))));
-    if (!DoingDNS(cptr))
-      SetAccess(cptr);
-    ircstp->is_abad++;
-    return;
+    }
+    else {
+      ++reply->ref_count;
+      auth->client->dns_reply = reply;
+      ircd_strncpy(auth->client->sockhost, hp->h_name, HOSTLEN);
+      if (IsUserPort(auth->client))
+        sendheader(auth->client, REPORT_FIN_DNS);
+    }
   }
-  if (cptr->authfd >= (MAXCONNECTIONS - 2))
-  {
-    close(cptr->authfd);
-    cptr->authfd = -1;
-    return;
+  else {
+    /*
+     * this should have already been done by s_bsd.c in add_connection
+     *
+     * strcpy(auth->client->sockhost, auth->client->sock_ip);
+     */
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_DNS);
+  }
+  if (!IsDoingAuth(auth)) {
+    release_auth_client(auth->client);
+    unlink_auth_request(auth, &AuthIncompleteList);
+    free_auth_request(auth);
   }
+}
 
-  set_non_blocking(cptr->authfd, cptr);
+/*
+ * authsenderr - handle auth send errors
+ */
+static void auth_error(struct AuthRequest* auth, int kill)
+{
+  ++ServerStats->is_abad;
 
-#ifdef VIRTUAL_HOST
-  if (bind(cptr->authfd, (struct sockaddr *)&vserv, sizeof(vserv)) == -1)
-  {
-    report_error("binding auth stream socket %s: %s", cptr);
-    close(cptr->authfd);
-    cptr->authfd = -1;
+  assert(0 != auth);
+  close(auth->fd);
+  auth->fd = -1;
+
+  if (IsUserPort(auth->client))
+    sendheader(auth->client, REPORT_FAIL_ID);
+
+  if (kill) {
+    /*
+     * we can't read the client info from the client socket,
+     * close the client connection and free the client
+     * Need to do this before we ClearAuth(auth) so we know
+     * which list to remove the query from. --Bleep
+     */
+    auth_kill_client(auth);
     return;
   }
+
+  ClearAuth(auth);
+  unlink_auth_request(auth, &AuthPollList);
+
+  if (IsDNSPending(auth))
+    link_auth_request(auth, &AuthIncompleteList);
+  else {
+    release_auth_client(auth->client);
+    free_auth_request(auth);
+  }
+}
+
+/*
+ * start_auth_query - Flag the client to show that an attempt to 
+ * contact the ident server on the client's host.  The connect and
+ * subsequently the socket are all put into 'non-blocking' mode.  
+ * Should the connect or any later phase of the identifing process fail,
+ * it is aborted and the user is given a username of "unknown".
+ */
+static int start_auth_query(struct AuthRequest* auth)
+{
+  struct sockaddr_in remote_addr;
+  struct sockaddr_in local_addr;
+  int                fd;
+
+  assert(0 != auth);
+  assert(0 != auth->client);
+
+  if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
+#if 0
+    report_error(SOCKET_ERROR_MSG, get_client_name(auth->client, HIDE_IP), errno);
+#endif
+    ++ServerStats->is_abad;
+    return 0;
+  }
+  if ((MAXCONNECTIONS - 10) < fd) {
+#if 0
+    report_error(CONNLIMIT_ERROR_MSG, 
+                 get_client_name(auth->client, HIDE_IP), errno);
+#endif
+    close(fd);
+    return 0;
+  }
+  if (!os_set_nonblocking(fd)) {
+#if 0
+    report_error(NONB_ERROR_MSG, get_client_name(auth->client, HIDE_IP), errno);
+#endif
+    close(fd);
+    return 0;
+  }
+  if (IsUserPort(auth->client))
+    sendheader(auth->client, REPORT_DO_ID);
+  /* 
+   * get the local address of the client and bind to that to
+   * make the auth request.  This used to be done only for
+   * ifdef VIRTTUAL_HOST, but needs to be done for all clients
+   * since the ident request must originate from that same address--
+   * and machines with multiple IP addresses are common now
+   */
+  memset(&local_addr, 0, sizeof(struct sockaddr_in));
+  os_get_sockname(auth->client->fd, &local_addr);
+  local_addr.sin_port = htons(0);
+
+  if (bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr_in))) {
+#if 0
+    report_error(BIND_ERROR_MSG,
+                 get_client_name(auth->client, HIDE_IP), errno);
 #endif
-  memcpy(&sock.sin_addr, &cptr->ip, sizeof(struct in_addr));
+    close(fd);
+    return 0;
+  }
 
-  sock.sin_port = htons(113);
-  sock.sin_family = AF_INET;
+  remote_addr.sin_addr.s_addr = auth->client->ip.s_addr;
+  remote_addr.sin_port = htons(113);
+  remote_addr.sin_family = AF_INET;
 
-  alarm((unsigned)4);
-  if (connect(cptr->authfd, (struct sockaddr *)&sock,
-      sizeof(sock)) == -1 && errno != EINPROGRESS)
-  {
-    ircstp->is_abad++;
+  if (!os_connect_nonb(fd, &remote_addr)) {
+    ServerStats->is_abad++;
     /*
      * No error report from this...
      */
-    alarm((unsigned)0);
-    close(cptr->authfd);
-    cptr->authfd = -1;
-    if (!DoingDNS(cptr))
-      SetAccess(cptr);
-    return;
+    close(fd);
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FAIL_ID);
+    return 0;
+  }
+
+  auth->fd = fd;
+
+  SetAuthConnect(auth);
+  return 1;
+}
+
+
+enum IdentReplyFields {
+  IDENT_PORT_NUMBERS,
+  IDENT_REPLY_TYPE,
+  IDENT_OS_TYPE,
+  IDENT_INFO,
+  USERID_TOKEN_COUNT
+};
+
+static char* check_ident_reply(char* reply)
+{
+  char* token;
+  char* end;
+  char* vector[USERID_TOKEN_COUNT];
+  int count = token_vector(reply, ':', vector, USERID_TOKEN_COUNT);
+
+  if (USERID_TOKEN_COUNT != count)
+    return 0;
+  /*
+   * second token is the reply type
+   */
+  token = vector[IDENT_REPLY_TYPE];
+  if (EmptyString(token))
+    return 0;
+
+  while (IsSpace(*token))
+    ++token;
+
+  if (0 != strncmp(token, "USERID", 6))
+    return 0;
+
+  /*
+   * third token is the os type
+   */
+  token = vector[IDENT_OS_TYPE];
+  if (EmptyString(token))
+    return 0;
+  while (IsSpace(*token))
+   ++token;
+
+  /*
+   * Unless "OTHER" is specified as the operating system
+   * type, the server is expected to return the "normal"
+   * user identification of the owner of this connection.
+   * "Normal" in this context may be taken to mean a string
+   * of characters which uniquely identifies the connection
+   * owner such as a user identifier assigned by the system
+   * administrator and used by such user as a mail
+   * identifier, or as the "user" part of a user/password
+   * pair used to gain access to system resources.  When an
+   * operating system is specified (e.g., anything but
+   * "OTHER"), the user identifier is expected to be in a
+   * more or less immediately useful form - e.g., something
+   * that could be used as an argument to "finger" or as a
+   * mail address.
+   */
+  if (0 == strncmp(token, "OTHER", 5))
+    return 0;
+  /*
+   * fourth token is the username
+   */
+  token = vector[IDENT_INFO];
+  if (EmptyString(token))
+    return 0;
+  while (IsSpace(*token))
+    ++token;
+  /*
+   * look for the end of the username, terminators are '\0, @, <SPACE>, :'
+   */
+  for (end = token; *end; ++end) {
+    if (IsSpace(*end) || '@' == *end || ':' == *end)
+      break;
   }
-  alarm((unsigned)0);
-  cptr->flags |= (FLAGS_WRAUTH | FLAGS_AUTH);
-  if (cptr->authfd > highest_fd)
-    highest_fd = cptr->authfd;
-  return;
+  *end = '\0'; 
+  return token;
 }
 
+#if 0
 /*
- * send_authports
- *
- * Send the ident server a query giving "theirport , ourport".
+ * GetValidIdent - parse ident query reply from identd server
+ * 
+ * Inputs        - pointer to ident buf
+ * Output        - NULL if no valid ident found, otherwise pointer to name
+ * Side effects        -
+ */
+static char* GetValidIdent(char *buf)
+{
+  int   remp = 0;
+  int   locp = 0;
+  char* colon1Ptr;
+  char* colon2Ptr;
+  char* colon3Ptr;
+  char* commaPtr;
+  char* remotePortString;
+
+  /* All this to get rid of a sscanf() fun. */
+  remotePortString = buf;
+  
+  colon1Ptr = strchr(remotePortString,':');
+  if(!colon1Ptr)
+    return 0;
+
+  *colon1Ptr = '\0';
+  colon1Ptr++;
+  colon2Ptr = strchr(colon1Ptr,':');
+  if(!colon2Ptr)
+    return 0;
+
+  *colon2Ptr = '\0';
+  colon2Ptr++;
+  commaPtr = strchr(remotePortString, ',');
+
+  if(!commaPtr)
+    return 0;
+
+  *commaPtr = '\0';
+  commaPtr++;
+
+  remp = atoi(remotePortString);
+  if(!remp)
+    return 0;
+              
+  locp = atoi(commaPtr);
+  if(!locp)
+    return 0;
+
+  /* look for USERID bordered by first pair of colons */
+  if(!strstr(colon1Ptr, "USERID"))
+    return 0;
+
+  colon3Ptr = strchr(colon2Ptr,':');
+  if(!colon3Ptr)
+    return 0;
+  
+  *colon3Ptr = '\0';
+  colon3Ptr++;
+  return(colon3Ptr);
+}
+#endif
+
+/*
+ * start_auth - starts auth (identd) and dns queries for a client
+ */
+void start_auth(struct Client* client)
+{
+  struct DNSQuery     query;
+  struct AuthRequest* auth = 0;
+
+  assert(0 != client);
+
+  auth = make_auth_request(client);
+  assert(0 != auth);
+
+  query.vptr     = auth;
+  query.callback = auth_dns_callback;
+
+  if (IsUserPort(auth->client))
+    sendheader(client, REPORT_DO_DNS);
+
+#if !defined(NODNS)
+  client->dns_reply = gethost_byaddr((const char*) &client->ip, &query);
+  if (client->dns_reply) {
+    ++client->dns_reply->ref_count;
+    ircd_strncpy(client->sockhost, client->dns_reply->hp->h_name, HOSTLEN);
+    if (IsUserPort(auth->client))
+      sendheader(client, REPORT_FIN_DNSC);
+  }
+  else
+    SetDNSPending(auth);
+#endif
+
+  if (start_auth_query(auth))
+    link_auth_request(auth, &AuthPollList);
+  else if (IsDNSPending(auth))
+    link_auth_request(auth, &AuthIncompleteList);
+  else {
+    free_auth_request(auth);
+    release_auth_client(client);
+  }
+}
+
+/*
+ * timeout_auth_queries - timeout resolver and identd requests
+ * allow clients through if requests failed
+ */
+void timeout_auth_queries(time_t now)
+{
+  struct AuthRequest* auth;
+  struct AuthRequest* auth_next = 0;
+
+  for (auth = AuthPollList; auth; auth = auth_next) {
+    auth_next = auth->next;
+    if (auth->timeout < CurrentTime) {
+      if (-1 < auth->fd) {
+        close(auth->fd);
+        auth->fd = -1;
+      }
+
+      if (IsUserPort(auth->client))
+        sendheader(auth->client, REPORT_FAIL_ID);
+      if (IsDNSPending(auth)) {
+        delete_resolver_queries(auth);
+        if (IsUserPort(auth->client))
+          sendheader(auth->client, REPORT_FAIL_DNS);
+      }
+      ircd_log(L_INFO, "DNS/AUTH timeout %s",
+               get_client_name(auth->client, HIDE_IP));
+
+      release_auth_client(auth->client);
+      unlink_auth_request(auth, &AuthPollList);
+      free_auth_request(auth);
+    }
+  }
+  for (auth = AuthIncompleteList; auth; auth = auth_next) {
+    auth_next = auth->next;
+    if (auth->timeout < CurrentTime) {
+      delete_resolver_queries(auth);
+      if (IsUserPort(auth->client))
+        sendheader(auth->client, REPORT_FAIL_DNS);
+      ircd_log(L_INFO, "DNS timeout %s", get_client_name(auth->client, HIDE_IP));
+
+      release_auth_client(auth->client);
+      unlink_auth_request(auth, &AuthIncompleteList);
+      free_auth_request(auth);
+    }
+  }
+}
+
+/*
+ * send_auth_query - send the ident server a query giving "theirport , ourport"
  * The write is only attempted *once* so it is deemed to be a fail if the
  * entire write doesn't write all the data given.  This shouldnt be a
  * problem since the socket should have a write buffer far greater than
  * this message to store it in should problems arise. -avalon
  */
-void send_authports(aClient *cptr)
+void send_auth_query(struct AuthRequest* auth)
 {
-  struct sockaddr_in us, them;
-  char authbuf[32];
-  size_t ulen, tlen;
-
-  Debug((DEBUG_NOTICE, "write_authports(%p) fd %d authfd %d stat %d",
-      cptr, cptr->fd, cptr->authfd, cptr->status));
-  tlen = ulen = sizeof(us);
-  if (getsockname(cptr->fd, (struct sockaddr *)&us, &ulen) ||
-      getpeername(cptr->fd, (struct sockaddr *)&them, &tlen))
-  {
-#ifdef USE_SYSLOG
-    syslog(LOG_ERR, "auth get{sock,peer}name error for %s:%m",
-       get_client_name(cptr, FALSE));
-#endif
-    goto authsenderr;
+  struct sockaddr_in us;
+  struct sockaddr_in them;
+  char               authbuf[32];
+  size_t             count;
+
+  assert(0 != auth);
+  assert(0 != auth->client);
+
+  if (!os_get_sockname(auth->client->fd, &us) ||
+      !os_get_peername(auth->client->fd, &them)) {
+    auth_error(auth, 1);
+    return;
   }
+  sprintf_irc(authbuf, "%u , %u\r\n",
+             (unsigned int) ntohs(them.sin_port),
+             (unsigned int) ntohs(us.sin_port));
 
-  sprintf_irc(authbuf, "%u , %u\r\n", (unsigned int)ntohs(them.sin_port),
-      (unsigned int)ntohs(us.sin_port));
-
-  Debug((DEBUG_SEND, "sending [%s] to auth port %s.113",
-      authbuf, inetntoa(them.sin_addr)));
-  if (write(cptr->authfd, authbuf, strlen(authbuf)) != (int)strlen(authbuf))
-  {
-  authsenderr:
-    ircstp->is_abad++;
-    close(cptr->authfd);
-    if (cptr->authfd == highest_fd)
-      while (!loc_clients[highest_fd])
-       highest_fd--;
-    cptr->authfd = -1;
-    cptr->flags &= ~FLAGS_AUTH;
-    if (!DoingDNS(cptr))
-      SetAccess(cptr);
+  if (IO_SUCCESS == os_send_nonb(auth->fd, authbuf, strlen(authbuf), &count)) {
+    ClearAuthConnect(auth);
+    SetAuthPending(auth);
   }
-  cptr->flags &= ~FLAGS_WRAUTH;
-  return;
+  else
+    auth_error(auth, 0);
 }
 
+
 /*
- * read_authports
- *
- * read the reply (if any) from the ident server we connected to.
- * The actual read processijng here is pretty weak - no handling of the reply
- * if it is fragmented by IP.
+ * read_auth_reply - read the reply (if any) from the ident server 
+ * we connected to.
+ * We only give it one shot, if the reply isn't good the first time
+ * fail the authentication entirely. --Bleep
  */
-void read_authports(aClient *cptr)
+void read_auth_reply(struct AuthRequest* auth)
 {
-  Reg1 char *s, *t;
-  Reg2 int len;
-  char ruser[USERLEN + 1], system[8];
-  unsigned short int remp = 0, locp = 0;
-
-  *system = *ruser = '\0';
-  Debug((DEBUG_NOTICE, "read_authports(%p) fd %d authfd %d stat %d",
-      cptr, cptr->fd, cptr->authfd, cptr->status));
+  char*  username = 0;
+  size_t len;
   /*
-   * Nasty.  Cant allow any other reads from client fd while we're
-   * waiting on the authfd to return a full valid string.  Use the
-   * client's input buffer to buffer the authd reply.
-   * Oh. this is needed because an authd reply may come back in more
-   * than 1 read! -avalon
+   * rfc1453 sez we MUST accept 512 bytes
    */
-  if ((len = read(cptr->authfd, cptr->buffer + cptr->count,
-      sizeof(cptr->buffer) - 1 - cptr->count)) >= 0)
-  {
-    cptr->count += len;
-    cptr->buffer[cptr->count] = '\0';
+  char   buf[BUFSIZE + 1];
+
+  assert(0 != auth);
+  assert(0 != auth->client);
+
+  if (IO_SUCCESS == os_recv_nonb(auth->fd, buf, BUFSIZE, &len)) {
+    buf[len] = '\0';
+    username = check_ident_reply(buf);
   }
 
-  cptr->lasttime = now;
-  if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) &&
-      (sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %10s",
-      &remp, &locp, ruser) == 3))
-  {
-    s = strrchr(cptr->buffer, ':');
-    *s++ = '\0';
-    for (t = (strrchr(cptr->buffer, ':') + 1); *t; t++)
-      if (!isSpace(*t))
-       break;
-    strncpy(system, t, sizeof(system) - 1);
-    system[sizeof(system) - 1] = 0;
-    for (t = ruser; *s && (t < ruser + sizeof(ruser)); s++)
-      if (!isSpace(*s) && *s != ':' && *s != '@')
-       *t++ = *s;
-    *t = '\0';
-    Debug((DEBUG_INFO, "auth reply ok [%s] [%s]", system, ruser));
+  close(auth->fd);
+  auth->fd = -1;
+  ClearAuth(auth);
+  
+  if (!EmptyString(username)) {
+    ircd_strncpy(auth->client->username, username, USERLEN);
+    /*
+     * Not needed, struct is zeroed by memset
+     * auth->client->username[USERLEN] = '\0';
+     */
+    SetGotId(auth->client);
+    ++ServerStats->is_asuc;
+    if (IsUserPort(auth->client))
+      sendheader(auth->client, REPORT_FIN_ID);
   }
-  else if (len != 0)
-  {
-    if (!strchr(cptr->buffer, '\n') && !strchr(cptr->buffer, '\r'))
-      return;
-    Debug((DEBUG_ERROR, "local %d remote %d", locp, remp));
-    Debug((DEBUG_ERROR, "bad auth reply in [%s]", cptr->buffer));
-    *ruser = '\0';
+  else {
+    ++ServerStats->is_abad;
+#if 0
+    strcpy(auth->client->username, "unknown");
+#endif
   }
-  close(cptr->authfd);
-  if (cptr->authfd == highest_fd)
-    while (!loc_clients[highest_fd])
-      highest_fd--;
-  cptr->count = 0;
-  cptr->authfd = -1;
-  ClearAuth(cptr);
-  if (!DoingDNS(cptr))
-    SetAccess(cptr);
-  if (len > 0)
-    Debug((DEBUG_INFO, "ident reply: [%s]", cptr->buffer));
-
-  if (!locp || !remp || !*ruser)
-  {
-    ircstp->is_abad++;
-    return;
+  unlink_auth_request(auth, &AuthPollList);
+
+  if (IsDNSPending(auth))
+    link_auth_request(auth, &AuthIncompleteList);
+  else {
+    release_auth_client(auth->client);
+    free_auth_request(auth);
   }
-  ircstp->is_asuc++;
-  strncpy(cptr->username, ruser, USERLEN);
-  cptr->username[USERLEN] = 0; /* This is the LA bug --Run */
-  if (strncmp(system, "OTHER", 5))
-    cptr->flags |= FLAGS_GOTID;
-  Debug((DEBUG_INFO, "got username [%s]", ruser));
-  return;
 }
+
+
index 9c4a64e09d9c5897a27043e819d51482ce81de5d..7860bc97f39b0610b4ca2ad39a4dac300c9b99b9 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdlib.h>
-#include <sys/socket.h>
-#if HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-#if HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef SOL2
-#include <sys/filio.h>
-#endif
-#ifdef UNIXPORT
-#include <sys/un.h>
-#endif
-#include <stdio.h>
-#ifdef USE_POLL
-#ifndef HAVE_POLL_H
-#undef USE_POLL
-#else /* HAVE_POLL_H */
-#ifdef HAVE_STROPTS_H
-#include <stropts.h>
-#endif
-#include <poll.h>
-#endif /* HAVE_POLL_H */
-#endif /* USE_POLL */
-#include <signal.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <sys/stat.h>
-#include <utmp.h>
-#include <sys/resource.h>
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include <sys/utsname.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#include "h.h"
-#include "res.h"
-#include "struct.h"
-#include "s_bsd.h"
-#include "s_serv.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_conf.h"
-#include "s_misc.h"
 #include "s_bsd.h"
+#include "client.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "class.h"
 #include "hash.h"
-#include "s_err.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_string.h"
 #include "ircd.h"
-#include "support.h"
-#include "s_auth.h"
-#include "class.h"
+#include "list.h"
+#include "listener.h"
+#include "numeric.h"
+#include "numnicks.h"
 #include "packet.h"
-#include "s_ping.h"
-#include "channel.h"
-#include "version.h"
 #include "parse.h"
-#include "common.h"
-#include "bsd.h"
-#include "numnicks.h"
+#include "querycmds.h"
+#include "res.h"
+#include "s_auth.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
 #include "s_user.h"
+#include "send.h"
 #include "sprintf_irc.h"
-#include "querycmds.h"
-#include "IPcheck.h"
+#include "struct.h"
+#include "support.h"
+#include "sys.h"
+#include "version.h"
+
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <unistd.h>
 
-RCSTAG_CC("$Id$");
+#ifdef USE_POLL
+#include <sys/poll.h>
+#endif /* USE_POLL */
 
 #ifndef IN_LOOPBACKNET
-#define IN_LOOPBACKNET 0x7f
+#define IN_LOOPBACKNET  0x7f
 #endif
 
-aClient *loc_clients[MAXCONNECTIONS];
-int highest_fd = 0, udpfd = -1, resfd = -1;
-unsigned int readcalls = 0;
-static struct sockaddr_in mysk;
-static void polludp();
-
-static struct sockaddr *connect_inet(aConfItem *, aClient *, int *);
-static int completed_connection(aClient *);
-static int check_init(aClient *, char *);
-static void do_dns_async(), set_sock_opts(int, aClient *);
-#ifdef UNIXPORT
-static struct sockaddr *connect_unix(aConfItem *, aClient *, int *);
-static void add_unixconnection(aClient *, int);
-static char unixpath[256];
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
 #endif
-static char readbuf[8192];
-#ifdef USE_POLL
-static struct pollfd poll_fds[MAXCONNECTIONS + 1];
-static aClient *poll_cptr[MAXCONNECTIONS + 1];
-#endif /* USE_POLL */
+
+struct Client*            LocalClientArray[MAXCONNECTIONS];
+int                       HighestFd = -1;
+static struct sockaddr_in virtualHost;
+static char               readbuf[SERVER_TCP_WINDOW];
+static int                running_in_background;
+
+/*
+ * report_error text constants
+ */
+const char* const ACCEPT_ERROR_MSG    = "error accepting connection for %s: %s";
+const char* const BIND_ERROR_MSG      = "bind error for %s: %s";
+const char* const CONNECT_ERROR_MSG   = "connect to host %s failed: %s";
+const char* const CONNLIMIT_ERROR_MSG = "connect limit exceeded for %s: %s";
+const char* const LISTEN_ERROR_MSG    = "listen error for %s: %s";
+const char* const NONB_ERROR_MSG      = "error setting non-blocking for %s: %s";
+const char* const PEERNAME_ERROR_MSG  = "getpeername failed for %s: %s";
+const char* const POLL_ERROR_MSG      = "poll error for %s: %s";
+const char* const REUSEADDR_ERROR_MSG = "error setting SO_REUSEADDR for %s: %s";
+const char* const SELECT_ERROR_MSG    = "select error for %s: %s";
+const char* const SETBUFS_ERROR_MSG   = "error setting buffer size for %s: %s";
+const char* const SOCKET_ERROR_MSG    = "error creating socket for %s: %s";
+
 #ifdef VIRTUAL_HOST
 struct sockaddr_in vserv;
 #endif
-static int running_in_background;
 
 #ifdef GODMODE
 #ifndef NODNS
@@ -131,24 +112,6 @@ static int running_in_background;
 #endif
 #endif
 
-/*
- * Try and find the correct name to use with getrlimit() for setting the max.
- * number of files allowed to be open by this process.
- */
-#ifdef RLIMIT_FDMAX
-#define RLIMIT_FD_MAX  RLIMIT_FDMAX
-#else
-#ifdef RLIMIT_NOFILE
-#define RLIMIT_FD_MAX RLIMIT_NOFILE
-#else
-#ifdef RLIMIT_OPEN_MAX
-#define RLIMIT_FD_MAX RLIMIT_OPEN_MAX
-#else
-#undef RLIMIT_FD_MAX
-#endif
-#endif
-#endif
-
 #if !defined(USE_POLL)
 #if FD_SETSIZE < (MAXCONNECTIONS + 4)
 /*
@@ -167,6 +130,7 @@ static int running_in_background;
 #endif
 #endif
 
+
 /*
  * Cannot use perror() within daemon. stderr is closed in
  * ircd and cannot be used. And, worse yet, it might have
@@ -187,1248 +151,652 @@ static int running_in_background;
  * cptr    if not NULL, is the *LOCAL* client associated with
  *         the error.
  */
-void report_error(char *text, aClient *cptr)
+void report_error(const char* text, const char* who, int err)
 {
-  Reg1 int errtmp = errno;     /* debug may change 'errno' */
-  Reg2 char *host;
-  int err;
-  size_t len = sizeof(err);
-
-  host = (cptr) ? cptr->name : "";
+  static time_t last_notice = 0;
+  int           errtmp = errno;   /* debug may change 'errno' */
+  const char*   errmsg = (err) ? strerror(err) : "";
+  
+  if (!who)
+    who = "unknown";
+
+  if (last_notice + 20 < CurrentTime) {
+    /*
+     * pace error messages so opers don't get flooded by transients
+     */
+    sendto_ops(text, who, errmsg);
+    last_notice = CurrentTime;
+  }
 
-  Debug((DEBUG_ERROR, text, host, strerror(errtmp)));
+  ircd_log(L_ERROR, text, who, errmsg);
 
-  /*
-   * Get the *real* error from the socket (well try to anyway..).
-   * This may only work when SO_DEBUG is enabled but its worth the
-   * gamble anyway.
-   */
-#if defined(SO_ERROR) && !defined(SOL2)
-  if (cptr && !IsMe(cptr) && cptr->fd >= 0)
-    if (!getsockopt(cptr->fd, SOL_SOCKET, SO_ERROR, (OPT_TYPE *)&err, &len))
-      if (err)
-       errtmp = err;
-#endif
-  sendto_ops(text, host, strerror(errtmp));
-#ifdef USE_SYSLOG
-  syslog(LOG_WARNING, text, host, strerror(errtmp));
-#endif
-  if (!running_in_background)
-  {
-    fprintf(stderr, text, host, strerror(errtmp));
+  if (!running_in_background) {
+    fprintf(stderr, text, who, errmsg);
     fprintf(stderr, "\n");
-    fflush(stderr);
   }
-  return;
+  errno = errtmp;
 }
 
+
 /*
- * inetport
- *
- * Create a socket in the AF_INET domain, bind it to the port given in
- * 'port' and listen to it.  Connections are accepted to this socket
- * depending on the IP# mask given by 'name'.  Returns the fd of the
- * socket created or -1 on error.
+ * connect_dns_callback - called when resolver query finishes
+ * if the query resulted in a successful search, reply will contain
+ * a non-null pointer, otherwise reply will be null.
+ * if successful start the connection, otherwise notify opers
  */
-int inetport(aClient *cptr, char *name, unsigned short int port)
+static void connect_dns_callback(void* vptr, struct DNSReply* reply)
 {
-  static struct sockaddr_in server;
-  int ad[4], opt;
-  size_t len = sizeof(server);
-  char ipname[20];
+  struct ConfItem* aconf = (struct ConfItem*) vptr;
+  aconf->dns_pending = 0;
+  if (reply) {
+    memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr));
+    connect_server(aconf, 0, reply);
+  }
+  else
+    sendto_ops("Connect to %s failed: host lookup", aconf->name);
+}
 
-  ad[0] = ad[1] = ad[2] = ad[3] = 0;
 
+/*
+ * connect_inet - set up address and port and make a connection
+ */
+static int connect_inet(struct ConfItem* aconf, struct Client* cptr)
+{
+  static struct sockaddr_in sin;
+  assert(0 != aconf);
+  assert(0 != cptr);
   /*
-   * do it this way because building ip# from separate values for each
-   * byte requires endian knowledge or some nasty messing. Also means
-   * easy conversion of "*" 0.0.0.0 or 134.* to 134.0.0.0 :-)
+   * Might as well get sockhost from here, the connection is attempted
+   * with it so if it fails its useless.
    */
-  sscanf(name, "%d.%d.%d.%d", &ad[0], &ad[1], &ad[2], &ad[3]);
-  sprintf_irc(ipname, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
-
-  if (cptr != &me)
-  {
-    sprintf(cptr->sockhost, "%-.42s.%u", name, port);
-    strcpy(cptr->name, me.name);
+  cptr->fd = socket(AF_INET, SOCK_STREAM, 0);
+  if (-1 == cptr->fd) {
+    cptr->error = errno;
+    report_error(SOCKET_ERROR_MSG, cptr->name, errno);
+    return 0;
+  }
+  if (cptr->fd >= MAXCLIENTS) {
+    report_error(CONNLIMIT_ERROR_MSG, cptr->name, 0);
+    close(cptr->fd);
+    cptr->fd = -1;
+    return 0;
   }
   /*
-   * At first, open a new socket
+   * Bind to a local IP# (with unknown port - let unix decide) so
+   * we have some chance of knowing the IP# that gets used for a host
+   * with more than one IP#.
+   *
+   * No we don't bind it, not all OS's can handle connecting with
+   * an already bound socket, different ip# might occur anyway
+   * leading to a freezing select() on this side for some time.
+   * I had this on my Linux 1.1.88 --Run
    */
-  if (cptr->fd == -1)
-  {
-    alarm(2);
-    cptr->fd = socket(AF_INET, SOCK_STREAM, 0);
-    alarm(0);
-    if (cptr->fd < 0 && errno == EAGAIN)
-    {
-      sendto_ops("opening stream socket %s: No more sockets",
-         cptr->name);
-      return -1;
-    }
-  }
-  if (cptr->fd < 0)
-  {
-    report_error("opening stream socket %s: %s", cptr);
-    return -1;
-  }
-  else if (cptr->fd >= MAXCLIENTS)
-  {
-    sendto_ops("No more connections allowed (%s)", cptr->name);
-    close(cptr->fd);
-    return -1;
+#ifdef VIRTUAL_HOST
+  /*
+   * No, we do bind it if we have virtual host support. If we don't
+   * explicitly bind it, it will default to IN_ADDR_ANY and we lose
+   * due to the other server not allowing our base IP --smg
+   */
+  if (bind(cptr->fd, (struct sockaddr*) &virtualHost, sizeof(virtualHost))) {
+    report_error(BIND_ERROR_MSG, cptr->name, errno);
+    return 0;
   }
+#endif
 
-  opt = 1;
-  setsockopt(cptr->fd, SOL_SOCKET, SO_REUSEADDR, (OPT_TYPE *)&opt, sizeof(opt));
-
+  memset(&sin, 0, sizeof(sin));
+  sin.sin_family      = AF_INET;
+  sin.sin_addr.s_addr = aconf->ipnum.s_addr;
+  sin.sin_port        = htons(aconf->port);
   /*
-   * Bind a port to listen for new connections if port is non-null,
-   * else assume it is already open and try get something from it.
+   * save connection info in client
    */
-  if (port)
-  {
-    server.sin_family = AF_INET;
-#ifndef VIRTUAL_HOST
-    server.sin_addr.s_addr = INADDR_ANY;
-#else
-    server.sin_addr = vserv.sin_addr;
-#endif
-#ifdef TESTNET
-    server.sin_port = htons(port + 10000);
-#else
-    server.sin_port = htons(port);
-#endif
-    if (bind(cptr->fd, (struct sockaddr *)&server, sizeof(server)) == -1)
-    {
-      report_error("binding stream socket %s: %s", cptr);
-      close(cptr->fd);
-      return -1;
-    }
+  cptr->ip.s_addr = aconf->ipnum.s_addr;
+  cptr->port      = aconf->port;
+  ircd_ntoa_r(cptr->sock_ip, (const char*) &cptr->ip);
+  /*
+   * we want a big buffer for server connections
+   */
+  if (!os_set_sockbufs(cptr->fd, SERVER_TCP_WINDOW)) {
+    cptr->error = errno;
+    report_error(SETBUFS_ERROR_MSG, cptr->name, errno);
+    return 0;
   }
-  if (getsockname(cptr->fd, (struct sockaddr *)&server, &len))
-  {
-    report_error("getsockname failed for %s: %s", cptr);
-    close(cptr->fd);
-    return -1;
+  /*
+   * ALWAYS set sockets non-blocking
+   */
+  if (!os_set_nonblocking(cptr->fd)) {
+    cptr->error = errno;
+    report_error(NONB_ERROR_MSG, cptr->name, errno);
+    return 0;
   }
-
-  if (cptr == &me)             /* KLUDGE to get it work... */
-  {
-    char buf[1024];
-
-#ifdef TESTNET
-    sprintf_irc(buf, rpl_str(RPL_MYPORTIS), me.name, "*",
-       ntohs(server.sin_port) - 10000);
-#else
-    sprintf_irc(buf, rpl_str(RPL_MYPORTIS), me.name, "*",
-       ntohs(server.sin_port));
-#endif
-    write(1, buf, strlen(buf));
+  if (!os_connect_nonb(cptr->fd, &sin)) {
+    cptr->error = errno;
+    report_error(CONNECT_ERROR_MSG, cptr->name, errno);
+    return 0;
   }
-  if (cptr->fd > highest_fd)
-    highest_fd = cptr->fd;
-  cptr->ip.s_addr = inet_addr(ipname);
-#ifdef TESTNET
-  cptr->port = ntohs(server.sin_port) - 10000;
-#else
-  cptr->port = ntohs(server.sin_port);
-#endif
-  listen(cptr->fd, 128);       /* Use listen port backlog of 128 */
-  loc_clients[cptr->fd] = cptr;
-
-  return 0;
+  return 1;
 }
 
-#ifdef UNIXPORT
 /*
- * unixport
+ * deliver_it
+ *   Attempt to send a sequence of bytes to the connection.
+ *   Returns
+ *
+ *   < 0     Some fatal error occurred, (but not EWOULDBLOCK).
+ *           This return is a request to close the socket and
+ *           clean up the link.
+ *
+ *   >= 0    No real error occurred, returns the number of
+ *           bytes actually transferred. EWOULDBLOCK and other
+ *           possibly similar conditions should be mapped to
+ *           zero return. Upper level routine will have to
+ *           decide what to do with those unwritten bytes...
+ *
+ *   *NOTE*  alarm calls have been preserved, so this should
+ *           work equally well whether blocking or non-blocking
+ *           mode is used...
  *
- * Create a socket and bind it to a filename which is comprised of the path
- * (directory where file is placed) and port (actual filename created).
- * Set directory permissions as rwxr-xr-x so other users can connect to the
- * file which is 'forced' to rwxrwxrwx (different OS's have different need of
- * modes so users can connect to the socket).
+ *   We don't use blocking anymore, that is impossible with the
+ *      net.loads today anyway. Commented out the alarms to save cpu.
+ *      --Run
  */
-int unixport(aClient *cptr, char *path, unsigned short int port)
+size_t deliver_it(struct Client *cptr, const char *str, size_t len)
 {
-  struct sockaddr_un un;
+  size_t bytes_written = 0;
+  assert(0 != cptr);
+
+  switch (os_send_nonb(cptr->fd, str, len, &bytes_written)) {
+  case IO_SUCCESS:
+    cptr->flags &= ~FLAGS_BLOCKED;
+
+    cptr->sendB += bytes_written;
+    me.sendB    += bytes_written;
+    if (cptr->sendB > 1023) {
+      cptr->sendK += (cptr->sendB >> 10);
+      cptr->sendB &= 0x03ff;    /* 2^10 = 1024, 3ff = 1023 */
+    }
+    if (me.sendB > 1023) {
+      me.sendK += (me.sendB >> 10);
+      me.sendB &= 0x03ff;
+    }
+    if (bytes_written < len)
+      cptr->flags |= FLAGS_BLOCKED;
+    break;
+  case IO_BLOCKED:
+    cptr->flags |= FLAGS_BLOCKED;
+    break;
+  case IO_FAILURE:
+    cptr->error = errno;
+    cptr->flags |= FLAGS_DEADSOCKET;
+    break;
+  }
+  return bytes_written;
+}
 
-  alarm(2);
-  cptr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  alarm(0);
-  if (cptr->fd == -1 && errno == EAGAIN)
-  {
-    sendto_ops("error opening unix domain socket %s: No more sockets",
-       cptr->name);
-    return -1;
-  }
-  if (cptr->fd == -1)
-  {
-    report_error("error opening unix domain socket %s: %s", cptr);
-    return -1;
+/*
+ * init_sys
+ */
+void init_sys(void)
+{
+  int fd;
+  int limit = os_set_fdlimit(MAXCONNECTIONS);
+  if (limit < 0) {
+    fprintf(stderr, "error setting max fd's to %d\n", limit);
+    exit(2);
   }
-  else if (cptr->fd >= MAXCLIENTS)
-  {
-    sendto_ops("No more connections allowed (%s)", cptr->name);
-    close(cptr->fd);
-    cptr->fd = -1;
-    return -1;
+  else if (limit > 0) {
+    fprintf(stderr, "ircd fd table too big\nHard Limit: %d IRC max: %d\n",
+            limit, MAXCONNECTIONS);
+    fprintf(stderr, "set MAXCONNECTIONS to a smaller value");
+    exit(2);
   }
 
-  un.sun_family = AF_UNIX;
-#if HAVE_MKDIR
-  mkdir(path, 0755);
-#else
-  if (chmod(path, 0755) == -1)
+  for (fd = 3; fd < MAXCONNECTIONS; ++fd)
   {
-    sendto_ops("error 'chmod 0755 %s': %s", path, strerror(errno));
-#ifdef USE_SYSLOG
-    syslog(LOG_WARNING, "error 'chmod 0755 %s': %s", path, strerror(errno));
-#endif
-    close(cptr->fd);
-    cptr->fd = -1;
-    return -1;
+    close(fd);
+    LocalClientArray[fd] = NULL;
   }
-#endif
-  sprintf_irc(unixpath, "%s/%u", path, port);
-  unlink(unixpath);
-  strncpy(un.sun_path, unixpath, sizeof(un.sun_path) - 1);
-  un.sun_path[sizeof(un.sun_path) - 1] = 0;
-  strcpy(cptr->name, me.name);
-  errno = 0;
-  get_sockhost(cptr, unixpath);
-
-  if (bind(cptr->fd, (struct sockaddr *)&un, strlen(unixpath) + 2) == -1)
-  {
-    report_error("error binding unix socket %s: %s", cptr);
-    close(cptr->fd);
-    return -1;
+  LocalClientArray[2] = 0;
+  LocalClientArray[1] = 0;
+  LocalClientArray[0] = 0;
+  close(1);
+  close(0);
+
+  if (bootopt & BOOT_TTY) {
+    /* debugging is going to a tty */
+    init_resolver();
+    return;
   }
-  if (cptr->fd > highest_fd)
-    highest_fd = cptr->fd;
-  listen(cptr->fd, 5);
-  chmod(unixpath, 0777);
-  cptr->flags |= FLAGS_UNIX;
-  cptr->port = 0;
-  loc_clients[cptr->fd] = cptr;
+  if (!(bootopt & BOOT_DEBUG))
+    close(2);
 
-  return 0;
-}
+  if (fork())
+    exit(0);
+  running_in_background = 1;
+#ifdef TIOCNOTTY
+  if ((fd = open("/dev/tty", O_RDWR)) > -1) {
+    ioctl(fd, TIOCNOTTY, 0);
+    close(fd);
+  }
 #endif
+  setsid();
+  init_resolver();
+}
 
-/*
- * add_listener
- *
- * Create a new client which is essentially the stub like 'me' to be used
- * for a socket that is passive (listen'ing for connections to be accepted).
- */
-int add_listener(aConfItem *aconf)
+void release_dns_reply(struct Client* cptr)
 {
-  aClient *cptr;
-
-  cptr = make_client(NULL, STAT_ME);
-  cptr->flags = FLAGS_LISTEN;
-  cptr->acpt = cptr;
-  cptr->from = cptr;
-  strncpy(cptr->name, aconf->host, sizeof(cptr->name) - 1);
-  cptr->name[sizeof(cptr->name) - 1] = 0;
-#ifdef UNIXPORT
-  if (*aconf->host == '/')
-  {
-    if (unixport(cptr, aconf->host, aconf->port))
-      cptr->fd = -2;
-  }
-  else
-#endif
-  if (inetport(cptr, aconf->host, aconf->port))
-    cptr->fd = -2;
+  assert(0 != cptr);
+  assert(MyConnect(cptr));
 
-  if (cptr->fd >= 0)
-  {
-    cptr->confs = make_link();
-    cptr->confs->next = NULL;
-    cptr->confs->value.aconf = aconf;
-    set_non_blocking(cptr->fd, cptr);
+  if (cptr->dns_reply) {
+    assert(0 < cptr->dns_reply->ref_count);
+    --cptr->dns_reply->ref_count;
+    cptr->dns_reply = 0;
   }
-  else
-    free_client(cptr);
-  return 0;
 }
 
 /*
- * close_listeners
+ * completed_connection
+ *
+ * Complete non-blocking connect()-sequence. Check access and
+ * terminate connection, if trouble detected.
  *
- * Close and free all clients which are marked as having their socket open
- * and in a state where they can accept connections.  Unix sockets have
- * the path to the socket unlinked for cleanliness.
+ * Return  TRUE, if successfully completed
+ *        FALSE, if failed and ClientExit
  */
-void close_listeners(void)
+static int completed_connection(struct Client* cptr)
 {
-  Reg1 aClient *cptr;
-  Reg2 int i;
-  Reg3 aConfItem *aconf;
+  struct ConfItem *aconf;
+  time_t newts;
+  struct Client *acptr;
+  int i;
+
+  assert(0 != cptr);
 
   /*
-   * close all 'extra' listening ports we have and unlink the file
-   * name if it was a unix socket.
+   * get the socket status from the fd first to check if
+   * connection actually succeeded
    */
-  for (i = highest_fd; i >= 0; i--)
-  {
-    if (!(cptr = loc_clients[i]))
-      continue;
-    if (!IsMe(cptr) || cptr == &me || !IsListening(cptr))
-      continue;
-    aconf = cptr->confs->value.aconf;
+  if ((cptr->error = os_get_sockerr(cptr->fd))) {
+    sendto_ops("Connection failed to %s: %s", cptr->name,
+               strerror(cptr->error));
+    return 0;
+  }
+  if (!(aconf = find_conf_byname(cptr->confs, cptr->name, CONF_SERVER))) {
+    sendto_ops("Lost Server Line for %s", cptr->name);
+    return 0;
+  }
+  if (!EmptyString(aconf->passwd))
+    sendto_one(cptr, "PASS :%s", aconf->passwd);
 
-    if (IsIllegal(aconf) && aconf->clients == 0)
-    {
-#ifdef UNIXPORT
-      if (IsUnixSocket(cptr))
-      {
-       sprintf_irc(unixpath, "%s/%u", aconf->host, aconf->port);
-       unlink(unixpath);
-      }
+#if 0 
+  /* dead code, already done in connect_server */
+  make_server(cptr);
 #endif
-      close_connection(cptr);
+  /*
+   * Create a unique timestamp
+   */
+  newts = TStime();
+  for (i = HighestFd; i > -1; --i) {
+    if ((acptr = LocalClientArray[i]) && 
+        (IsServer(acptr) || IsHandshake(acptr))) {
+      if (acptr->serv->timestamp >= newts)
+        newts = acptr->serv->timestamp + 1;
     }
   }
+  assert(0 != cptr->serv);
+
+  cptr->serv->timestamp = newts;
+  SetHandshake(cptr);
+  /*
+   * Make us timeout after twice the timeout for DNS look ups
+   */
+  cptr->lasttime = CurrentTime;
+  cptr->flags |= FLAGS_PINGSENT;
+  sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
+             me.name, me.serv->timestamp, newts, MAJOR_PROTOCOL, 
+             NumServCap(&me), me.info);
+
+  return (IsDead(cptr)) ? 0 : 1;
 }
 
 /*
- * init_sys
+ * close_connection
+ *
+ * Close the physical connection. This function must make
+ * MyConnect(cptr) == FALSE, and set cptr->from == NULL.
  */
-void init_sys(void)
+void close_connection(struct Client *cptr)
 {
-  Reg1 int fd;
-#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX)
-  struct rlimit limit;
-
-  if (!getrlimit(RLIMIT_FD_MAX, &limit))
-  {
-#ifdef pyr
-    if (limit.rlim_cur < MAXCONNECTIONS)
-#else
-    if (limit.rlim_max < MAXCONNECTIONS)
-#endif
-    {
-      fprintf(stderr, "ircd fd table too big\n");
-      fprintf(stderr, "Hard Limit: " LIMIT_FMT " IRC max: %d\n",
-#ifdef pyr
-         limit.rlim_cur,
-#else
-         limit.rlim_max,
-#endif
-         (int)MAXCONNECTIONS);
-      fprintf(stderr, "Fix MAXCONNECTIONS\n");
-      exit(-1);
+  struct ConfItem* aconf;
+
+  if (IsServer(cptr)) {
+    ServerStats->is_sv++;
+    ServerStats->is_sbs += cptr->sendB;
+    ServerStats->is_sbr += cptr->receiveB;
+    ServerStats->is_sks += cptr->sendK;
+    ServerStats->is_skr += cptr->receiveK;
+    ServerStats->is_sti += CurrentTime - cptr->firsttime;
+    if (ServerStats->is_sbs > 1023) {
+      ServerStats->is_sks += (ServerStats->is_sbs >> 10);
+      ServerStats->is_sbs &= 0x3ff;
     }
-#ifndef pyr
-    limit.rlim_cur = limit.rlim_max;   /* make soft limit the max */
-    if (setrlimit(RLIMIT_FD_MAX, &limit) == -1)
-    {
-      fprintf(stderr, "error setting max fd's to " LIMIT_FMT "\n",
-         limit.rlim_cur);
-      exit(-1);
+    if (ServerStats->is_sbr > 1023) {
+      ServerStats->is_skr += (ServerStats->is_sbr >> 10);
+      ServerStats->is_sbr &= 0x3ff;
+    }
+    /*
+     * If the connection has been up for a long amount of time, schedule
+     * a 'quick' reconnect, else reset the next-connect cycle.
+     */
+    if ((aconf = find_conf_exact(cptr->name, 0, cptr->sockhost, CONF_SERVER))) {
+      /*
+       * Reschedule a faster reconnect, if this was a automaticly
+       * connected configuration entry. (Note that if we have had
+       * a rehash in between, the status has been changed to
+       * CONF_ILLEGAL). But only do this if it was a "good" link.
+       */
+      aconf->hold = CurrentTime;
+      aconf->hold += (aconf->hold - cptr->since > HANGONGOODLINK) ?
+                     HANGONRETRYDELAY : ConfConFreq(aconf);
+      if (nextconnect > aconf->hold)
+        nextconnect = aconf->hold;
     }
-#endif
-  }
-#endif /* defined(HAVE_SETRLIMIT) && defined(RLIMIT_FD_MAX) */
-#ifdef DEBUGMODE
-  if (1)
-  {
-    static char logbuf[BUFSIZ];
-#if SETVBUF_REVERSED
-    setvbuf(stderr, _IOLBF, logbuf, sizeof(logbuf));
-#else
-    setvbuf(stderr, logbuf, _IOLBF, sizeof(logbuf));
-#endif
-  }
-#endif
-
-  for (fd = 3; fd < MAXCONNECTIONS; fd++)
-  {
-    close(fd);
-    loc_clients[fd] = NULL;
   }
-  loc_clients[1] = NULL;
-  close(1);
-
-  if (bootopt & BOOT_TTY)      /* debugging is going to a tty */
-    goto init_dgram;
-  if (!(bootopt & BOOT_DEBUG))
-    close(2);
-
-  if (((bootopt & BOOT_CONSOLE) || isatty(0)) &&
-      !(bootopt & BOOT_INETD))
-  {
-    if (fork())
-      exit(0);
-    running_in_background = 1;
-#ifdef TIOCNOTTY
-    if ((fd = open("/dev/tty", O_RDWR)) >= 0)
-    {
-      ioctl(fd, TIOCNOTTY, (char *)NULL);
-      close(fd);
+  else if (IsUser(cptr)) {
+    ServerStats->is_cl++;
+    ServerStats->is_cbs += cptr->sendB;
+    ServerStats->is_cbr += cptr->receiveB;
+    ServerStats->is_cks += cptr->sendK;
+    ServerStats->is_ckr += cptr->receiveK;
+    ServerStats->is_cti += CurrentTime - cptr->firsttime;
+    if (ServerStats->is_cbs > 1023) {
+      ServerStats->is_cks += (ServerStats->is_cbs >> 10);
+      ServerStats->is_cbs &= 0x3ff;
+    }
+    if (ServerStats->is_cbr > 1023) {
+      ServerStats->is_ckr += (ServerStats->is_cbr >> 10);
+      ServerStats->is_cbr &= 0x3ff;
     }
-#endif
-#if defined(HPUX) || defined(SOL2) || defined(_SEQUENT_) || \
-    defined(_POSIX_SOURCE) || defined(SVR4)
-    setsid();
-#else
-    setpgid(0, 0);
-#endif
-    close(0);                  /* fd 0 opened by inetd */
-    loc_clients[0] = NULL;
   }
-init_dgram:
-  resfd = init_resolver();
-
-  return;
-}
+  else
+    ServerStats->is_ni++;
 
-void write_pidfile(void)
-{
-#ifdef PPATH
-  int fd;
-  char buff[20];
-  if ((fd = open(PPATH, O_CREAT | O_WRONLY, 0600)) >= 0)
-  {
-    memset(buff, 0, sizeof(buff));
-    sprintf(buff, "%5d\n", (int)getpid());
-    if (write(fd, buff, strlen(buff)) == -1)
-      Debug((DEBUG_NOTICE, "Error writing to pid file %s", PPATH));
-    close(fd);
-    return;
+  if (-1 < cptr->fd) {
+    flush_connections(cptr);
+    LocalClientArray[cptr->fd] = 0;
+    close(cptr->fd);
+    cptr->fd = -1;
   }
-#ifdef DEBUGMODE
-  else
-    Debug((DEBUG_NOTICE, "Error opening pid file \"%s\": %s",
-       PPATH, strerror(errno)));
-#endif
-#endif
-}
+  cptr->flags |= FLAGS_DEADSOCKET;
 
-/*
- * Initialize the various name strings used to store hostnames. This is set
- * from either the server's sockhost (if client fd is a tty or localhost)
- * or from the ip# converted into a string. 0 = success, -1 = fail.
- */
-static int check_init(aClient *cptr, char *sockn)
-{
-  struct sockaddr_in sk;
-  size_t len = sizeof(struct sockaddr_in);
-  sockn[HOSTLEN] = 0;
+  DBufClear(&cptr->sendQ);
+  DBufClear(&cptr->recvQ);
+  memset(cptr->passwd, 0, sizeof(cptr->passwd));
+  set_snomask(cptr, 0, SNO_SET);
 
-#ifdef UNIXPORT
-  if (IsUnixSocket(cptr))
-  {
-    strncpy(sockn, cptr->acpt->sockhost, HOSTLEN);
-    get_sockhost(cptr, sockn);
-    return 0;
-  }
-#endif
+  det_confs_butmask(cptr, 0);
 
-  /* If descriptor is a tty, special checking... */
-  if (isatty(cptr->fd))
-  {
-    strncpy(sockn, me.name, HOSTLEN);
-    memset(&sk, 0, sizeof(struct sockaddr_in));
-  }
-  else if (getpeername(cptr->fd, (struct sockaddr *)&sk, &len) == -1)
-  {
-    report_error("connect failure: %s %s", cptr);
-    return -1;
+  if (cptr->listener) {
+    release_listener(cptr->listener);
+    cptr->listener = 0;
   }
-  strcpy(sockn, inetntoa(sk.sin_addr));
-  if (inet_netof(sk.sin_addr) == IN_LOOPBACKNET)
-  {
-    cptr->hostp = NULL;
-    strncpy(sockn, me.name, HOSTLEN);
-  }
-  memcpy(&cptr->ip, &sk.sin_addr, sizeof(struct in_addr));
-#ifdef TESTNET
-  cptr->port = ntohs(sk.sin_port) - 10000;
-#else
-  cptr->port = ntohs(sk.sin_port);
-#endif
 
-  return 0;
+  for ( ; HighestFd > 0; --HighestFd) {
+    if (LocalClientArray[HighestFd])
+      break;
+  }
 }
 
-/*
- * Ordinary client access check. Look for conf lines which have the same
- * status as the flags passed.
- */
-enum AuthorizationCheckResult check_client(aClient *cptr)
+int net_close_unregistered_connections(struct Client* source)
 {
-  static char sockname[HOSTLEN + 1];
-  Reg2 struct hostent *hp = NULL;
-  Reg3 int i;
-  enum AuthorizationCheckResult acr;
-
-  ClearAccess(cptr);
-  Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]",
-      cptr->name, inetntoa(cptr->ip)));
-
-  if (check_init(cptr, sockname))
-    return ACR_BAD_SOCKET;
-
-  if (!IsUnixSocket(cptr))
-    hp = cptr->hostp;
-  /*
-   * Verify that the host to ip mapping is correct both ways and that
-   * the ip#(s) for the socket is listed for the host.
-   */
-  if (hp)
-  {
-    for (i = 0; hp->h_addr_list[i]; i++)
-      if (!memcmp(hp->h_addr_list[i], &cptr->ip, sizeof(struct in_addr)))
-       break;
-    if (!hp->h_addr_list[i])
-    {
-      sendto_op_mask(SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%08x]",
-         inetntoa(cptr->ip), hp->h_name, *((unsigned int *)hp->h_addr));
-      hp = NULL;
+  int            i;
+  struct Client* cptr;
+  int            count = 0;
+  assert(0 != source);
+
+  for (i = HighestFd; i > 0; --i) {
+    if ((cptr = LocalClientArray[i]) && !IsRegistered(cptr)) {
+      sendto_one(source, rpl_str(RPL_CLOSING), me.name, source->name,
+                 get_client_name(source, HIDE_IP), cptr->status);
+      exit_client(source, cptr, &me, "Oper Closing");
+      ++count;
     }
   }
-
-  if ((acr = attach_Iline(cptr, hp, sockname)))
-  {
-    Debug((DEBUG_DNS, "ch_cl: access denied: %s[%s]", cptr->name, sockname));
-    return acr;
-  }
-
-  Debug((DEBUG_DNS, "ch_cl: access ok: %s[%s]", cptr->name, sockname));
-
-  if (inet_netof(cptr->ip) == IN_LOOPBACKNET || IsUnixSocket(cptr) ||
-      inet_netof(cptr->ip) == inet_netof(mysk.sin_addr))
-  {
-    ircstp->is_loc++;
-    cptr->flags |= FLAGS_LOCAL;
-  }
-  return ACR_OK;
+  return count;
 }
 
-#define CFLAG  CONF_CONNECT_SERVER
-#define NFLAG  CONF_NOCONNECT_SERVER
-
 /*
- * check_server()
- *
- * Check access for a server given its name (passed in cptr struct).
- * Must check for all C/N lines which have a name which matches the
- * name given and a host which matches. A host alias which is the
- * same as the server name is also acceptable in the host field of a
- * C/N line.
- *
- * Returns
- *  0 = Success
- * -1 = Access denied
- * -2 = Bad socket.
+ * Creates a client which has just connected to us on the given fd.
+ * The sockhost field is initialized with the ip# of the host.
+ * The client is not added to the linked list of clients, it is
+ * passed off to the auth handler for dns and ident queries.
  */
-int check_server(aClient *cptr)
+void add_connection(struct Listener* listener, int fd)
 {
-  Reg1 const char *name;
-  Reg2 aConfItem *c_conf = NULL, *n_conf = NULL;
-  struct hostent *hp = NULL;
-  Link *lp;
-  char abuff[HOSTLEN + USERLEN + 2];
-  char sockname[HOSTLEN + 1], fullname[HOSTLEN + 1];
-  int i;
-
-  name = cptr->name;
-  Debug((DEBUG_DNS, "sv_cl: check access for %s[%s]", name, cptr->sockhost));
-
-  if (IsUnknown(cptr) && !attach_confs(cptr, name, CFLAG | NFLAG))
-  {
-    Debug((DEBUG_DNS, "No C/N lines for %s", name));
-    return -1;
-  }
-  lp = cptr->confs;
+  struct sockaddr_in addr;
+  struct Client*     new_client;
+  time_t             next_target = 0;
+  const char* const throttle_message =
+         "ERROR: Your host is trying to (re)connect too fast -- throttled\r\n";
+       /* 12345678901234567890123456789012345679012345678901234567890123456 */
+  
+  assert(0 != listener);
   /*
-   * We initiated this connection so the client should have a C and N
-   * line already attached after passing through the connec_server()
-   * function earlier.
+   * Removed preliminary access check. Full check is performed in
+   * m_server and m_user instead. Also connection time out help to
+   * get rid of unwanted connections.
    */
-  if (IsConnecting(cptr) || IsHandshake(cptr))
-  {
-    c_conf = find_conf(lp, name, CFLAG);
-    n_conf = find_conf(lp, name, NFLAG);
-    if (!c_conf || !n_conf)
-    {
-      sendto_ops("Connecting Error: %s", name);
-      det_confs_butmask(cptr, 0);
-      return -1;
-    }
-  }
-#ifdef UNIXPORT
-  if (IsUnixSocket(cptr))
-  {
-    if (!c_conf)
-      c_conf = find_conf(lp, name, CFLAG);
-    if (!n_conf)
-      n_conf = find_conf(lp, name, NFLAG);
+  if (!os_get_peername(fd, &addr) || !os_set_nonblocking(fd)) {
+    ++ServerStats->is_ref;
+    close(fd);
+    return;
   }
-#endif
-
   /*
-   * If the servername is a hostname, either an alias (CNAME) or
-   * real name, then check with it as the host. Use gethostbyname()
-   * to check for servername as hostname.
+   * XXX - do we really want to do this? is it needed?
    */
-  if (!IsUnixSocket(cptr) && !cptr->hostp)
-  {
-    Reg1 aConfItem *aconf;
-
-    aconf = count_cnlines(lp);
-    if (aconf)
-    {
-      Reg1 char *s;
-      Link lin;
-
-      /*
-       * Do a lookup for the CONF line *only* and not
-       * the server connection else we get stuck in a
-       * nasty state since it takes a SERVER message to
-       * get us here and we cant interrupt that very well.
-       */
-      ClearAccess(cptr);
-      lin.value.aconf = aconf;
-      lin.flags = ASYNC_CONF;
-      nextdnscheck = 1;
-      if ((s = strchr(aconf->host, '@')))
-       s++;
-      else
-       s = aconf->host;
-      Debug((DEBUG_DNS, "sv_ci:cache lookup (%s)", s));
-      hp = gethost_byname(s, &lin);
-    }
-  }
-
-  lp = cptr->confs;
-
-  ClearAccess(cptr);
-  if (check_init(cptr, sockname))
-    return -2;
-
-check_serverback:
-  if (hp)
-  {
-    for (i = 0; hp->h_addr_list[i]; i++)
-      if (!memcmp(hp->h_addr_list[i], &cptr->ip, sizeof(struct in_addr)))
-       break;
-    if (!hp->h_addr_list[i])
-    {
-      sendto_op_mask(SNO_IPMISMATCH, "IP# Mismatch: %s != %s[%08x]",
-         inetntoa(cptr->ip), hp->h_name, *((unsigned int *)hp->h_addr));
-      hp = NULL;
-    }
-  }
-  else if (cptr->hostp)
-  {
-    hp = cptr->hostp;
-    goto check_serverback;
-  }
-
-  if (hp)
-    /*
-     * If we are missing a C or N line from above, search for
-     * it under all known hostnames we have for this ip#.
-     */
-    for (i = 0, name = hp->h_name; name; name = hp->h_aliases[i++])
-    {
-      strncpy(fullname, name, sizeof(fullname) - 1);
-      fullname[sizeof(fullname) - 1] = 0;
-      add_local_domain(fullname, HOSTLEN - strlen(fullname));
-      Debug((DEBUG_DNS, "sv_cl: gethostbyaddr: %s->%s", sockname, fullname));
-      sprintf_irc(abuff, "%s@%s", cptr->username, fullname);
-      if (!c_conf)
-       c_conf = find_conf_host(lp, abuff, CFLAG);
-      if (!n_conf)
-       n_conf = find_conf_host(lp, abuff, NFLAG);
-      if (c_conf && n_conf)
-      {
-       get_sockhost(cptr, fullname);
-       break;
-      }
-    }
-  name = cptr->name;
+  os_disable_options(fd);
 
   /*
-   * Check for C and N lines with the hostname portion the ip number
-   * of the host the server runs on. This also checks the case where
-   * there is a server connecting from 'localhost'.
-   */
-  if (IsUnknown(cptr) && (!c_conf || !n_conf))
-  {
-    sprintf_irc(abuff, "%s@%s", cptr->username, sockname);
-    if (!c_conf)
-      c_conf = find_conf_host(lp, abuff, CFLAG);
-    if (!n_conf)
-      n_conf = find_conf_host(lp, abuff, NFLAG);
-  }
-  /*
-   * Attach by IP# only if all other checks have failed.
-   * It is quite possible to get here with the strange things that can
-   * happen when using DNS in the way the irc server does. -avalon
-   */
-  if (!hp)
-  {
-    if (!c_conf)
-      c_conf = find_conf_ip(lp, (char *)&cptr->ip, cptr->username, CFLAG);
-    if (!n_conf)
-      n_conf = find_conf_ip(lp, (char *)&cptr->ip, cptr->username, NFLAG);
-  }
-  else
-    for (i = 0; hp->h_addr_list[i]; i++)
-    {
-      if (!c_conf)
-       c_conf = find_conf_ip(lp, hp->h_addr_list[i], cptr->username, CFLAG);
-      if (!n_conf)
-       n_conf = find_conf_ip(lp, hp->h_addr_list[i], cptr->username, NFLAG);
-    }
-  /*
-   * detach all conf lines that got attached by attach_confs()
-   */
-  det_confs_butmask(cptr, 0);
-  /*
-   * if no C or no N lines, then deny access
+   * Add this local client to the IPcheck registry.
+   * If it is a connection to a user port and if the site has been throttled,
+   * reject the user.
    */
-  if (!c_conf || !n_conf)
-  {
-    get_sockhost(cptr, sockname);
-    Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s] c %p n %p",
-       name, cptr->username, cptr->sockhost, c_conf, n_conf));
-    return -1;
+  if (!IPcheck_local_connect(addr.sin_addr, &next_target) && !listener->server) {
+    ++ServerStats->is_ref;
+    /*
+     * strlen(throttle_message) == 66
+     */
+    send(fd, throttle_message, 66, 0);
+    close(fd);
+    return;
   }
+
+  new_client = make_client(NULL,
+      (listener->server) ? STAT_UNKNOWN_SERVER : STAT_UNKNOWN_USER);
   /*
-   * attach the C and N lines to the client structure for later use.
+   * Copy ascii address to 'sockhost' just in case. Then we
+   * have something valid to put into error messages...
    */
-  attach_conf(cptr, n_conf);
-  attach_conf(cptr, c_conf);
-  attach_confs(cptr, name, CONF_HUB | CONF_LEAF | CONF_UWORLD);
+  ircd_ntoa_r(new_client->sock_ip, (const char*) &addr.sin_addr);   
+  strcpy(new_client->sockhost, new_client->sock_ip);
+  new_client->ip.s_addr = addr.sin_addr.s_addr;
+  new_client->port      = ntohs(addr.sin_port);
 
-  if ((c_conf->ipnum.s_addr == INADDR_NONE) && !IsUnixSocket(cptr))
-    memcpy(&c_conf->ipnum, &cptr->ip, sizeof(struct in_addr));
-  if (!IsUnixSocket(cptr))
-    get_sockhost(cptr, c_conf->host);
+  if (next_target)
+    new_client->nexttarget = next_target;
 
-  Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", name, cptr->sockhost));
-  return 0;
-}
-#undef CFLAG
-#undef NFLAG
+  new_client->fd = fd;
 
-/*
- * completed_connection
- *
- * Complete non-blocking connect()-sequence. Check access and
- * terminate connection, if trouble detected.
- *
- * Return  TRUE, if successfully completed
- *        FALSE, if failed and ClientExit
- */
-static int completed_connection(aClient *cptr)
-{
-  aConfItem *aconf;
-  time_t newts;
-  aClient *acptr;
-  int i;
-
-  aconf = find_conf(cptr->confs, cptr->name, CONF_CONNECT_SERVER);
-  if (!aconf)
-  {
-    sendto_ops("Lost C-Line for %s", cptr->name);
-    return -1;
-  }
-  if (!BadPtr(aconf->passwd))
-    sendto_one(cptr, "PASS :%s", aconf->passwd);
-
-  aconf = find_conf(cptr->confs, cptr->name, CONF_NOCONNECT_SERVER);
-  if (!aconf)
-  {
-    sendto_ops("Lost N-Line for %s", cptr->name);
-    return -1;
-  }
-  make_server(cptr);
-  /* Create a unique timestamp */
-  newts = TStime();
-  for (i = highest_fd; i >= 0; i--)
-  {
-    if (!(acptr = loc_clients[i]) || (!IsServer(acptr) && !IsHandshake(acptr)))
-      continue;
-    if (acptr->serv->timestamp >= newts)
-      newts = acptr->serv->timestamp + 1;
-  }
-  cptr->serv->timestamp = newts;
-  SetHandshake(cptr);
-  /* Make us timeout after twice the timeout for DNS look ups */
-  cptr->lasttime = now;
-  cptr->flags |= FLAGS_PINGSENT;
-  sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
-      my_name_for_link(me.name, aconf), me.serv->timestamp,
-      newts, MAJOR_PROTOCOL, NumServCap(&me), me.info);
-  if (!IsDead(cptr))
-    start_auth(cptr);
+  if (!listener->server)
+    SetIPChecked(new_client);
+  new_client->listener = listener;
+  ++listener->ref_count;
 
-  return (IsDead(cptr)) ? -1 : 0;
+  Count_newunknown(UserStats);
+  /*
+   * if we've made it this far we can put the client on the auth query pile
+   */
+  start_auth(new_client);
 }
 
 /*
- * close_connection
+ * read_packet
  *
- * Close the physical connection. This function must make
- * MyConnect(cptr) == FALSE, and set cptr->from == NULL.
+ * Read a 'packet' of data from a connection and process it.  Read in 8k
+ * chunks to give a better performance rating (for server connections).
+ * Do some tricky stuff for client connections to make sure they don't do
+ * any flooding >:-) -avalon
  */
-void close_connection(aClient *cptr)
+static int read_packet(struct Client *cptr, int socket_ready)
 {
-  Reg1 aConfItem *aconf;
-  Reg2 int i, j;
-  int empty = cptr->fd;
-
-  if (IsServer(cptr))
-  {
-    ircstp->is_sv++;
-    ircstp->is_sbs += cptr->sendB;
-    ircstp->is_sbr += cptr->receiveB;
-    ircstp->is_sks += cptr->sendK;
-    ircstp->is_skr += cptr->receiveK;
-    ircstp->is_sti += now - cptr->firsttime;
-    if (ircstp->is_sbs > 1023)
-    {
-      ircstp->is_sks += (ircstp->is_sbs >> 10);
-      ircstp->is_sbs &= 0x3ff;
-    }
-    if (ircstp->is_sbr > 1023)
-    {
-      ircstp->is_skr += (ircstp->is_sbr >> 10);
-      ircstp->is_sbr &= 0x3ff;
-    }
-  }
-  else if (IsUser(cptr))
-  {
-    ircstp->is_cl++;
-    ircstp->is_cbs += cptr->sendB;
-    ircstp->is_cbr += cptr->receiveB;
-    ircstp->is_cks += cptr->sendK;
-    ircstp->is_ckr += cptr->receiveK;
-    ircstp->is_cti += now - cptr->firsttime;
-    if (ircstp->is_cbs > 1023)
-    {
-      ircstp->is_cks += (ircstp->is_cbs >> 10);
-      ircstp->is_cbs &= 0x3ff;
-    }
-    if (ircstp->is_cbr > 1023)
-    {
-      ircstp->is_ckr += (ircstp->is_cbr >> 10);
-      ircstp->is_cbr &= 0x3ff;
+  size_t dolen = 0;
+  size_t length = 0;
+
+  if (socket_ready && !(IsUser(cptr) && DBufLength(&cptr->recvQ) > CLIENT_FLOOD)) {
+    switch (os_recv_nonb(cptr->fd, readbuf, sizeof(readbuf), &length)) {
+    case IO_SUCCESS:
+      if (length) {
+        cptr->lasttime = CurrentTime;
+        if (cptr->lasttime > cptr->since)
+          cptr->since = cptr->lasttime;
+        cptr->flags &= ~(FLAGS_PINGSENT | FLAGS_NONL);
+      }
+      break;
+    case IO_BLOCKED:
+      break;
+    case IO_FAILURE:
+      cptr->error = errno;
+      /* cptr->flags |= FLAGS_DEADSOCKET; */
+      return 0;
     }
   }
-  else
-    ircstp->is_ni++;
 
   /*
-   * Remove outstanding DNS queries.
-   */
-  del_queries((char *)cptr);
-  /*
-   * If the connection has been up for a long amount of time, schedule
-   * a 'quick' reconnect, else reset the next-connect cycle.
+   * For server connections, we process as many as we can without
+   * worrying about the time of day or anything :)
    */
-
-  if ((aconf = find_conf_exact(cptr->name, cptr->username,
-      cptr->sockhost, CONF_CONNECT_SERVER)))
-  {
+  if (length > 0 && IsServer(cptr)) {
+    return server_dopacket(cptr, readbuf, length);
+  }
+  else {
     /*
-     * Reschedule a faster reconnect, if this was a automaticly
-     * connected configuration entry. (Note that if we have had
-     * a rehash in between, the status has been changed to
-     * CONF_ILLEGAL). But only do this if it was a "good" link.
+     * Before we even think of parsing what we just read, stick
+     * it on the end of the receive queue and do it when its
+     * turn comes around.
      */
-    aconf->hold = now;
-    aconf->hold += (aconf->hold - cptr->since > HANGONGOODLINK) ?
-       HANGONRETRYDELAY : ConfConFreq(aconf);
-    if (nextconnect > aconf->hold)
-      nextconnect = aconf->hold;
-  }
-
-  if (cptr->authfd >= 0)
-    close(cptr->authfd);
-
-  if (cptr->fd >= 0)
-  {
-    flush_connections(cptr->fd);
-    loc_clients[cptr->fd] = NULL;
-    close(cptr->fd);
-    cptr->fd = -2;
-  }
-
-  DBufClear(&cptr->sendQ);
-  DBufClear(&cptr->recvQ);
-  memset(cptr->passwd, 0, sizeof(cptr->passwd));
-  set_snomask(cptr, 0, SNO_SET);
-  /*
-   * Clean up extra sockets from P-lines which have been discarded.
-   */
-  if (cptr->acpt != &me && cptr->acpt != cptr)
-  {
-    aconf = cptr->acpt->confs->value.aconf;
-    if (aconf->clients > 0)
-      aconf->clients--;
-    if (!aconf->clients && IsIllegal(aconf))
-      close_connection(cptr->acpt);
-  }
-
-  for (; highest_fd > 0; highest_fd--)
-    if (loc_clients[highest_fd])
-      break;
-
-  det_confs_butmask(cptr, 0);
-
-  /*
-   * fd remap to keep loc_clients[i] filled at the bottom.
-   */
-  if (empty > 0)
-    if ((j = highest_fd) > (i = empty) && !IsLog(loc_clients[j]))
-    {
-      if (IsListening(loc_clients[j]))
-       return;
-      if (dup2(j, i) == -1)
-       return;
-      loc_clients[i] = loc_clients[j];
-      loc_clients[i]->fd = i;
-      loc_clients[j] = NULL;
-      close(j);
-      while (!loc_clients[highest_fd])
-       highest_fd--;
+    if (length > 0 && 0 == dbuf_put(&cptr->recvQ, readbuf, length)) {
+      return exit_client(cptr, cptr, &me, "dbuf_put fail");
     }
+#ifndef NOFLOODCONTROL
+    /*
+     * XXX - cptr will always be a user or unregistered
+     */
+    if (IsUser(cptr) && DBufLength(&cptr->recvQ) > CLIENT_FLOOD)
+      return exit_client(cptr, cptr, &me, "Excess Flood");
 
-  return;
-}
-
-/*
- *  set_sock_opts
- */
-static void set_sock_opts(int fd, aClient *cptr)
-{
-  size_t opt;
-#ifdef SO_REUSEADDR
-  opt = 1;
-  if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
-      (OPT_TYPE *)&opt, sizeof(opt)) < 0)
-    report_error("setsockopt(SO_REUSEADDR) %s: %s", cptr);
-#endif
-#ifdef SO_USELOOPBACK
-  opt = 1;
-  if (setsockopt(fd, SOL_SOCKET, SO_USELOOPBACK,
-      (OPT_TYPE *)&opt, sizeof(opt)) < 0)
-    report_error("setsockopt(SO_USELOOPBACK) %s: %s", cptr);
-#endif
-#ifdef SO_RCVBUF
-  opt = 8192;
-  if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (OPT_TYPE *)&opt, sizeof(opt)) < 0)
-    report_error("setsockopt(SO_RCVBUF) %s: %s", cptr);
-#endif
-#ifdef SO_SNDBUF
-#ifdef _SEQUENT_
-/*
- * Seems that Sequent freezes up if the receving buffer is a different size
- * to the sending buffer (maybe a tcp window problem too).
- */
-  opt = 8192;
+    while (DBufLength(&cptr->recvQ) && !NoNewLine(cptr) && 
+           (IsTrusted(cptr) || cptr->since - CurrentTime < 10))
 #else
-  opt = 8192;
+    while (DBufLength(&cptr->recvQ) && !NoNewLine(cptr))
 #endif
-  if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (OPT_TYPE *)&opt, sizeof(opt)) < 0)
-    report_error("setsockopt(SO_SNDBUF) %s: %s", cptr);
-#endif
-#if defined(IP_OPTIONS) && defined(IPPROTO_IP)
-  {
-    char *s = readbuf, *t = readbuf + sizeof(readbuf) / 2;
-
-    opt = sizeof(readbuf) / 8;
-    if (getsockopt(fd, IPPROTO_IP, IP_OPTIONS, (OPT_TYPE *)t, &opt) < 0)
-      report_error("getsockopt(IP_OPTIONS) %s: %s", cptr);
-    else if (opt > 0 && opt != sizeof(readbuf) / 8)
     {
-      for (*readbuf = '\0'; opt > 0; opt--, s += 3)
-       sprintf(s, "%02x:", *t++);
-      *s = '\0';
-      sendto_ops("Connection %s using IP opts: (%s)",
-         get_client_name(cptr, FALSE), readbuf);
+      /*
+       * If it has become registered as a Server
+       * then skip the per-message parsing below.
+       */
+      if (IsServer(cptr)) {
+        dolen = dbuf_get(&cptr->recvQ, readbuf, sizeof(readbuf));
+        return (dolen) ? server_dopacket(cptr, readbuf, dolen) : 1;
+      }
+      dolen = dbuf_getmsg(&cptr->recvQ, cptr->buffer, BUFSIZE);
+      /*
+       * Devious looking...whats it do ? well..if a client
+       * sends a *long* message without any CR or LF, then
+       * dbuf_getmsg fails and we pull it out using this
+       * loop which just gets the next 512 bytes and then
+       * deletes the rest of the buffer contents.
+       * -avalon
+       */
+      if (0 == dolen) {
+        if (DBufLength(&cptr->recvQ) < 510)
+          cptr->flags |= FLAGS_NONL;
+        else
+          DBufClear(&cptr->recvQ);
+      }
+      else if (CPTR_KILLED == client_dopacket(cptr, dolen))
+        return CPTR_KILLED;
     }
-    if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, (OPT_TYPE *)NULL, 0) < 0)
-      report_error("setsockopt(IP_OPTIONS) %s: %s", cptr);
   }
-#endif
-}
-
-int get_sockerr(aClient *cptr)
-{
-  int errtmp = errno, err = 0;
-  size_t len = sizeof(err);
-#if defined(SO_ERROR) && !defined(SOL2)
-  if (cptr->fd >= 0)
-    if (!getsockopt(cptr->fd, SOL_SOCKET, SO_ERROR, (OPT_TYPE *)&err, &len))
-      if (err)
-       errtmp = err;
-#endif
-  return errtmp;
+  return 1;
 }
 
-/*
- * set_non_blocking
- *
- * Set the client connection into non-blocking mode. If your
- * system doesn't support this, you can make this a dummy
- * function (and get all the old problems that plagued the
- * blocking version of IRC--not a problem if you are a
- * lightly loaded node...)
- */
-void set_non_blocking(int fd, aClient *cptr)
+static int on_write_unblocked(struct Client* cptr)
 {
-  int res;
-#ifndef NBLOCK_SYSV
-  int nonb = 0;
-#endif
-
   /*
-   * NOTE: consult ALL your relevant manual pages *BEFORE* changing
-   * these ioctl's. There are quite a few variations on them,
-   * as can be seen by the PCS one. They are *NOT* all the same.
-   * Heed this well. - Avalon.
+   *  ...room for writing, empty some queue then...
    */
-#ifdef NBLOCK_POSIX
-  nonb |= O_NONBLOCK;
-#endif
-#ifdef NBLOCK_BSD
-  nonb |= O_NDELAY;
-#endif
-#ifdef NBLOCK_SYSV
-  /* This portion of code might also apply to NeXT. -LynX */
-  res = 1;
-
-  if (ioctl(fd, FIONBIO, &res) < 0)
-    report_error("ioctl(fd,FIONBIO) failed for %s: %s", cptr);
-#else
-  if ((res = fcntl(fd, F_GETFL, 0)) == -1)
-    report_error("fcntl(fd, F_GETFL) failed for %s: %s", cptr);
-  else if (fcntl(fd, F_SETFL, res | nonb) == -1)
-    report_error("fcntl(fd, F_SETL, nonb) failed for %s: %s", cptr);
-#endif
-  return;
+  cptr->flags &= ~FLAGS_BLOCKED;
+  if (IsConnecting(cptr)) {
+    if (!completed_connection(cptr))
+      return 0;
+  }
+  else if (cptr->listing && DBufLength(&cptr->sendQ) < 2048)
+    list_next_channels(cptr, 64);
+  send_queued(cptr);
+  return 1;
 }
 
-extern unsigned short server_port;
-
 /*
- * Creates a client which has just connected to us on the given fd.
- * The sockhost field is initialized with the ip# of the host.
- * The client is added to the linked list of clients but isnt added to any
- * hash tables yet since it doesn't have a name.
+ * Select / Poll Read Algorithm for ircd
+ *
+ * We need to check the file descriptors for all the different types
+ * of things that use them, so check for reads on everything but connects
+ * and writes on connects and descriptors that are blocked
+ *
+ * for each (client in local) {
+ *   if (not connecting)
+ *     check for read;
+ *   if (connecting or blocked)
+ *     check for write;
+ * }
+ * wait for activity;
+ *
+ * for each (client in local) {
+ *   if (there are descriptors to check) {
+ *     if (write activity)
+ *       send data;
+ *     if (read activity)
+ *       read data;
+ *   }
+ *   process data read;
+ * }
+ * Note we must always process data read whether or not there has been
+ * read activity or file descriptors set, since data is buffered by the client.
  */
-aClient *add_connection(aClient *cptr, int fd, int type)
-{
-  Link lin;
-  aClient *acptr;
-  aConfItem *aconf = NULL;
-  acptr =
-      make_client(NULL,
-      (cptr->port == server_port) ? STAT_UNKNOWN_SERVER : STAT_UNKNOWN_USER);
-
-  if (cptr != &me)
-    aconf = cptr->confs->value.aconf;
-  /*
-   * Removed preliminary access check. Full check is performed in
-   * m_server and m_user instead. Also connection time out help to
-   * get rid of unwanted connections.
-   */
-  if (type == ADCON_TTY)       /* If descriptor is a tty,
-                                  special checking... */
-    get_sockhost(acptr, cptr->sockhost);
-  else
-  {
-    Reg1 char *s, *t;
-    struct sockaddr_in addr;
-    size_t len = sizeof(struct sockaddr_in);
-
-    if (getpeername(fd, (struct sockaddr *)&addr, &len) == -1)
-    {
-      report_error("Failed in connecting to %s: %s", cptr);
-    add_con_refuse:
-      ircstp->is_ref++;
-      acptr->fd = -2;
-      free_client(acptr);
-      close(fd);
-      return NULL;
-    }
-    /* Don't want to add "Failed in connecting to" here.. */
-    if (aconf && IsIllegal(aconf))
-      goto add_con_refuse;
-    /*
-     * Copy ascii address to 'sockhost' just in case. Then we
-     * have something valid to put into error messages...
-     */
-    get_sockhost(acptr, inetntoa(addr.sin_addr));
-    memcpy(&acptr->ip, &addr.sin_addr, sizeof(struct in_addr));
-#ifdef TESTNET
-    acptr->port = ntohs(addr.sin_port) - 10000;
-#else
-    acptr->port = ntohs(addr.sin_port);
-#endif
-
-    /*
-     * Check that this socket (client) is allowed to accept
-     * connections from this IP#.
-     */
-    for (s = (char *)&cptr->ip, t = (char *)&acptr->ip, len = 4;
-       len > 0; len--, s++, t++)
-    {
-      if (!*s)
-       continue;
-      if (*s != *t)
-       break;
-    }
-
-    if (len)
-      goto add_con_refuse;
 
-    lin.flags = ASYNC_CLIENT;
-    lin.value.cptr = acptr;
-#ifdef NODNS
-    if (!strcmp("127.0.0.1", inetntoa(addr.sin_addr)))
-    {
-      static struct hostent lhe = { "localhost", NULL, 0, 0, NULL };
-      acptr->hostp = &lhe;
-      if (!DoingAuth(acptr))
-       SetAccess(acptr);
-    }
-    else
-    {
-#endif
-      Debug((DEBUG_DNS, "lookup %s", inetntoa(addr.sin_addr)));
-      acptr->hostp = gethost_byaddr(&acptr->ip, &lin);
-      if (!acptr->hostp)
-       SetDNS(acptr);
-      nextdnscheck = 1;
-#ifdef NODNS
-    }
-#endif
-  }
-
-  if (aconf)
-    aconf->clients++;
-  acptr->fd = fd;
-  if (fd > highest_fd)
-    highest_fd = fd;
-  loc_clients[fd] = acptr;
-  acptr->acpt = cptr;
-  Count_newunknown(nrof);
-  add_client_to_list(acptr);
-  set_non_blocking(acptr->fd, acptr);
-  set_sock_opts(acptr->fd, acptr);
-
-  /*
-   * Add this local client to the IPcheck registry.
-   * If it is a connection to a user port and if the site has been throttled,
-   * reject the user.
-   */
-  if (IPcheck_local_connect(acptr) == -1 && IsUserPort(acptr))
-  {
-    ircstp->is_ref++;
-    exit_client(cptr, acptr, &me,
-       "Your host is trying to (re)connect too fast -- throttled");
-    return NULL;
-  }
-
-  start_auth(acptr);
-  return acptr;
-}
 
-#ifdef UNIXPORT
-static void add_unixconnection(aClient *cptr, int fd)
-{
-  aClient *acptr;
-  aConfItem *aconf = NULL;
-
-  acptr = make_client(NULL, STAT_UNKNOWN);
-
-  /*
-   * Copy ascii address to 'sockhost' just in case. Then we
-   * have something valid to put into error messages...
-   */
-  strncpy(acptr->sockhost, me.name, HOSTLEN);
-  if (cptr != &me)
-    aconf = cptr->confs->value.aconf;
-  if (aconf)
-  {
-    if (IsIllegal(aconf))
-    {
-      ircstp->is_ref++;
-      acptr->fd = -2;
-      free_client(acptr);
-      close(fd);
-      return;
-    }
-    else
-      aconf->clients++;
-  }
-  acptr->fd = fd;
-  if (fd > highest_fd)
-    highest_fd = fd;
-  loc_clients[fd] = acptr;
-  acptr->acpt = cptr;
-  SetUnixSock(acptr);
-  memcpy(&acptr->ip, &me.ip, sizeof(struct in_addr));
-
-  Count_newunknown(nrof);
-  add_client_to_list(acptr);
-  set_non_blocking(acptr->fd, acptr);
-  set_sock_opts(acptr->fd, acptr);
-  SetAccess(acptr);
-  return;
-}
-#endif
+#ifdef USE_POLL
 
 /*
- * select/poll convert macro's by Run.
- *
- * The names are chosen to reflect what they means when NOT using poll().
+ * poll macros
  */
-#ifndef USE_POLL
-typedef fd_set *fd_setp_t;
-#define RFD_ISSET(fd, rfd, index) FD_ISSET((fd), (rfd))
-#define WFD_ISSET(fd, wfd, index) FD_ISSET((fd), (wfd))
-#define RFD_SET(fd, rfd, index, cptr) FD_SET((fd), (rfd))
-#define WFD_SET(fd, wfd, index, cptr) FD_SET((fd), (wfd))
-#define RWFD_SET(fd, wfd, index) FD_SET((fd), (wfd))
-#define RFD_CLR_OUT(fd, rfd, index) FD_CLR((fd), (rfd))
-#define WFD_CLR_OUT(fd, wfd, index) FD_CLR((fd), (wfd))
-#define LOC_FD(index) (index)
-#define LOC_CLIENTS(index) loc_clients[index]
-#define HIGHEST_INDEX highest_fd
-#else /* USE_POLL */
-typedef unsigned int fd_setp_t;        /* Actually, an index to poll_fds[] */
-#ifdef _AIX
-#define POLLREADFLAGS (POLLIN|POLLMSG)
+#if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
+#  define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
 #else
-#  if defined(POLLMSG) && defined(POLLIN) && defined(POLLRDNORM)
-#    define POLLREADFLAGS (POLLMSG|POLLIN|POLLRDNORM)
+#  if defined(POLLIN) && defined(POLLRDNORM)
+#    define POLLREADFLAGS (POLLIN|POLLRDNORM)
 #  else
-#    if defined(POLLIN) && defined(POLLRDNORM)
-#      define POLLREADFLAGS (POLLIN|POLLRDNORM)
+#    if defined(POLLIN)
+#      define POLLREADFLAGS POLLIN
 #    else
-#      if defined(POLLIN)
-#        define POLLREADFLAGS POLLIN
-#      else
-#        if defined(POLLRDNORM)
-#          define POLLREADFLAGS POLLRDNORM
-#        endif
+#      if defined(POLLRDNORM)
+#        define POLLREADFLAGS POLLRDNORM
 #      endif
 #    endif
 #  endif
 #endif
+
 #if defined(POLLOUT) && defined(POLLWRNORM)
 #define POLLWRITEFLAGS (POLLOUT|POLLWRNORM)
 #else
@@ -1440,155 +808,232 @@ typedef unsigned int fd_setp_t;        /* Actually, an index to poll_fds[] */
 #    endif
 #  endif
 #endif
+
 #ifdef POLLHUP
 #define POLLERRORS (POLLHUP|POLLERR)
 #else
 #define POLLERRORS POLLERR
 #endif
-#define RFD_ISSET(fd, rfd, index) \
-  ((poll_fds[index].revents & POLLREADFLAGS) || \
-  ((poll_fds[index].events & POLLREADFLAGS) && \
-    (poll_fds[index].revents & POLLERRORS)))
-#define WFD_ISSET(fd, wfd, index) \
-  ((poll_fds[index].revents & POLLWRITEFLAGS) || \
-  ((poll_fds[index].events & POLLWRITEFLAGS) && \
-    (poll_fds[index].revents & POLLERRORS)))
-#define RFD_SET(fdes, rfd, index, cptr) \
-  do { \
-    poll_fds[index].fd = fdes; \
-    poll_cptr[index] = cptr; \
-    poll_fds[index].events = POLLREADFLAGS; \
-    added = TRUE; \
-  } while(0)
-#define WFD_SET(fdes, wfd, index, cptr) \
-  do { \
-    poll_fds[index].fd = fdes; \
-    poll_cptr[index] = cptr; \
-    if (added) \
-      poll_fds[index].events |= POLLWRITEFLAGS; \
-    else \
-    { \
-      poll_fds[index].events = POLLWRITEFLAGS; \
-      added = TRUE; \
-    } \
-  } while(0)
-/* This identical to WFD_SET() when used after a call to RFD_SET(): */
-#define RWFD_SET(fd, wfd, index) poll_fds[index].events |= POLLWRITEFLAGS
-/* [RW]FD_CLR_OUT() clears revents, not events */
-#define RFD_CLR_OUT(fd, rfd, index) poll_fds[index].revents &= ~POLLREADFLAGS
-#define WFD_CLR_OUT(fd, wfd, index) poll_fds[index].revents &= ~POLLWRITEFLAGS
-#define LOC_FD(index) (poll_fds[index].fd)
-#define LOC_CLIENTS(index) (poll_cptr[index])
-#define HIGHEST_INDEX (currfd_index - 1)
-#endif /* USE_POLL */
 
 /*
- * read_packet
+ * NOTE: pfd and pfd_count are local variable names in read_message
+ */
+#define PFD_SETR(xfd) \
+  do { CHECK_ADD_PFD(xfd) pfd->events |= POLLREADFLAGS; } while(0)
+#define PFD_SETW(xfd) \
+  do { CHECK_ADD_PFD(xfd) pfd->events |= POLLWRITEFLAGS; } while(0)
+
+#define CHECK_ADD_PFD(xfd) \
+  if (pfd->fd != xfd) { \
+    pfd = &poll_fds[pfd_count++]; \
+    poll_fds[pfd_count].fd = -1; \
+    pfd->fd = xfd; \
+    pfd->events = 0; \
+  }
+
+/*
+ * Check all connections for new connections and input data that is to be
+ * processed. Also check for connections with data queued and whether we can
+ * write it out.
  *
- * Read a 'packet' of data from a connection and process it.  Read in 8k
- * chunks to give a better performance rating (for server connections).
- * Do some tricky stuff for client connections to make sure they don't do
- * any flooding >:-) -avalon
+ * Don't ever use ZERO for `delay', unless you mean to poll and then
+ * you have to have sleep/wait somewhere else in the code.--msa
  */
-static int read_packet(aClient *cptr, fd_setp_t rfd)
+int read_message(time_t delay)
 {
-  size_t dolen = 0;
-  int length = 0;
-  int done;
+  struct pollfd poll_fds[MAXCONNECTIONS + 1];
+  struct Client*    cptr;
+  struct Listener*    listener  = 0;
+  struct AuthRequest* auth      = 0;
+  struct AuthRequest* auth_next = 0;
+  int nfds;
+  time_t delay2 = delay;
+  int length;
+  int i;
+  int res = 0;
+  int pfd_count = 0;
+  struct pollfd* pfd = 0;
+  struct pollfd* res_pfd = 0;
+  int read_ready;
+  int write_ready;
 
-  if (RFD_ISSET(cptr->fd, rfd, rfd) &&
-      !(IsUser(cptr) && DBufLength(&cptr->recvQ) > 6090))
-  {
-    errno = 0;
-    length = recv(cptr->fd, readbuf, sizeof(readbuf), 0);
+  unsigned long timeout;
 
-    cptr->lasttime = now;
-    if (cptr->lasttime > cptr->since)
-      cptr->since = cptr->lasttime;
-    cptr->flags &= ~(FLAGS_PINGSENT | FLAGS_NONL);
+  for ( ; ; ) {
+    pfd_count = 0;
+    pfd = poll_fds;
+    res_pfd = 0;
+    pfd->fd = -1;
+
+    if (-1 < ResolverFileDescriptor) {
+      PFD_SETR(ResolverFileDescriptor);
+      res_pfd = pfd;
+    }
     /*
-     * If not ready, fake it so it isnt closed
+     * add auth file descriptors
      */
-    if (length == -1 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
-      return 1;
-    if (length <= 0)
-      return length;
+    for (auth = AuthPollList; auth; auth = auth->next) {
+      assert(-1 < auth->fd);
+      auth->index = pfd_count;
+      if (IsAuthConnect(auth))
+        PFD_SETW(auth->fd);
+      else
+        PFD_SETR(auth->fd);
+    }
+    /*
+     * add listener file descriptors
+     */    
+    for (listener = ListenerPollList; listener; listener = listener->next) {
+      assert(-1 < listener->fd);
+      /*
+       * pfd_count is incremented by PFD_SETR so we need to save the 
+       * index first 
+       */
+      listener->index = pfd_count;
+      PFD_SETR(listener->fd);
+    }
+
+    for (i = HighestFd; -1 < i; --i) {
+      if ((cptr = LocalClientArray[i])) {
+
+        if (DBufLength(&cptr->recvQ))
+          delay2 = 1;
+        if (DBufLength(&cptr->recvQ) < 4088 || IsServer(cptr)) {
+          PFD_SETR(i);
+        }
+        if (DBufLength(&cptr->sendQ) || IsConnecting(cptr) ||
+            (cptr->listing && DBufLength(&cptr->sendQ) < 2048)) {
+          PFD_SETW(i);
+        }
+      }
+    }
+
+    Debug((DEBUG_INFO, "poll: %d %d", delay, delay2));
+
+    timeout = (IRCD_MIN(delay2, delay)) * 1000;
+
+    nfds = poll(poll_fds, pfd_count, timeout);
+
+    CurrentTime = time(0);
+    if (-1 < nfds)
+      break;
+
+    if (EINTR == errno)
+      return -1;
+    report_error(POLL_ERROR_MSG, me.name, errno);
+    ++res;
+    if (res > 5)
+      server_restart("too many poll errors");
+    sleep(1);
+    CurrentTime = time(0);
   }
 
+  if (res_pfd && (res_pfd->revents & (POLLREADFLAGS | POLLERRORS))) {
+    resolver_read();
+    --nfds;
+  }
   /*
-   * For server connections, we process as many as we can without
-   * worrying about the time of day or anything :)
+   * check auth queries
    */
-  if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr))
-  {
-    if (length > 0)
-      if ((done = dopacket(cptr, readbuf, length)))
-       return done;
-  }
-  else
-  {
+  for (auth = AuthPollList; auth; auth = auth_next) {
+    auth_next = auth->next;
+    i = auth->index;
     /*
-     * Before we even think of parsing what we just read, stick
-     * it on the end of the receive queue and do it when its
-     * turn comes around.
+     * check for any event, we only ask for one at a time
      */
-    if (!dbuf_put(&cptr->recvQ, readbuf, length))
-      return exit_client(cptr, cptr, &me, "dbuf_put fail");
-
-#ifndef NOFLOODCONTROL
-    if (IsUser(cptr) && DBufLength(&cptr->recvQ) > CLIENT_FLOOD)
-      return exit_client(cptr, cptr, &me, "Excess Flood");
-#endif
+    if (poll_fds[i].revents) {
+      if (IsAuthConnect(auth))
+        send_auth_query(auth);
+      else
+        read_auth_reply(auth);
+      if (0 == --nfds)
+        break;
+    }
+  }
+  /*
+   * check listeners
+   */
+  for (listener = ListenerPollList; listener; listener = listener->next) {
+    i = listener->index;
+    if (poll_fds[i].revents) {
+      accept_connection(listener);
+      if (0 == --nfds)
+        break;
+    }
+  }
+  /*
+   * i contains the next non-auth/non-listener index, since we put the
+   * resolver, auth and listener, file descriptors in poll_fds first,
+   * the very next one should be the start of the clients
+   */
+  pfd = &poll_fds[++i];
 
-    while (DBufLength(&cptr->recvQ) && !NoNewLine(cptr)
-#ifndef NOFLOODCONTROL
-       && (IsTrusted(cptr) || cptr->since - now < 10)
-#endif
-       )
-    {
-      /*
-       * If it has become registered as a Server
-       * then skip the per-message parsing below.
-       */
-      if (IsServer(cptr))
-      {
-       /*
-        * XXX - this blindly deletes data if no cr/lf is received at
-        * the end of a lot of messages and the data stored in the 
-        * dbuf is greater than sizeof(readbuf)
-        */
-       dolen = dbuf_get(&cptr->recvQ, readbuf, sizeof(readbuf));
-       if (0 == dolen)
-         break;
-       if ((done = dopacket(cptr, readbuf, dolen)))
-         return done;
-       break;
+  for ( ; (i < pfd_count); ++i, ++pfd) {
+    if (!(cptr = LocalClientArray[pfd->fd]))
+      continue;
+    read_ready = write_ready = 0;
+
+    if (0 < nfds && pfd->revents) {
+      --nfds;
+    
+      read_ready  = pfd->revents & POLLREADFLAGS;
+      write_ready = pfd->revents & POLLWRITEFLAGS;
+
+      if (pfd->revents & POLLERRORS) {
+        if (pfd->events & POLLREADFLAGS)
+          ++read_ready;
+        if (pfd->events & POLLWRITEFLAGS)
+          ++write_ready;
       }
-      dolen = dbuf_getmsg(&cptr->recvQ, cptr->buffer, BUFSIZE);
-      /*
-       * Devious looking...whats it do ? well..if a client
-       * sends a *long* message without any CR or LF, then
-       * dbuf_getmsg fails and we pull it out using this
-       * loop which just gets the next 512 bytes and then
-       * deletes the rest of the buffer contents.
-       * -avalon
-       */
-      if (0 == dolen)
-      {
-       if (DBufLength(&cptr->recvQ) < 510)
-       {
-         cptr->flags |= FLAGS_NONL;
-         break;
-       }
-       DBufClear(&cptr->recvQ);
-       break;
+    }
+    if (write_ready) {
+      if (!on_write_unblocked(cptr) || IsDead(cptr)) {
+        exit_client(cptr, cptr, &me,
+                    cptr->error ? strerror(cptr->error) : LastDeadComment(cptr));
+        continue;
       }
-      else if (CPTR_KILLED == client_dopacket(cptr, dolen))
-       return CPTR_KILLED;
     }
+    length = 1;                 /* for fall through case */
+    if ((!NoNewLine(cptr) || read_ready) && !IsDead(cptr)) {
+      if (CPTR_KILLED == (length = read_packet(cptr, read_ready)))
+        continue;
+    }
+#if 0
+    /* Bullshit, why would we want to flush sockets while using non-blocking?
+     * This uses > 4% cpu! --Run */
+    if (length > 0)
+      flush_connections(poll_cptr[i]);
+#endif
+    if (IsDead(cptr)) {
+      exit_client(cptr, cptr, &me,
+         cptr->error ? strerror(cptr->error) : LastDeadComment(cptr));
+      continue;
+    }
+    if (length > 0)
+      continue;
+    cptr->flags |= FLAGS_DEADSOCKET;
+    /*
+     * ...hmm, with non-blocking sockets we might get
+     * here from quite valid reasons, although.. why
+     * would select report "data available" when there
+     * wasn't... So, this must be an error anyway...  --msa
+     * actually, EOF occurs when read() returns 0 and
+     * in due course, select() returns that fd as ready
+     * for reading even though it ends up being an EOF. -avalon
+     */
+    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", pfd->fd, errno, length));
+
+    if ((IsServer(cptr) || IsHandshake(cptr)) && cptr->error == 0 && length == 0)
+      exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
+                      cptr->name, cptr->serv->last_error_msg);
+    else
+      exit_client_msg(cptr, cptr, &me, "Read error to %s: %s",
+                      get_client_name(cptr, HIDE_IP), 
+                      (cptr->error) ?  strerror(cptr->error) : "EOF from client");
   }
-  return 1;
+  return 0;
 }
+#else /* USE_SELECT */
 
 /*
  * Check all connections for new connections and input data that is to be
@@ -1600,358 +1045,146 @@ static int read_packet(aClient *cptr, fd_setp_t rfd)
  */
 int read_message(time_t delay)
 {
-  Reg1 aClient *cptr;
-  Reg2 int nfds;
-  struct timeval wait;
-#ifdef pyr
-  struct timeval nowt;
-  unsigned long us;
-#endif
-  time_t delay2 = delay;
-  unsigned long usec = 0;
-  int res, length, fd, i;
-  int auth = 0, ping = 0;
-#ifndef USE_POLL
-  fd_set read_set, write_set;
-#else /* USE_POLL */
-  unsigned int currfd_index = 0;
-  unsigned int udpfdindex = 0;
-  unsigned int resfdindex = 0;
-  unsigned long timeout;
-  int added;
-#endif /* USE_POLL */
-
-#ifdef pyr
-  gettimeofday(&nowt, NULL);
-  now = nowt.tv_sec;
-#endif
-
-  for (res = 0;;)
+  struct Client*   cptr;
+  struct Listener* listener;
+  int              nfds;
+  struct timeval   wait;
+  time_t           delay2 = delay;
+  unsigned long    usec = 0;
+  int              res = 0;
+  int              length;
+  int              i;
+  struct AuthRequest* auth = 0;
+  struct AuthRequest* auth_next = 0;
+  int              read_ready;
+  fd_set           read_set;
+  fd_set           write_set;
+
+  for ( ; ; )
   {
-#ifndef USE_POLL
     FD_ZERO(&read_set);
     FD_ZERO(&write_set);
-#endif /* not USE_POLL */
-    for (i = highest_fd; i >= 0; i--)
-    {
-#ifdef USE_POLL
-      added = FALSE;
-#endif /* USE_POLL */
-      if (!(cptr = loc_clients[i]))
-       continue;
-      if (IsLog(cptr))
-       continue;
-      if (DoingAuth(cptr))
-      {
-       auth++;
-       Debug((DEBUG_NOTICE, "auth on %p %d", cptr, i));
-       RFD_SET(cptr->authfd, &read_set, currfd_index, cptr);
-       if (cptr->flags & FLAGS_WRAUTH)
-         RWFD_SET(cptr->authfd, &write_set, currfd_index);
-      }
-      if (IsPing(cptr))
-      {
-       ping++;
-       Debug((DEBUG_NOTICE, "open ping on %p %d", cptr, i));
-       if (!cptr->firsttime || now <= cptr->firsttime)
-       {
-         RFD_SET(i, &read_set, currfd_index, cptr);
-         delay2 = 1;
-         if (DoPing(cptr) && now > cptr->lasttime)
-           RWFD_SET(i, &write_set, currfd_index);
-       }
-       else
-       {
-         del_queries((char *)cptr);
-         end_ping(cptr);
-       }
-#ifdef USE_POLL
-       if (added)
-         currfd_index++;
-#endif /* USE_POLL */
-       continue;
-      }
-      if (DoingDNS(cptr) || DoingAuth(cptr))
-      {
-#ifdef USE_POLL
-       if (added)
-         currfd_index++;
-#endif /* USE_POLL */
-       continue;
-      }
-      if (IsMe(cptr) && IsListening(cptr))
-       RFD_SET(i, &read_set, currfd_index, cptr);
-      else if (!IsMe(cptr))
-      {
-       if (DBufLength(&cptr->recvQ) && delay2 > 2)
-         delay2 = 1;
-       if (DBufLength(&cptr->recvQ) < 4088)
-         RFD_SET(i, &read_set, currfd_index, cptr);
-       if (DBufLength(&cptr->sendQ) || IsConnecting(cptr) ||
-           (cptr->listing && DBufLength(&cptr->sendQ) < 2048))
-#ifndef pyr
-         WFD_SET(i, &write_set, currfd_index, cptr);
-#else /* pyr */
-       {
-         if (!(cptr->flags & FLAGS_BLOCKED))
-           WFD_SET(i, &write_set, currfd_index, cptr);
-         else
-           delay2 = 0, usec = 500000;
-       }
-       if (now - cptr->lw.tv_sec && nowt.tv_usec - cptr->lw.tv_usec < 0)
-         us = 1000000;
-       else
-         us = 0;
-       us += nowt.tv_usec;
-       if (us - cptr->lw.tv_usec > 500000)
-         cptr->flags &= ~FLAGS_BLOCKED;
-#endif /* pyr */
-      }
-#ifdef USE_POLL
-      if (added)
-       currfd_index++;
-#endif /* USE_POLL */
+
+    if (-1 < ResolverFileDescriptor)
+      FD_SET(ResolverFileDescriptor, &read_set);
+    /*
+     * set auth file descriptors
+     */
+    for (auth = AuthPollList; auth; auth = auth->next) {
+      assert(-1 < auth->fd);
+      if (IsAuthConnect(auth))
+        FD_SET(auth->fd, &write_set);
+      else /* if (IsAuthPending(auth)) */
+        FD_SET(auth->fd, &read_set);
     }
-
-    if (udpfd >= 0)
-    {
-      RFD_SET(udpfd, &read_set, currfd_index, NULL);
-#ifdef USE_POLL
-      udpfdindex = currfd_index;
-      currfd_index++;
-#endif /* USE_POLL */
+    /*
+     * set listener file descriptors
+     */
+    for (listener = ListenerPollList; listener; listener = listener->next) {
+      assert(-1 < listener->fd);
+      FD_SET(listener->fd, &read_set);
     }
-    if (resfd >= 0)
-    {
-      RFD_SET(resfd, &read_set, currfd_index, NULL);
-#ifdef USE_POLL
-      resfdindex = currfd_index;
-      currfd_index++;
-#endif /* USE_POLL */
+
+    for (i = HighestFd; i > -1; --i) {
+      if ((cptr = LocalClientArray[i])) {
+        if (DBufLength(&cptr->recvQ))
+          delay2 = 1;
+        if (DBufLength(&cptr->recvQ) < 4088 || IsServer(cptr))
+          FD_SET(i, &read_set);
+        if (DBufLength(&cptr->sendQ) || IsConnecting(cptr) ||
+            (cptr->listing && DBufLength(&cptr->sendQ) < 2048))
+          FD_SET(i, &write_set);
+      }
     }
 
-    wait.tv_sec = MIN(delay2, delay);
+    wait.tv_sec = IRCD_MIN(delay2, delay);
     wait.tv_usec = usec;
-#ifndef USE_POLL
-#ifdef HPUX
-    nfds = select(FD_SETSIZE, (int *)&read_set, (int *)&write_set, 0, &wait);
-#else
+
+    Debug((DEBUG_INFO, "select: %d %d", delay, delay2));
+
     nfds = select(FD_SETSIZE, &read_set, &write_set, 0, &wait);
-#endif
-#else /* USE_POLL */
-    timeout = (wait.tv_sec * 1000) + (wait.tv_usec / 1000);
-    nfds = poll(poll_fds, currfd_index, timeout);
-#endif /* USE_POLL */
-    now = time(NULL);
-    if (nfds == -1 && errno == EINTR)
-      return -1;
-    else if (nfds >= 0)
+
+    CurrentTime = time(0);
+
+    if (-1 < nfds)
       break;
-    report_error("select %s: %s", &me);
-    res++;
-    if (res > 5)
-      restart("too many select errors");
-    sleep(10);
-    now += 10;
+
+    if (errno == EINTR)
+      return -1;
+    report_error(SELECT_ERROR_MSG, me.name, errno);
+    if (++res > 5)
+      server_restart("too many select errors");
+    sleep(1);
+    CurrentTime = time(0);
   }
 
-  if (udpfd >= 0 && RFD_ISSET(udpfd, &read_set, udpfdindex))
-  {
-    polludp();
-    nfds--;
-    RFD_CLR_OUT(udpfd, &read_set, udpfdindex);
+  if (-1 < ResolverFileDescriptor && 
+      FD_ISSET(ResolverFileDescriptor, &read_set)) {
+    resolver_read();
+    --nfds;
   }
   /*
-   * Check fd sets for the ping fd's (if set and valid!) first
+   * Check fd sets for the auth fd's (if set and valid!) first
    * because these can not be processed using the normal loops below.
-   * And we want them to be as fast as possible.
-   * -Run
+   * -avalon
    */
-  for (i = HIGHEST_INDEX; (ping > 0) && (i >= 0); i--)
-  {
-    if (!(cptr = LOC_CLIENTS(i)))
-      continue;
-    if (!IsPing(cptr))
-      continue;
-    ping--;
-    if ((nfds > 0) && RFD_ISSET(cptr->fd, &read_set, i))
-    {
-      nfds--;
-      RFD_CLR_OUT(cptr->fd, &read_set, i);
-      read_ping(cptr);         /* This can RunFree(cptr) ! */
+  for (auth = AuthPollList; auth; auth = auth_next) {
+    auth_next = auth->next;
+    assert(-1 < auth->fd);
+    if (IsAuthConnect(auth) && FD_ISSET(auth->fd, &write_set)) {
+      send_auth_query(auth);
+      if (0 == --nfds)
+        break;
     }
-    else if ((nfds > 0) && WFD_ISSET(cptr->fd, &write_set, i))
-    {
-      nfds--;
-      cptr->lasttime = now;
-      WFD_CLR_OUT(cptr->fd, &write_set, i);
-      send_ping(cptr);         /* This can RunFree(cptr) ! */
+    else if (FD_ISSET(auth->fd, &read_set)) {
+      read_auth_reply(auth);
+      if (0 == --nfds)
+        break;
     }
   }
-  if (resfd >= 0 && RFD_ISSET(resfd, &read_set, resfdindex))
-  {
-    do_dns_async();
-    nfds--;
-    RFD_CLR_OUT(resfd, &read_set, resfdindex);
-  }
   /*
-   * Check fd sets for the auth fd's (if set and valid!) first
-   * because these can not be processed using the normal loops below.
-   * -avalon
+   * next accept connections from active listeners
    */
-  for (i = HIGHEST_INDEX; (auth > 0) && (i >= 0); i--)
-  {
-    if (!(cptr = LOC_CLIENTS(i)))
-      continue;
-    if (cptr->authfd < 0)
+  for (listener = ListenerPollList; listener; listener = listener->next) {
+    assert(-1 < listener->fd);
+    if (0 < nfds && FD_ISSET(listener->fd, &read_set))
+      accept_connection(listener);
+  } 
+
+  for (i = HighestFd; -1 < i; --i) {
+    if (!(cptr = LocalClientArray[i]))
       continue;
-    auth--;
-    if ((nfds > 0) && WFD_ISSET(cptr->authfd, &write_set, i))
-    {
-      nfds--;
-      send_authports(cptr);
-    }
-    else if ((nfds > 0) && RFD_ISSET(cptr->authfd, &read_set, i))
-    {
-      nfds--;
-      read_authports(cptr);
-    }
-  }
-  for (i = HIGHEST_INDEX; i >= 0; i--)
-    if ((cptr = LOC_CLIENTS(i)) && RFD_ISSET(i, &read_set, i) &&
-       IsListening(cptr))
-    {
-      RFD_CLR_OUT(i, &read_set, i);
-      nfds--;
-      cptr->lasttime = now;
-      /*
-       * There may be many reasons for error return, but
-       * in otherwise correctly working environment the
-       * probable cause is running out of file descriptors
-       * (EMFILE, ENFILE or others?). The man pages for
-       * accept don't seem to list these as possible,
-       * although it's obvious that it may happen here.
-       * Thus no specific errors are tested at this
-       * point, just assume that connections cannot
-       * be accepted until some old is closed first.
-       */
-      if ((fd = accept(LOC_FD(i), NULL, NULL)) < 0)
-      {
-       if (errno != EWOULDBLOCK)
-         report_error("accept() failed%s: %s", NULL);
-       break;
-      }
-#if defined(USE_SYSLOG) && defined(SYSLOG_CONNECTS)
-      {                                /* get an early log of all connections   --dl */
-       static struct sockaddr_in peer;
-       static int len;
-       len = sizeof(peer);
-       getpeername(fd, (struct sockaddr *)&peer, &len);
-       syslog(LOG_DEBUG, "Conn: %s", inetntoa(peer.sin_addr));
-      }
-#endif
-      ircstp->is_ac++;
-      if (fd >= MAXCLIENTS)
-      {
-       /* Don't send more messages then one every 10 minutes */
-       static int count;
-       static time_t last_time;
-       ircstp->is_ref++;
-       ++count;
-       if (last_time < now - (time_t) 600)
-       {
-         if (count > 0)
-         {
-           if (!last_time)
-             last_time = me.since;
-           sendto_ops
-               ("All connections in use!  Had to refuse %d clients in the last "
-               STIME_T_FMT " minutes", count, (now - last_time) / 60);
-         }
-         else
-           sendto_ops("All connections in use. (%s)", cptr->name);
-         count = 0;
-         last_time = now;
-       }
-       send(fd, "ERROR :All connections in use\r\n", 32, 0);
-       close(fd);
-       break;
+    read_ready = 0;
+    if (0 < nfds) {
+      if (FD_ISSET(i, &write_set)) {
+        --nfds;
+        if (!on_write_unblocked(cptr) || IsDead(cptr)) {
+          if (FD_ISSET(i, &read_set))
+            --nfds;
+          exit_client(cptr, cptr, &me,
+                      cptr->error ? strerror(cptr->error) : LastDeadComment(cptr));
+          continue;
+        }
       }
-      /*
-       * Use of add_connection (which never fails :) meLazy
-       */
-#ifdef UNIXPORT
-      if (IsUnixSocket(cptr))
-       add_unixconnection(cptr, fd);
-      else
-#endif
-      if (!add_connection(cptr, fd, ADCON_SOCKET))
-       continue;
-      nextping = now;
-      if (!cptr->acpt)
-       cptr->acpt = &me;
+      if ((read_ready = FD_ISSET(i, &read_set)))
+        --nfds;
     }
-
-  for (i = HIGHEST_INDEX; i >= 0; i--)
-  {
-    if (!(cptr = LOC_CLIENTS(i)) || IsMe(cptr))
-      continue;
-#ifdef USE_POLL
-    if (DoingDNS(cptr) || DoingAuth(cptr) || !(cptr = loc_clients[LOC_FD(i)]))
-      continue;
-#endif /* USE_POLL */
-#ifdef DEBUGMODE
-    if (IsLog(cptr))
-      continue;
-#endif
-    if (WFD_ISSET(i, &write_set, i))
-    {
-      int write_err = 0;
-      nfds--;
-      /*
-       *  ...room for writing, empty some queue then...
-       */
-      cptr->flags &= ~FLAGS_BLOCKED;
-      if (IsConnecting(cptr))
-       write_err = completed_connection(cptr);
-      if (!write_err)
-      {
-       if (cptr->listing && DBufLength(&cptr->sendQ) < 2048)
-         list_next_channels(cptr, 64);
-       send_queued(cptr);
-      }
-      if (IsDead(cptr) || write_err)
-      {
-      deadsocket:
-       if (RFD_ISSET(i, &read_set, i))
-       {
-         nfds--;
-         RFD_CLR_OUT(i, &read_set, i);
-       }
-       exit_client(cptr, cptr, &me,
-           IsDead(cptr) ? LastDeadComment(cptr) : strerror(get_sockerr(cptr)));
-       continue;
-      }
+    length = 1;                 /* for fall through case */
+    if ((!NoNewLine(cptr) || read_ready) && !IsDead(cptr)) {
+      if (CPTR_KILLED == (length = read_packet(cptr, read_ready)))
+        continue;
     }
-    length = 1;                        /* for fall through case */
-    if ((!NoNewLine(cptr) || RFD_ISSET(i, &read_set, i)) && !IsDead(cptr))
-#ifndef USE_POLL
-      length = read_packet(cptr, &read_set);
-#else /* USE_POLL */
-      length = read_packet(cptr, i);
-#endif /* USE_POLL */
 #if 0
     /* Bullshit, why would we want to flush sockets while using non-blocking?
      * This uses > 4% cpu! --Run */
     if (length > 0)
-      flush_connections(LOC_FD(i));
+      flush_connections(LocalClientArray[i]);
 #endif
-    if ((length != CPTR_KILLED) && IsDead(cptr))
-      goto deadsocket;
-    if (!RFD_ISSET(i, &read_set, i) && length > 0)
+    if (IsDead(cptr)) {
+      exit_client(cptr, cptr, &me,
+              cptr->error ? strerror(cptr->error) : LastDeadComment(cptr));
       continue;
-    nfds--;
-    readcalls++;
+    }
     if (length > 0)
       continue;
 
@@ -1964,587 +1197,200 @@ int read_message(time_t delay)
      * in due course, select() returns that fd as ready
      * for reading even though it ends up being an EOF. -avalon
      */
-    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", LOC_FD(i), errno, length));
+    Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", i, cptr->error, length));
 
-    if (length == CPTR_KILLED)
-      continue;
-
-    if ((IsServer(cptr) || IsHandshake(cptr)) && errno == 0 && length == 0)
+    if ((IsServer(cptr) || IsHandshake(cptr)) && cptr->error == 0 && length == 0)
       exit_client_msg(cptr, cptr, &me, "Server %s closed the connection (%s)",
-         cptr->name, cptr->serv->last_error_msg);
+                      cptr->name, cptr->serv->last_error_msg);
     else
       exit_client_msg(cptr, cptr, &me, "Read error to %s: %s",
-         get_client_name(cptr, FALSE), (length < 0) ?
-         strerror(get_sockerr(cptr)) : "EOF from client");
+                      get_client_name(cptr, HIDE_IP),
+                      cptr->error ? strerror(cptr->error) : "EOF from client");
   }
   return 0;
 }
 
+#endif /* USE_SELECT */
+
 /*
- * connect_server
+ * connect_server - start or complete a connection to another server
+ * returns true (1) if successful, false (0) otherwise
+ *
+ * aconf must point to a valid C:line
+ * m_connect            calls this with a valid by client and a null reply
+ * try_connections      calls this with a null by client, and a null reply
+ * connect_dns_callback call this with a null by client, and a valid reply
+ *
+ * XXX - if this comes from an m_connect message and a dns query needs to
+ * be done, we loose the information about who started the connection and
+ * it's considered an auto connect.
  */
-int connect_server(aConfItem *aconf, aClient *by, struct hostent *hp)
+int connect_server(struct ConfItem* aconf, struct Client* by,
+                   struct DNSReply* reply)
 {
-  Reg1 struct sockaddr *svp;
-  Reg2 aClient *cptr, *c2ptr;
-  Reg3 char *s;
-  int errtmp, len;
+  struct Client*   cptr = 0;
+  assert(0 != aconf);
 
-  Debug((DEBUG_NOTICE, "Connect to %s[%s] @%s",
-      aconf->name, aconf->host, inetntoa(aconf->ipnum)));
+  if (aconf->dns_pending) {
+    sendto_ops("Server %s connect DNS pending");
+    return 0;
+  }
+  Debug((DEBUG_NOTICE, "Connect to %s[@%s]", aconf->name,
+         ircd_ntoa((const char*) &aconf->ipnum)));
 
-  if ((c2ptr = FindClient(aconf->name)))
-  {
-    if (IsServer(c2ptr) || IsMe(c2ptr))
-    {
-      sendto_ops("Server %s already present from %s",
-         aconf->name, c2ptr->from->name);
-      if (by && IsUser(by) && !MyUser(by))
-      {
-#ifndef NO_PROTOCOL9
-       if (Protocol(by->from) < 10)
-         sendto_one(by, ":%s NOTICE %s :Server %s already present from %s",
-             me.name, by->name, aconf->name, c2ptr->from->name);
-       else
-#endif
-         sendto_one(by, "%s NOTICE %s%s :Server %s already present from %s",
-             NumServ(&me), NumNick(by), aconf->name, c2ptr->from->name);
+  if ((cptr = FindClient(aconf->name))) {
+    if (IsServer(cptr) || IsMe(cptr)) {
+      sendto_ops("Server %s already present from %s", 
+                 aconf->name, cptr->from->name);
+      if (by && IsUser(by) && !MyUser(by)) {
+        sendto_one(by, "%s NOTICE %s%s :Server %s already present from %s",
+                     NumServ(&me), NumNick(by), aconf->name, cptr->from->name);
       }
-      return -1;
+      return 0;
     }
-    else if (IsHandshake(c2ptr) || IsConnecting(c2ptr))
-    {
-      if (by && IsUser(by))
-      {
-       if (MyUser(by) || Protocol(by->from) < 10)
-         sendto_one(by, ":%s NOTICE %s :Connection to %s already in progress",
-             me.name, by->name, c2ptr->name);
-       else
-         sendto_one(by,
-             "%s NOTICE %s%s :Connection to %s already in progress",
-             NumServ(&me), NumNick(by), c2ptr->name);
+    else if (IsHandshake(cptr) || IsConnecting(cptr)) {
+      if (by && IsUser(by)) {
+        if (MyUser(by))
+          sendto_one(by, ":%s NOTICE %s :Connection to %s already in progress",
+                     me.name, by->name, cptr->name);
+        else
+          sendto_one(by, "%s NOTICE %s%s :Connection to %s already in progress",
+                     NumServ(&me), NumNick(by), cptr->name);
       }
-      return -1;
+      return 0;
     }
   }
-
   /*
    * If we dont know the IP# for this host and itis a hostname and
    * not a ip# string, then try and find the appropriate host record.
    */
-  if ((!aconf->ipnum.s_addr)
-#ifdef UNIXPORT
-      && ((aconf->host[2]) != '/')     /* needed for Unix domain -- dl */
-#endif
-      )
-  {
-    Link lin;
-
-    lin.flags = ASYNC_CONNECT;
-    lin.value.aconf = aconf;
-    nextdnscheck = 1;
-    s = strchr(aconf->host, '@');
-    s++;                       /* should NEVER be NULL */
-    if ((aconf->ipnum.s_addr = inet_addr(s)) == INADDR_NONE)
-    {
-      aconf->ipnum.s_addr = INADDR_ANY;
-      hp = gethost_byname(s, &lin);
-      Debug((DEBUG_NOTICE, "co_sv: hp %p ac %p na %s ho %s",
-         hp, aconf, aconf->name, s));
-      if (!hp)
-       return 0;
-      memcpy(&aconf->ipnum, hp->h_addr, sizeof(struct in_addr));
+  if (INADDR_NONE == aconf->ipnum.s_addr) {
+    char buf[HOSTLEN + 1];
+    assert(0 == reply);
+    if (INADDR_NONE == (aconf->ipnum.s_addr = inet_addr(aconf->host))) {
+      struct DNSQuery  query;
+
+      query.vptr     = aconf;
+      query.callback = connect_dns_callback;
+      host_from_uh(buf, aconf->host, HOSTLEN);
+      buf[HOSTLEN] = '\0';
+
+      reply = gethost_byname(buf, &query);
+
+      if (!reply) {
+        aconf->dns_pending = 1;
+        return 0;
+      }
+      memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr));
     }
   }
-  cptr = make_client(NULL, STAT_UNKNOWN);
-  cptr->hostp = hp;
+  cptr = make_client(NULL, STAT_UNKNOWN_SERVER);
+  if (reply)
+    ++reply->ref_count;
+  cptr->dns_reply = reply;
+
   /*
    * Copy these in so we have something for error detection.
    */
-  strncpy(cptr->name, aconf->name, sizeof(cptr->name) - 1);
-  cptr->name[sizeof(cptr->name) - 1] = 0;
-  strncpy(cptr->sockhost, aconf->host, HOSTLEN);
-  cptr->sockhost[HOSTLEN] = 0;
-
-#ifdef UNIXPORT
-  if (aconf->host[2] == '/')   /* (/ starts a 2), Unix domain -- dl */
-    svp = connect_unix(aconf, cptr, &len);
-  else
-    svp = connect_inet(aconf, cptr, &len);
-#else
-  svp = connect_inet(aconf, cptr, &len);
-#endif
+  ircd_strncpy(cptr->name, aconf->name, HOSTLEN);
+  ircd_strncpy(cptr->sockhost, aconf->host, HOSTLEN);
 
-  if (!svp)
-  {
-    if (cptr->fd >= 0)
-      close(cptr->fd);
-    cptr->fd = -2;
-    if (by && IsUser(by) && !MyUser(by))
-    {
-#ifndef NO_PROTOCOL9
-      if (Protocol(by->from) < 10)
-       sendto_one(by, ":%s NOTICE %s :Couldn't connect to %s",
-           me.name, by->name, cptr->name);
-      else
-#endif
-       sendto_one(by, "%s NOTICE %s%s :Couldn't connect to %s",
-           NumServ(&me), NumNick(by), cptr->name);
-    }
-    free_client(cptr);
-    return -1;
-  }
+  /*
+   * Attach config entries to client here rather than in
+   * completed_connection. This to avoid null pointer references
+   */
+  attach_confs_byhost(cptr, aconf->host, CONF_SERVER);
 
-  set_non_blocking(cptr->fd, cptr);
-  set_sock_opts(cptr->fd, cptr);
-  signal(SIGALRM, dummy);
-  alarm(4);
-  if (connect(cptr->fd, svp, len) < 0 && errno != EINPROGRESS)
-  {
-    int err = get_sockerr(cptr);
-    errtmp = errno;            /* other system calls may eat errno */
-    alarm(0);
-    report_error("Connect to host %s failed: %s", cptr);
-    if (by && IsUser(by) && !MyUser(by))
-    {
-#ifndef NO_PROTOCOL9
-      if (Protocol(by->from) < 10)
-       sendto_one(by, ":%s NOTICE %s :Connect to host %s failed: %s",
-           me.name, by->name, cptr->name, strerror(err));
-      else
-#endif
-       sendto_one(by, "%s NOTICE %s%s :Connect to host %s failed: %s",
-           NumServ(&me), NumNick(by), cptr->name, strerror(err));
+  if (!find_conf_byhost(cptr->confs, aconf->host, CONF_SERVER)) {
+    sendto_ops("Host %s is not enabled for connecting: no C-line", aconf->name);
+    if (by && IsUser(by) && !MyUser(by)) {
+      sendto_one(by, "%s NOTICE %s%s :Connect to host %s failed: no C-line",
+                 NumServ(&me), NumNick(by), aconf->name);
     }
-    close(cptr->fd);
-    cptr->fd = -2;
+    det_confs_butmask(cptr, 0);
     free_client(cptr);
-    errno = errtmp;
-    if (errno == EINTR)
-      errno = ETIMEDOUT;
-    return -1;
+    return 0;
   }
-  alarm(0);
-
   /*
-   * Attach config entries to client here rather than in
-   * completed_connection. This to avoid null pointer references
-   * when name returned by gethostbyaddr matches no C lines
-   * (could happen in 2.6.1a when host and servername differ).
-   * No need to check access and do gethostbyaddr calls.
-   * There must at least be one as we got here C line...  meLazy
+   * attempt to connect to the server in the conf line
    */
-  attach_confs_host(cptr, aconf->host,
-      CONF_NOCONNECT_SERVER | CONF_CONNECT_SERVER);
-
-  if (!find_conf_host(cptr->confs, aconf->host, CONF_NOCONNECT_SERVER) ||
-      !find_conf_host(cptr->confs, aconf->host, CONF_CONNECT_SERVER))
-  {
-    sendto_ops("Host %s is not enabled for connecting:no C/N-line",
-              aconf->name);
-    if (by && IsUser(by) && !MyUser(by))
-    {
-#ifndef NO_PROTOCOL9
-      if (Protocol(by->from) < 10)
-       sendto_one(by,
-           ":%s NOTICE %s :Connect to host %s failed: no C/N-lines",
-           me.name, by->name, cptr->name);
-      else
-#endif
-       sendto_one(by,
-           "%s NOTICE %s%s :Connect to host %s failed: no C/N-lines",
-           NumServ(&me), NumNick(by), cptr->name);
+  if (!connect_inet(aconf, cptr)) {
+    if (by && IsUser(by) && !MyUser(by)) {
+      sendto_one(by, "%s NOTICE %s%s :Couldn't connect to %s",
+                 NumServ(&me), NumNick(by), cptr->name);
     }
     det_confs_butmask(cptr, 0);
-    close(cptr->fd);
-    cptr->fd = -2;
     free_client(cptr);
-    return (-1);
+    return 0;
   }
   /*
+   * NOTE: if we're here we have a valid C:Line and the client should
+   * have started the connection and stored the remote address/port and
+   * ip address name in itself
+   *
    * The socket has been connected or connect is in progress.
    */
   make_server(cptr);
-  if (by && IsUser(by))
-  {
+  if (by && IsUser(by)) {
     sprintf_irc(cptr->serv->by, "%s%s", NumNick(by));
-    if (cptr->serv->user)
-      free_user(cptr->serv->user, NULL);
+    assert(0 == cptr->serv->user);
     cptr->serv->user = by->user;
     by->user->refcnt++;
   }
-  else
-  {
+  else {
     *cptr->serv->by = '\0';
-    if (cptr->serv->user)
-      free_user(cptr->serv->user, NULL);
-    cptr->serv->user = NULL;
+    /* strcpy(cptr->serv->by, "Auto"); */
   }
   cptr->serv->up = &me;
-  if (cptr->fd > highest_fd)
-    highest_fd = cptr->fd;
-  loc_clients[cptr->fd] = cptr;
-  cptr->acpt = &me;
   SetConnecting(cptr);
 
-  get_sockhost(cptr, aconf->host);
-  Count_newunknown(nrof);
+  if (cptr->fd > HighestFd)
+    HighestFd = cptr->fd;
+  LocalClientArray[cptr->fd] = cptr;
+
+  Count_newunknown(UserStats);
   add_client_to_list(cptr);
   hAddClient(cptr);
-  nextping = now;
-
-  return 0;
-}
-
-static struct sockaddr *connect_inet(aConfItem *aconf, aClient *cptr, int *lenp)
-{
-  static struct sockaddr_in server;
-  Reg3 struct hostent *hp;
+  nextping = CurrentTime;
 
-  /*
-   * Might as well get sockhost from here, the connection is attempted
-   * with it so if it fails its useless.
-   */
-  alarm(2);
-  cptr->fd = socket(AF_INET, SOCK_STREAM, 0);
-  alarm(0);
-  if (cptr->fd == -1 && errno == EAGAIN)
-  {
-    sendto_ops("opening stream socket to server %s: No more sockets",
-       cptr->name);
-    return NULL;
-  }
-  if (cptr->fd == -1)
-  {
-    report_error("opening stream socket to server %s: %s", cptr);
-    return NULL;
-  }
-  if (cptr->fd >= MAXCLIENTS)
-  {
-    sendto_ops("No more connections allowed (%s)", cptr->name);
-    return NULL;
-  }
-  mysk.sin_port = 0;
-
-  memset(&server, 0, sizeof(server));
-  server.sin_family = AF_INET;
-  get_sockhost(cptr, aconf->host);
-
-#ifdef VIRTUAL_HOST
-  mysk.sin_addr = vserv.sin_addr;
-#endif
-
-  /*
-   * Bind to a local IP# (with unknown port - let unix decide) so
-   * we have some chance of knowing the IP# that gets used for a host
-   * with more than one IP#.
-   */
-  /* No we don't bind it, not all OS's can handle connecting with
-   * an already bound socket, different ip# might occur anyway
-   * leading to a freezing select() on this side for some time.
-   * I had this on my Linux 1.1.88 --Run
-   */
-#ifdef VIRTUAL_HOST
-  /*
-   * No, we do bind it if we have virtual host support. If we don't
-   * explicitly bind it, it will default to IN_ADDR_ANY and we lose
-   * due to the other server not allowing our base IP --smg
-   */
-  if (bind(cptr->fd, (struct sockaddr *)&mysk, sizeof(mysk)) == -1)
-  {
-    report_error("error binding to local port for %s: %s", cptr);
-    return NULL;
-  }
-#endif
-
-  /*
-   * By this point we should know the IP# of the host listed in the
-   * conf line, whether as a result of the hostname lookup or the ip#
-   * being present instead. If we dont know it, then the connect fails.
-   */
-  if (isDigit(*aconf->host) && (aconf->ipnum.s_addr == INADDR_NONE))
-    aconf->ipnum.s_addr = inet_addr(aconf->host);
-  if (aconf->ipnum.s_addr == INADDR_NONE)
-  {
-    hp = cptr->hostp;
-    if (!hp)
-    {
-      Debug((DEBUG_FATAL, "%s: unknown host", aconf->host));
-      return NULL;
-    }
-    memcpy(&aconf->ipnum, hp->h_addr, sizeof(struct in_addr));
-  }
-  memcpy(&server.sin_addr, &aconf->ipnum, sizeof(struct in_addr));
-  memcpy(&cptr->ip, &aconf->ipnum, sizeof(struct in_addr));
-#ifdef TESTNET
-  server.sin_port = htons(((aconf->port > 0) ? aconf->port : portnum) + 10000);
-#else
-  server.sin_port = htons(((aconf->port > 0) ? aconf->port : portnum));
-#endif
-  *lenp = sizeof(server);
-  return (struct sockaddr *)&server;
+  return 1;
 }
 
-#ifdef UNIXPORT
 /*
- * connect_unix
- *
- * Build a socket structure for cptr so that it can connet to the unix
- * socket defined by the conf structure aconf.
+ * Setup local socket structure to use for binding to.
  */
-static struct sockaddr *connect_unix(aConfItem *aconf, aClient *cptr, int *lenp)
+void init_virtual_host(const struct ConfItem* conf)
 {
-  static struct sockaddr_un sock;
-
-  alarm(2);
-  cptr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
-  alarm(0);
-  if (cptr->fd == -1 && errno == EAGAIN)
-  {
-    sendto_ops("Unix domain connect to host %s failed: No more sockets",
-       cptr->name);
-    return NULL;
-  }
-  if (cptr->fd == -1)
-  {
-    report_error("Unix domain connect to host %s failed: %s", cptr);
-    return NULL;
-  }
-  else if (cptr->fd >= MAXCLIENTS)
-  {
-    sendto_ops("No more connections allowed (%s)", cptr->name);
-    return NULL;
-  }
+  assert(0 != conf);
 
-  get_sockhost(cptr, aconf->host);
-  /* +2 needed for working Unix domain -- dl */
-  strncpy(sock.sun_path, aconf->host + 2, sizeof(sock.sun_path) - 1);
-  sock.sun_path[sizeof(sock.sun_path) - 1] = 0;
-  sock.sun_family = AF_UNIX;
-  *lenp = strlen(sock.sun_path) + 2;
+  memset(&virtualHost, 0, sizeof(virtualHost));
+  virtualHost.sin_family = AF_INET;
+  virtualHost.sin_addr.s_addr = INADDR_ANY;
 
-  SetUnixSock(cptr);
-  return (struct sockaddr *)&sock;
-}
+  if (EmptyString(conf->passwd) || 0 == strcmp(conf->passwd, "*"))
+    return;
+  virtualHost.sin_addr.s_addr = inet_addr(conf->passwd);
 
-#endif
+  if (INADDR_NONE == virtualHost.sin_addr.s_addr)
+    virtualHost.sin_addr.s_addr = INADDR_ANY;
+}  
 
 /*
  * Find the real hostname for the host running the server (or one which
  * matches the server's name) and its primary IP#.  Hostname is stored
  * in the client structure passed as a pointer.
  */
-void get_my_name(aClient *cptr)
-{
-  struct ConfItem* aconf = find_me();
-  /*
-   * Setup local socket structure to use for binding to.
-   */
-  memset(&mysk, 0, sizeof(mysk));
-  mysk.sin_family = AF_INET;
-  mysk.sin_addr.s_addr = INADDR_ANY; 
-
-  if (!aconf || BadPtr(aconf->host))
-    return;
-  strncpy(me.name, aconf->host, sizeof(me.name) - 1);
-
-  if (!BadPtr(aconf->passwd) && 0 != strcmp(aconf->passwd, "*")) {
-    mysk.sin_addr.s_addr = inet_addr(aconf->passwd);
-    if (INADDR_NONE == mysk.sin_addr.s_addr)
-      mysk.sin_addr.s_addr = INADDR_ANY;
-#ifdef VIRTUAL_HOST
-    memcpy(&vserv, &mysk, sizeof(struct sockaddr_in));
-#endif
-  }
-  Debug((DEBUG_DEBUG, "local name is %s", get_client_name(&me, TRUE)));
-}
-
-/*
- * Setup a UDP socket and listen for incoming packets
- */
-int setup_ping(void)
-{
-  struct sockaddr_in from;
-  int on = 1;
-
-  memset(&from, 0, sizeof(from));
-#ifdef VIRTUAL_HOST
-  from.sin_addr = vserv.sin_addr;
-#else
-  from.sin_addr.s_addr = htonl(INADDR_ANY);
-#endif
-#ifdef TESTNET
-  from.sin_port = htons(atoi(UDP_PORT) + 10000);
-#else
-  from.sin_port = htons(atoi(UDP_PORT));
-#endif
-  from.sin_family = AF_INET;
-
-  if ((udpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-  {
-    Debug((DEBUG_ERROR, "socket udp : %s", strerror(errno)));
-    return -1;
-  }
-  if (setsockopt(udpfd, SOL_SOCKET, SO_REUSEADDR,
-      (OPT_TYPE *)&on, sizeof(on)) == -1)
-  {
-#ifdef USE_SYSLOG
-    syslog(LOG_ERR, "setsockopt udp fd %d : %m", udpfd);
-#endif
-    Debug((DEBUG_ERROR, "setsockopt so_reuseaddr : %s", strerror(errno)));
-    close(udpfd);
-    udpfd = -1;
-    return -1;
-  }
-  on = 0;
-  setsockopt(udpfd, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on));
-  if (bind(udpfd, (struct sockaddr *)&from, sizeof(from)) == -1)
-  {
-#ifdef USE_SYSLOG
-    syslog(LOG_ERR, "bind udp.%d fd %d : %m", from.sin_port, udpfd);
-#endif
-    Debug((DEBUG_ERROR, "bind : %s", strerror(errno)));
-    close(udpfd);
-    udpfd = -1;
-    return -1;
-  }
-  if (fcntl(udpfd, F_SETFL, FNDELAY) == -1)
-  {
-    Debug((DEBUG_ERROR, "fcntl fndelay : %s", strerror(errno)));
-    close(udpfd);
-    udpfd = -1;
-    return -1;
-  }
-  return udpfd;
-}
-
-/*
- * max # of pings set to 15/sec.
- */
-static void polludp(void)
+int init_server_identity()
 {
-  Reg1 char *s;
-  struct sockaddr_in from;
-  int n;
-  size_t fromlen = sizeof(from);
-  static time_t last = 0;
-  static int cnt = 0, mlen = 0;
-
-  /*
-   * find max length of data area of packet.
-   */
-  if (!mlen)
-  {
-    mlen = sizeof(readbuf) - strlen(me.name) - strlen(version);
-    mlen -= 6;
-    if (mlen < 0)
-      mlen = 0;
-  }
-  Debug((DEBUG_DEBUG, "udp poll"));
+  struct ConfItem* conf = find_me();
 
-  n = recvfrom(udpfd, readbuf, mlen, 0, (struct sockaddr *)&from, &fromlen);
-  if (now == last)
-    if (++cnt > 14)
-      return;
-  cnt = 0;
-  last = now;
+  if (!conf || EmptyString(conf->host))
+    return 0;
 
-  if (n == -1)
-  {
-    if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
-      return;
-    else
-    {
-      report_error("udp port recvfrom (%s): %s", &me);
-      return;
-    }
-  }
-  ircstp->is_udp++;
-  if (n < 19)
-    return;
+  ircd_strncpy(me.name, conf->host, HOSTLEN);
 
-  s = readbuf + n;
-  /*
-   * attach my name and version for the reply
-   */
-  *readbuf |= 1;
-  strcpy(s, me.name);
-  s += strlen(s) + 1;
-  strcpy(s, version);
-  s += strlen(s);
-  sendto(udpfd, readbuf, s - readbuf, 0,
-      (struct sockaddr *)&from, sizeof(from));
-  return;
+  init_virtual_host(conf);
+  return 1;
 }
 
-/*
- * do_dns_async
- *
- * Called when the fd returned from init_resolver() has been selected for
- * reading.
- */
-static void do_dns_async(void)
-{
-  static Link ln;
-  aClient *cptr;
-  aConfItem *aconf;
-  struct hostent *hp;
-
-  ln.flags = ASYNC_NONE;
-  hp = get_res((char *)&ln);
 
-  Debug((DEBUG_DNS, "%p = get_res(%d,%p)", hp, ln.flags, ln.value.cptr));
-
-  switch (ln.flags)
-  {
-    case ASYNC_NONE:
-      /*
-       * No reply was processed that was outstanding or had a client
-       * still waiting.
-       */
-      break;
-    case ASYNC_CLIENT:
-      if ((cptr = ln.value.cptr))
-      {
-       del_queries((char *)cptr);
-       ClearDNS(cptr);
-       if (!DoingAuth(cptr))
-         SetAccess(cptr);
-       cptr->hostp = hp;
-      }
-      break;
-    case ASYNC_CONNECT:
-      aconf = ln.value.aconf;
-      if (hp && aconf)
-      {
-       memcpy(&aconf->ipnum, hp->h_addr, sizeof(struct in_addr));
-       connect_server(aconf, NULL, hp);
-      }
-      else
-       sendto_ops("Connect to %s failed: host lookup",
-           (aconf) ? aconf->host : "unknown");
-      break;
-    case ASYNC_PING:
-      cptr = ln.value.cptr;
-      del_queries((char *)cptr);
-      if (hp)
-      {
-       memcpy(&cptr->ip, hp->h_addr, sizeof(struct in_addr));
-       if (ping_server(cptr) == -1)
-         end_ping(cptr);
-      }
-      else
-      {
-       sendto_ops("Udp ping to %s failed: host lookup", cptr->sockhost);
-       end_ping(cptr);
-      }
-      break;
-    case ASYNC_CONF:
-      aconf = ln.value.aconf;
-      if (hp && aconf)
-       memcpy(&aconf->ipnum, hp->h_addr, sizeof(struct in_addr));
-      break;
-    default:
-      break;
-  }
-}
index 05da98d91375036aacfefca511e2a92a8e02b86c..b0547819c4cc22fa4aa0bcbffd1470be8e050076 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
+#include "s_conf.h"
 
+#include "IPcheck.h"
+#include "class.h"
+#include "client.h"
+#include "crule.h"
+#include "fileio.h"
+#include "gline.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "listener.h"
+#include "match.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "opercmds.h"
+#include "parse.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "send.h"
+#include "sprintf_irc.h"
+#include "struct.h"
+#include "support.h"
 #include "sys.h"
-#include <sys/socket.h>
-#if HAVE_FCNTL_H
+
+#include <assert.h>
+#include <arpa/inet.h>
+#include <errno.h>
 #include <fcntl.h>
-#endif
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-#if HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
 #endif
 
-#include <sys/stat.h>
-#ifdef R_LINES
-#include <signal.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
+struct ConfItem* GlobalConfList  = 0;
+int              GlobalConfCount = 0;
+struct MotdItem* motd = NULL;
+struct MotdItem* rmotd = NULL;
+struct TRecord*  tdata = NULL;
+struct tm        motd_tm;
+
+
+/*
+ *  is the K line field an interval or a comment? - Mmmm
+ */
+static int is_comment(const char *comment)
+{
+  size_t i;
+  size_t len = strlen(comment);
+  for (i = 0; i < len; ++i) {
+    if (!IsKTimeChar(comment[i]))
+      return 1;
+  }
+  return 0;
+}
+
+/*
+ *  check against a set of time intervals
+ */
+static int check_time_interval(char *interval, char *reply)
+{
+  struct tm* tptr;
+  char*      p;
+  int        perm_min_hours;
+  int        perm_min_minutes;
+  int        perm_max_hours;
+  int        perm_max_minutes;
+  int        nowm;
+  int        perm_min;
+  int        perm_max;
+
+  tptr = localtime(&CurrentTime);
+  nowm = tptr->tm_hour * 60 + tptr->tm_min;
+
+  while (interval) {
+    p = strchr(interval, ',');
+    if (p)
+      *p = '\0';
+    if (sscanf(interval, "%2d%2d-%2d%2d", &perm_min_hours, &perm_min_minutes,
+               &perm_max_hours, &perm_max_minutes) != 4)
+    {
+      if (p)
+        *p = ',';
+      return 0;
+    }
+    if (p)
+      *(p++) = ',';
+    perm_min = 60 * perm_min_hours + perm_min_minutes;
+    perm_max = 60 * perm_max_hours + perm_max_minutes;
+    /*
+     * The following check allows intervals over midnight ...
+     */
+    if ((perm_min < perm_max)
+        ? (perm_min <= nowm && nowm <= perm_max)
+        : (perm_min <= nowm || nowm <= perm_max))
+    {
+      sprintf_irc(reply, ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
+                  "You are not allowed to connect from",
+                  perm_min_hours, perm_min_minutes,
+                  perm_max_hours, perm_max_minutes);
+      return (ERR_YOUREBANNEDCREEP);
+    }
+    if ((perm_min < perm_max)
+        ? (perm_min <= nowm + 5 && nowm + 5 <= perm_max)
+        : (perm_min <= nowm + 5 || nowm + 5 <= perm_max))
+    {
+      sprintf_irc(reply, ":%%s %%d %%s :%d minute%s%s",
+                  perm_min - nowm, (perm_min - nowm) > 1 ? "s " : " ",
+                  "and you will be denied for further access");
+      return (ERR_YOUWILLBEBANNED);
+    }
+    interval = p;
+  }
+  return 0;
+}
+
+/*
+ * output the reason for being k lined from a file  - Mmmm
+ * sptr is server
+ * parv is the sender prefix
+ * filename is the file that is to be output to the K lined client
+ */
+static void killcomment(struct Client *sptr, char *parv, char *filename)
+{
+  FBFILE*     file = NULL;
+  char        line[80];
+  char*       tmp;
+  struct stat sb;
+  struct tm*  tm;
+
+  if (NULL == (file = fbopen(filename, "r"))) {
+    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
+    sendto_one(sptr,
+        ":%s %d %s :Connection from your host is refused on this server.",
+        me.name, ERR_YOUREBANNEDCREEP, parv);
+    return;
+  }
+  fbstat(&sb, file);
+  tm = localtime((time_t*) &sb.st_mtime);        /* NetBSD needs cast */
+  while (fbgets(line, sizeof(line) - 1, file)) {
+    if ((tmp = strchr(line, '\n')))
+      *tmp = '\0';
+    if ((tmp = strchr(line, '\r')))
+      *tmp = '\0';
+    /* sendto_one(sptr,
+     * ":%s %d %s : %s.",
+     * me.name, ERR_YOUREBANNEDCREEP, parv,line); */
+    sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line);
+  }
+  sendto_one(sptr,
+      ":%s %d %s :Connection from your host is refused on this server.",
+      me.name, ERR_YOUREBANNEDCREEP, parv);
+  fbclose(file);
+}
+
+struct ConfItem* make_conf(void)
+{
+  struct ConfItem* aconf;
+
+  aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem));
+  assert(0 != aconf);
+#ifdef        DEBUGMODE
+  ++GlobalConfCount;
 #endif
-#include <stdlib.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#ifdef USE_SYSLOG
-#include <syslog.h>
+  aconf->status       = CONF_ILLEGAL;
+  aconf->clients      = 0;
+  aconf->ipnum.s_addr = INADDR_NONE;
+  aconf->host         = 0;
+  aconf->passwd       = 0;
+  aconf->name         = 0;
+  aconf->port         = 0;
+  aconf->hold         = 0;
+  aconf->dns_pending  = 0;
+  aconf->confClass    = 0;
+  aconf->next         = 0;
+  return aconf;
+}
+
+void delist_conf(struct ConfItem *aconf)
+{
+  if (aconf == GlobalConfList)
+    GlobalConfList = GlobalConfList->next;
+  else {
+    struct ConfItem *bconf;
+
+    for (bconf = GlobalConfList; aconf != bconf->next; bconf = bconf->next)
+      ;
+    bconf->next = aconf->next;
+  }
+  aconf->next = NULL;
+}
+
+void free_conf(struct ConfItem *aconf)
+{
+  Debug((DEBUG_DEBUG, "free_conf: %s %s %d",
+         aconf->host ? aconf->host : "*",
+         aconf->name ? aconf->name : "*",
+         aconf->port));
+  if (aconf->dns_pending)
+    delete_resolver_queries(aconf);
+  MyFree(aconf->host);
+  if (aconf->passwd)
+    memset(aconf->passwd, 0, strlen(aconf->passwd));
+  MyFree(aconf->passwd);
+  MyFree(aconf->name);
+  MyFree(aconf);
+#ifdef        DEBUGMODE
+  --GlobalConfCount;
 #endif
-#include "h.h"
-#include "struct.h"
-#include "s_serv.h"
-#include "opercmds.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_conf.h"
-#include "class.h"
-#include "s_misc.h"
-#include "match.h"
-#include "common.h"
-#include "s_err.h"
-#include "s_bsd.h"
-#include "ircd.h"
-#include "crule.h"
-#include "res.h"
-#include "support.h"
-#include "parse.h"
-#include "numnicks.h"
-#include "sprintf_irc.h"
-#include "IPcheck.h"
-#include "hash.h"
-#include "fileio.h"
+}
 
-RCSTAG_CC("$Id$");
+/*
+ * conf_dns_callback - called when resolver query finishes
+ * if the query resulted in a successful search, hp will contain
+ * a non-null pointer, otherwise hp will be null.
+ * if successful save hp in the conf item it was called with
+ */
+static void conf_dns_callback(void* vptr, struct DNSReply* reply)
+{
+  struct ConfItem* aconf = (struct ConfItem*) vptr;
+  aconf->dns_pending = 0;
+  if (reply)
+    memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr));
+}
 
-static int check_time_interval(char *, char *);
-static int lookup_confhost(aConfItem *);
-static int is_comment(char *);
-static void killcomment(aClient *sptr, char *parv, char *filename);
+/*
+ * conf_dns_lookup - do a nameserver lookup of the conf host
+ * if the conf entry is currently doing a ns lookup do nothing, otherwise
+ * if the lookup returns a null pointer, set the conf dns_pending flag
+ */
+static struct DNSReply* conf_dns_lookup(struct ConfItem* aconf)
+{
+  struct DNSReply* dns_reply = 0;
+  if (!aconf->dns_pending) {
+    char            buf[HOSTLEN + 1];
+    struct DNSQuery query;
+    query.vptr     = aconf;
+    query.callback = conf_dns_callback;
+    host_from_uh(buf, aconf->host, HOSTLEN);
+    buf[HOSTLEN] = '\0';
+
+    if (0 == (dns_reply = gethost_byname(buf, &query)))
+      aconf->dns_pending = 1;
+  }
+  return dns_reply;
+}
+
+
+/*
+ * lookup_confhost
+ *
+ * Do (start) DNS lookups of all hostnames in the conf line and convert
+ * an IP addresses in a.b.c.d number for to IP#s.
+ */
+static void lookup_confhost(struct ConfItem *aconf)
+{
+  struct DNSReply* reply;
+
+  if (EmptyString(aconf->host) || EmptyString(aconf->name)) {
+    Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+           aconf->host, aconf->name));
+    return;
+  }
+  /*
+   * Do name lookup now on hostnames given and store the
+   * ip numbers in conf structure.
+   */
+  if (IsDigit(*aconf->host)) {
+    /*
+     * rfc 1035 sez host names may not start with a digit
+     */
+    aconf->ipnum.s_addr = inet_addr(aconf->host);
+    if (INADDR_NONE == aconf->ipnum.s_addr) {
+      Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
+            aconf->host, aconf->name));
+    }
+  }
+  else if ((reply = conf_dns_lookup(aconf)))
+    memcpy(&aconf->ipnum, reply->hp->h_addr, sizeof(struct in_addr));
+}
+
+/*
+ * conf_find_server - find a server by name or hostname
+ * returns a server conf item pointer if found, 0 otherwise
+ *
+ * NOTE: at some point when we don't have to scan the entire
+ * list it may be cheaper to look for server names and host
+ * names in separate loops (original code did it that way)
+ */
+struct ConfItem* conf_find_server(const char* name)
+{
+  struct ConfItem* conf;
+  assert(0 != name);
+
+  for (conf = GlobalConfList; conf; conf = conf->next) {
+    if (CONF_SERVER == conf->status) {
+      /*
+       * Check first servernames, then try hostnames.
+       * XXX - match returns 0 if there _is_ a match... guess they
+       * haven't decided what true is yet
+       */
+      if (0 == match(name, conf->name))
+        return conf;
+    }
+  }
+  return 0;
+}
+
+/*
+ * conf_eval_crule - evaluate connection rules
+ * returns the name of the rule triggered if found, 0 otherwise
+ *
+ * Evaluate connection rules...  If no rules found, allow the
+ * connect.   Otherwise stop with the first true rule (ie: rules
+ * are ored together.  Oper connects are effected only by D
+ * lines (CRULEALL) not d lines (CRULEAUTO).
+ */
+const char* conf_eval_crule(struct ConfItem* conf)
+{
+  struct ConfItem* rule;
+  assert(0 != conf);
+
+  for (rule = GlobalConfList; rule; rule = rule->next) {
+    if ((CONF_CRULEALL == rule->status) && (0 == match(rule->host, conf->name))) {
+      if (crule_eval(rule->passwd))
+        return rule->name;
+    }
+  }
+  return 0;
+}
 
-aConfItem *conf = NULL;
-aGline *gline = NULL;
-aGline *badchan = NULL;
-aMotdItem *motd = NULL;
-aMotdItem *rmotd = NULL;
-atrecord *tdata = NULL;
-struct tm motd_tm;
 
 /*
  * field breakup for ircd.conf file.
  */
-static char *gfline = NULL;
-char *getfield(char *newline, char fs)
+static char* getfield(char* newline, char fs)
 {
-  char *end, *field;
+  static char* gfline = NULL;
+  char*        end;
+  char*        field;
 
   if (newline)
     gfline = newline;
@@ -103,29 +380,23 @@ char *getfield(char *newline, char fs)
 
   end = field = gfline;
 
-  if (fs != ':')
-  {
+  if (fs != ':') {
     if (*end == fs)
       ++end;
     else
       fs = ':';
   }
-  do
-  {
-    while (*end != fs)
-    {
-      if (!*end)
-      {
-       end = NULL;
-       break;
+  do {
+    while (*end != fs) {
+      if (!*end) {
+        end = NULL;
+        break;
       }
       ++end;
     }
-  }
-  while (end && fs != ':' && *++end != ':' && *end != '\n');
+  } while (end && fs != ':' && *++end != ':' && *end != '\n') ;
 
-  if (end == NULL)
-  {
+  if (end == NULL) {
     gfline = NULL;
     if ((end = strchr(field, '\n')) == NULL)
       end = field + strlen(field);
@@ -142,12 +413,11 @@ char *getfield(char *newline, char fs)
  * Remove all conf entries from the client except those which match
  * the status field mask.
  */
-void det_confs_butmask(aClient *cptr, int mask)
+void det_confs_butmask(struct Client *cptr, int mask)
 {
-  Reg1 Link *tmp, *tmp2;
+  struct SLink *tmp, *tmp2;
 
-  for (tmp = cptr->confs; tmp; tmp = tmp2)
-  {
+  for (tmp = cptr->confs; tmp; tmp = tmp2) {
     tmp2 = tmp->next;
     if ((tmp->value.aconf->status & mask) == 0)
       detach_conf(cptr, tmp->value.aconf);
@@ -155,192 +425,184 @@ void det_confs_butmask(aClient *cptr, int mask)
 }
 
 /*
- * Find the first (best) I line to attach.
+ * validate_hostent - make sure hostnames are valid in a hostent struct
+ * XXX - this is terrible, what's worse is it used to be in the inner
+ * loop of scanning all the I:lines --Bleep
  */
-enum AuthorizationCheckResult attach_Iline(aClient *cptr, struct hostent *hp,
-    char *sockhost)
+static int validate_hostent(struct hostent* hp)
 {
-  Reg1 aConfItem *aconf;
-  Reg3 const char *hname;
-  Reg4 int i;
-  static char uhost[HOSTLEN + USERLEN + 3];
-  static char fullname[HOSTLEN + 1];
+  char        fullname[HOSTLEN + 1];
+  int         i     = 0;
+  int         error = 0;
+  const char* hname;
 
-  for (aconf = conf; aconf; aconf = aconf->next)
-  {
+  for (hname = hp->h_name; hname; hname = hp->h_aliases[i++]) {
+    size_t fullnamelen = 0;
+    size_t label_count = 0;
+
+    ircd_strncpy(fullname, hname, HOSTLEN);
+    fullname[HOSTLEN] = '\0';
+    /*
+     * Disallow a hostname label to contain anything but a [-a-zA-Z0-9].
+     * It may not start or end on a '.'.
+     * A label may not end on a '-', the maximum length of a label is
+     * 63 characters.
+     * On top of that (which seems to be the RFC) we demand that the
+     * top domain does not contain any digits.
+     */
+    error = (*hname == '.') ? 1 : 0;        /* May not start with a '.' */
+    if (!error) {
+      char *p;
+      for (p = fullname; *p; ++p, ++fullnamelen) {
+        if (*p == '.') { 
+          /* Label may not end on '-' and May not end on a '.' */
+          if (p[-1] == '-' || p[1] == 0) {
+            error = 1;
+            break;
+          }
+          label_count = 0;
+          error = 0;        /* Was not top domain */
+          continue;
+        }
+        if (++label_count > 63) {
+          /* Label not longer then 63 */
+          error = 1;
+          break;
+        }
+        if (*p >= '0' && *p <= '9') {
+          /* In case this is top domain */
+          error = 1;
+          continue;
+        }
+        if (!(*p >= 'a' && *p <= 'z')
+            && !(*p >= 'A' && *p <= 'Z') && *p != '-') {
+          error = 1;
+          break;
+        }
+      }
+    }
+    if (error)
+      break;
+  }
+  return (0 == error);
+}
+
+/*
+ * check_limit_and_attach - check client limits and attach I:line
+ */
+static int check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf)
+{
+  if (aconf->passwd) {
+    /* Special case: exactly one digit */
+    if (IsDigit(*aconf->passwd) && !aconf->passwd[1]) {
+      /*
+       * Refuse connections when there are already <digit>
+       * clients connected with the same IP number
+       */
+      unsigned short nr = *aconf->passwd - '0';
+      if (IPcheck_nr(cptr) > nr)
+        return ACR_TOO_MANY_FROM_IP; /* Already got nr with that ip# */
+    }
+#ifdef USEONE
+    else if (0 == strcmp(aconf->passwd, "ONE")) {
+      int i;
+      for (i = HighestFd; i > -1; --i) {
+        if (LocalClientArray[i] && MyUser(LocalClientArray[i]) &&
+            LocalClientArray[i]->ip.s_addr == cptr->ip.s_addr)
+          return ACR_TOO_MANY_FROM_IP; /* Already got one with that ip# */
+      }
+    }
+#endif
+  }
+  return attach_conf(cptr, aconf);
+}
+
+/*
+ * Find the first (best) I line to attach.
+ */
+int attach_iline(struct Client*  cptr)
+{
+  struct ConfItem* aconf;
+  const char*      hname;
+  int              i;
+  static char      uhost[HOSTLEN + USERLEN + 3];
+  static char      fullname[HOSTLEN + 1];
+  struct hostent*  hp = 0;
+
+  if (cptr->dns_reply) {
+    hp = cptr->dns_reply->hp;
+    if (!validate_hostent(hp))
+      hp = 0;
+  }
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
     if (aconf->status != CONF_CLIENT)
       continue;
-    if (aconf->port && aconf->port != cptr->acpt->port)
+    if (aconf->port && aconf->port != cptr->listener->port)
       continue;
     if (!aconf->host || !aconf->name)
       continue;
-    if (hp)
-      for (i = 0, hname = hp->h_name; hname; hname = hp->h_aliases[i++])
-      {
-       size_t fullnamelen = 0;
-       size_t label_count = 0;
-       int error;
-
-       strncpy(fullname, hname, HOSTLEN);
-       fullname[HOSTLEN] = 0;
-
-       /*
-        * Disallow a hostname label to contain anything but a [-a-zA-Z0-9].
-        * It may not start or end on a '.'.
-        * A label may not end on a '-', the maximum length of a label is
-        * 63 characters.
-        * On top of that (which seems to be the RFC) we demand that the
-        * top domain does not contain any digits.
-        */
-       error = (*hname == '.') ? 1 : 0;        /* May not start with a '.' */
-       if (!error)
-       {
-         char *p;
-         for (p = fullname; *p; ++p, ++fullnamelen)
-         {
-           if (*p == '.')
-           {
-             if (p[-1] == '-'  /* Label may not end on '-' */
-                 || p[1] == 0) /* May not end on a '.' */
-             {
-               error = 1;
-               break;
-             }
-             label_count = 0;
-             error = 0;        /* Was not top domain */
-             continue;
-           }
-           if (++label_count > 63)     /* Label not longer then 63 */
-           {
-             error = 1;
-             break;
-           }
-           if (*p >= '0' && *p <= '9')
-           {
-             error = 1;        /* In case this is top domain */
-             continue;
-           }
-           if (!(*p >= 'a' && *p <= 'z')
-               && !(*p >= 'A' && *p <= 'Z') && *p != '-')
-           {
-             error = 1;
-             break;
-           }
-         }
-       }
-       if (error)
-       {
-         hp = NULL;
-         break;
-       }
-
-       add_local_domain(fullname, HOSTLEN - fullnamelen);
-       Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
-       if (strchr(aconf->name, '@'))
-       {
-         strcpy(uhost, cptr->username);
-         strcat(uhost, "@");
-       }
-       else
-         *uhost = '\0';
-       strncat(uhost, fullname, sizeof(uhost) - 1 - strlen(uhost));
-       uhost[sizeof(uhost) - 1] = 0;
-       if (!match(aconf->name, uhost))
-       {
-         if (strchr(uhost, '@'))
-           cptr->flags |= FLAGS_DOID;
-         goto attach_iline;
-       }
+    if (hp) {
+      for (i = 0, hname = hp->h_name; hname; hname = hp->h_aliases[i++]) {
+        ircd_strncpy(fullname, hname, HOSTLEN);
+        fullname[HOSTLEN] = '\0';
+
+        Debug((DEBUG_DNS, "a_il: %s->%s", cptr->sockhost, fullname));
+
+        if (strchr(aconf->name, '@')) {
+          strcpy(uhost, cptr->username);
+          strcat(uhost, "@");
+        }
+        else
+          *uhost = '\0';
+        strncat(uhost, fullname, sizeof(uhost) - 1 - strlen(uhost));
+        uhost[sizeof(uhost) - 1] = 0;
+        if (0 == match(aconf->name, uhost)) {
+          if (strchr(uhost, '@'))
+            cptr->flags |= FLAGS_DOID;
+          return check_limit_and_attach(cptr, aconf);
+        }
       }
-
-    if (strchr(aconf->host, '@'))
-    {
-      strncpy(uhost, cptr->username, sizeof(uhost) - 2);
+    }
+    if (strchr(aconf->host, '@')) {
+      ircd_strncpy(uhost, cptr->username, sizeof(uhost) - 2);
       uhost[sizeof(uhost) - 2] = 0;
       strcat(uhost, "@");
     }
     else
       *uhost = '\0';
-    strncat(uhost, sockhost, sizeof(uhost) - 1 - strlen(uhost));
+    strncat(uhost, cptr->sock_ip, sizeof(uhost) - 1 - strlen(uhost));
     uhost[sizeof(uhost) - 1] = 0;
     if (match(aconf->host, uhost))
       continue;
     if (strchr(uhost, '@'))
       cptr->flags |= FLAGS_DOID;
-    if (hp && hp->h_name)
-    {
-      strncpy(uhost, hp->h_name, HOSTLEN);
-      uhost[HOSTLEN] = 0;
-      add_local_domain(uhost, HOSTLEN - strlen(uhost));
-    }
-  attach_iline:
-    get_sockhost(cptr, uhost);
 
-    if (aconf->passwd)
-    {
-      if (isDigit(*aconf->passwd) && !aconf->passwd[1])        /* Special case: exactly one digit */
-      {
-       /* Refuse connections when there are already <digit> clients connected with the same IP number */
-       unsigned short nr = *aconf->passwd - '0';
-       if (IPcheck_nr(cptr) > nr)
-         return ACR_TOO_MANY_FROM_IP;  /* Already got nr with that ip# */
-      }
-#ifdef USEONE
-      else if (!strcmp(aconf->passwd, "ONE"))
-      {
-       for (i = highest_fd; i >= 0; i--)
-         if (loc_clients[i] && MyUser(loc_clients[i]) &&
-             loc_clients[i]->ip.s_addr == cptr->ip.s_addr)
-           return ACR_TOO_MANY_FROM_IP;        /* Already got one with that ip# */
-      }
-#endif
-    }
-    return attach_conf(cptr, aconf);
+    return check_limit_and_attach(cptr, aconf);
   }
   return ACR_NO_AUTHORIZATION;
 }
 
 /*
- * Find the single N line and return pointer to it (from list).
- * If more than one then return NULL pointer.
+ * detach_conf - Disassociate configuration from the client.
  */
-aConfItem *count_cnlines(Link *lp)
+int detach_conf(struct Client *cptr, struct ConfItem *aconf)
 {
-  Reg1 aConfItem *aconf, *cline = NULL, *nline = NULL;
+  struct SLink** lp;
+  struct SLink*  tmp;
 
-  for (; lp; lp = lp->next)
-  {
-    aconf = lp->value.aconf;
-    if (!(aconf->status & CONF_SERVER_MASK))
-      continue;
-    if (aconf->status == CONF_CONNECT_SERVER && !cline)
-      cline = aconf;
-    else if (aconf->status == CONF_NOCONNECT_SERVER && !nline)
-      nline = aconf;
-  }
-  return nline;
-}
-
-/*
- * detach_conf
- *
- * Disassociate configuration from the client.
- */
-int detach_conf(aClient *cptr, aConfItem *aconf)
-{
-  Reg1 Link **lp, *tmp;
+  assert(0 != aconf);
+  assert(0 != cptr);
+  assert(0 < aconf->clients);
 
   lp = &(cptr->confs);
 
-  while (*lp)
-  {
-    if ((*lp)->value.aconf == aconf)
-    {
-      if (aconf && (aconf->confClass)
-         && (aconf->status & CONF_CLIENT_MASK) && ConfLinks(aconf) > 0)
-       --ConfLinks(aconf);
-      if (aconf && !--aconf->clients && IsIllegal(aconf))
-       free_conf(aconf);
+  while (*lp) {
+    if ((*lp)->value.aconf == aconf) {
+      if (aconf->confClass && (aconf->status & CONF_CLIENT_MASK) && 
+          ConfLinks(aconf) > 0)
+        --ConfLinks(aconf);
+      if (0 == --aconf->clients && IsIllegal(aconf))
+        free_conf(aconf);
       tmp = *lp;
       *lp = tmp->next;
       free_link(tmp);
@@ -352,9 +614,9 @@ int detach_conf(aClient *cptr, aConfItem *aconf)
   return -1;
 }
 
-static int is_attached(aConfItem *aconf, aClient *cptr)
+static int is_attached(struct ConfItem *aconf, struct Client *cptr)
 {
-  Reg1 Link *lp;
+  struct SLink *lp;
 
   for (lp = cptr->confs; lp; lp = lp->next)
     if (lp->value.aconf == aconf)
@@ -371,9 +633,9 @@ static int is_attached(aConfItem *aconf, aClient *cptr)
  * connection). Note, that this automaticly changes the
  * attachment if there was an old one...
  */
-enum AuthorizationCheckResult attach_conf(aClient *cptr, aConfItem *aconf)
+int attach_conf(struct Client *cptr, struct ConfItem *aconf)
 {
-  Reg1 Link *lp;
+  struct SLink *lp;
 
   if (is_attached(aconf, cptr))
     return ACR_ALREADY_AUTHORIZED;
@@ -381,119 +643,113 @@ enum AuthorizationCheckResult attach_conf(aClient *cptr, aConfItem *aconf)
     return ACR_NO_AUTHORIZATION;
   if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) &&
       ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
-    return ACR_TOO_MANY_IN_CLASS;      /* Use this for printing error message */
+    return ACR_TOO_MANY_IN_CLASS;  /* Use this for printing error message */
   lp = make_link();
   lp->next = cptr->confs;
   lp->value.aconf = aconf;
   cptr->confs = lp;
-  aconf->clients++;
+  ++aconf->clients;
   if (aconf->status & CONF_CLIENT_MASK)
     ConfLinks(aconf)++;
   return ACR_OK;
 }
 
-aConfItem *find_admin(void)
+struct ConfItem *find_admin(void)
 {
-  Reg1 aConfItem *aconf;
+  struct ConfItem *aconf;
 
-  for (aconf = conf; aconf; aconf = aconf->next)
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
     if (aconf->status & CONF_ADMIN)
       break;
-
-  return (aconf);
+  }
+  return aconf;
 }
 
-aConfItem *find_me(void)
+struct ConfItem* find_me(void)
 {
-  Reg1 aConfItem *aconf;
-  for (aconf = conf; aconf; aconf = aconf->next)
+  struct ConfItem* aconf;
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next) {
     if (aconf->status & CONF_ME)
       break;
-
-  return (aconf);
+  }
+  return aconf;
 }
 
 /*
- * attach_confs
+ * attach_confs_byname
  *
  * Attach a CONF line to a client if the name passed matches that for
  * the conf file (for non-C/N lines) or is an exact match (C/N lines
  * only).  The difference in behaviour is to stop C:*::* and N:*::*.
  */
-aConfItem *attach_confs(aClient *cptr, const char *name, int statmask)
+struct ConfItem* attach_confs_byname(struct Client* cptr, const char* name,
+                                     int statmask)
 {
-  Reg1 aConfItem *tmp;
-  aConfItem *first = NULL;
-  int len = strlen(name);
+  struct ConfItem* tmp;
+  struct ConfItem* first = NULL;
 
-  if (!name || len > HOSTLEN)
-    return NULL;
-  for (tmp = conf; tmp; tmp = tmp->next)
-  {
-    if ((tmp->status & statmask) && !IsIllegal(tmp) &&
-       ((tmp->status & (CONF_SERVER_MASK | CONF_HUB)) == 0) &&
-       tmp->name && !match(tmp->name, name))
-    {
-      if (attach_conf(cptr, tmp) == ACR_OK && !first)
-       first = tmp;
-    }
-    else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
-       (tmp->status & (CONF_SERVER_MASK | CONF_HUB)) &&
-       tmp->name && !strCasediff(tmp->name, name))
-    {
-      if (attach_conf(cptr, tmp) == ACR_OK && !first)
-       first = tmp;
+  assert(0 != name);
+
+  if (HOSTLEN < strlen(name))
+    return 0;
+
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
+    if (0 != (tmp->status & statmask) && !IsIllegal(tmp)) {
+      assert(0 != tmp->name);
+      if (0 == match(tmp->name, name) || 0 == ircd_strcmp(tmp->name, name)) { 
+        if (ACR_OK == attach_conf(cptr, tmp) && !first)
+          first = tmp;
+      }
     }
   }
-  return (first);
+  return first;
 }
 
 /*
  * Added for new access check    meLazy
  */
-aConfItem *attach_confs_host(aClient *cptr, char *host, int statmask)
+struct ConfItem* attach_confs_byhost(struct Client* cptr, const char* host,
+                                     int statmask)
 {
-  Reg1 aConfItem *tmp;
-  aConfItem *first = NULL;
-  int len = strlen(host);
+  struct ConfItem* tmp;
+  struct ConfItem* first = 0;
 
-  if (!host || len > HOSTLEN)
-    return NULL;
+  assert(0 != host);
+  if (HOSTLEN < strlen(host))
+    return 0;
 
-  for (tmp = conf; tmp; tmp = tmp->next)
-  {
-    if ((tmp->status & statmask) && !IsIllegal(tmp) &&
-       (tmp->status & CONF_SERVER_MASK) == 0 &&
-       (!tmp->host || match(tmp->host, host) == 0))
-    {
-      if (attach_conf(cptr, tmp) == ACR_OK && !first)
-       first = tmp;
-    }
-    else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
-       (tmp->status & CONF_SERVER_MASK) &&
-       (tmp->host && strCasediff(tmp->host, host) == 0))
-    {
-      if (attach_conf(cptr, tmp) == ACR_OK && !first)
-       first = tmp;
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
+    if (0 != (tmp->status & statmask) && !IsIllegal(tmp)) {
+      assert(0 != tmp->host);
+      if (0 == match(tmp->host, host) || 0 == ircd_strcmp(tmp->host, host)) { 
+        if (ACR_OK == attach_conf(cptr, tmp) && !first)
+          first = tmp;
+      }
     }
   }
-  return (first);
+  return first;
 }
 
 /*
  * find a conf entry which matches the hostname and has the same name.
  */
-aConfItem *find_conf_exact(char *name, char *user, char *host, int statmask)
+struct ConfItem* find_conf_exact(const char* name, const char* user,
+                                 const char* host, int statmask)
 {
-  Reg1 aConfItem *tmp;
+  struct ConfItem *tmp;
   char userhost[USERLEN + HOSTLEN + 3];
 
-  sprintf_irc(userhost, "%s@%s", user, host);
+  /*
+   * XXX - buffer overflow possible, unchecked variables
+   */
+  if (user)
+    sprintf_irc(userhost, "%s@%s", user, host);
+  else
+    ircd_strncpy(userhost, host, sizeof(userhost) - 1);
 
-  for (tmp = conf; tmp; tmp = tmp->next)
-  {
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
     if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
-       strCasediff(tmp->name, name))
+        0 != ircd_strcmp(tmp->name, name))
       continue;
     /*
      * Accept if the *real* hostname (usually sockecthost)
@@ -502,59 +758,59 @@ aConfItem *find_conf_exact(char *name, char *user, char *host, int statmask)
      */
     if (match(tmp->host, userhost))
       continue;
-    if (tmp->status & (CONF_OPERATOR | CONF_LOCOP))
-    {
+    if (tmp->status & (CONF_OPERATOR | CONF_LOCOP)) {
       if (tmp->clients < MaxLinks(tmp->confClass))
-       return tmp;
+        return tmp;
       else
-       continue;
+        continue;
     }
     else
       return tmp;
   }
-  return NULL;
+  return 0;
 }
 
-aConfItem *find_conf(Link *lp, const char *name, int statmask)
+struct ConfItem* find_conf_byname(struct SLink* lp, const char* name,
+                                  int statmask)
 {
-  Reg1 aConfItem *tmp;
-  int namelen = name ? strlen(name) : 0;
+  struct ConfItem* tmp;
+  assert(0 != name);
 
-  if (namelen > HOSTLEN)
-    return (aConfItem *)0;
+  if (HOSTLEN < strlen(name))
+    return 0;
 
-  for (; lp; lp = lp->next)
-  {
+  for (; lp; lp = lp->next) {
     tmp = lp->value.aconf;
-    if ((tmp->status & statmask) &&
-       (((tmp->status & (CONF_SERVER_MASK | CONF_HUB)) &&
-       tmp->name && !strCasediff(tmp->name, name)) ||
-       ((tmp->status & (CONF_SERVER_MASK | CONF_HUB)) == 0 &&
-       tmp->name && !match(tmp->name, name))))
-      return tmp;
+    if (0 != (tmp->status & statmask)) {
+      assert(0 != tmp->name);
+      if (0 == ircd_strcmp(tmp->name, name) || 0 == match(tmp->name, name))
+        return tmp;
+    }
   }
-  return NULL;
+  return 0;
 }
 
 /*
  * Added for new access check    meLazy
  */
-aConfItem *find_conf_host(Link *lp, char *host, int statmask)
+struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host,
+                                  int statmask)
 {
-  Reg1 aConfItem *tmp;
-  int hostlen = host ? strlen(host) : 0;
+  struct ConfItem* tmp;
+  assert(0 != host);
 
-  if (hostlen > HOSTLEN || BadPtr(host))
-    return (aConfItem *)NULL;
-  for (; lp; lp = lp->next)
-  {
+  if (HOSTLEN < strlen(host))
+    return 0;
+
+  for (; lp; lp = lp->next) {
     tmp = lp->value.aconf;
-    if (tmp->status & statmask &&
-       (!(tmp->status & CONF_SERVER_MASK || tmp->host) ||
-       (tmp->host && !match(tmp->host, host))))
-      return tmp;
+    if (0 != (tmp->status & statmask)) {
+      assert(0 != tmp->host);
+      if (0 == match(tmp->host, host))
+        return tmp;
+    }
   }
-  return NULL;
+  return 0;
 }
 
 /*
@@ -563,28 +819,19 @@ aConfItem *find_conf_host(Link *lp, char *host, int statmask)
  * Find a conf line using the IP# stored in it to search upon.
  * Added 1/8/92 by Avalon.
  */
-aConfItem *find_conf_ip(Link *lp, char *ip, char *user, int statmask)
+struct ConfItem* find_conf_byip(struct SLink* lp, const char* ip, 
+                                int statmask)
 {
-  Reg1 aConfItem *tmp;
-  Reg2 char *s;
+  struct ConfItem* tmp;
 
-  for (; lp; lp = lp->next)
-  {
-    tmp = lp->value.aconf;
-    if (!(tmp->status & statmask))
-      continue;
-    s = strchr(tmp->host, '@');
-    *s = '\0';
-    if (match(tmp->host, user))
-    {
-      *s = '@';
-      continue;
+  for (; lp; lp = lp->next) {
+    tmp = lp->value.aconf;
+    if (0 != (tmp->status & statmask)) {
+      if (0 == memcmp(&tmp->ipnum, ip, sizeof(struct in_addr)))
+        return tmp;
     }
-    *s = '@';
-    if (!memcmp(&tmp->ipnum, ip, sizeof(struct in_addr)))
-      return tmp;
   }
-  return NULL;
+  return 0;
 }
 
 /*
@@ -592,35 +839,38 @@ aConfItem *find_conf_ip(Link *lp, char *ip, char *user, int statmask)
  *
  * - looks for a match on all given fields.
  */
-static aConfItem *find_conf_entry(aConfItem *aconf, unsigned int mask)
+static struct ConfItem *find_conf_entry(struct ConfItem *aconf,
+                                        unsigned int mask)
 {
-  Reg1 aConfItem *bconf;
+  struct ConfItem *bconf;
+  assert(0 != aconf);
 
-  for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
-  {
+  mask &= ~CONF_ILLEGAL;
+
+  for (bconf = GlobalConfList; bconf; bconf = bconf->next) {
     if (!(bconf->status & mask) || (bconf->port != aconf->port))
       continue;
 
-    if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
-       (BadPtr(aconf->host) && !BadPtr(bconf->host)))
+    if ((EmptyString(bconf->host) && !EmptyString(aconf->host)) ||
+        (EmptyString(aconf->host) && !EmptyString(bconf->host)))
       continue;
-    if (!BadPtr(bconf->host) && strCasediff(bconf->host, aconf->host))
+    if (!EmptyString(bconf->host) && 0 != ircd_strcmp(bconf->host, aconf->host))
       continue;
 
-    if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
-       (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
+    if ((EmptyString(bconf->passwd) && !EmptyString(aconf->passwd)) ||
+        (EmptyString(aconf->passwd) && !EmptyString(bconf->passwd)))
       continue;
-    if (!BadPtr(bconf->passwd) && (!isDigit(*bconf->passwd) || bconf->passwd[1])
+    if (!EmptyString(bconf->passwd) && (!IsDigit(*bconf->passwd) || bconf->passwd[1])
 #ifdef USEONE
-       && strCasediff(bconf->passwd, "ONE")
+        && 0 != ircd_strcmp(bconf->passwd, "ONE")
 #endif
-       && strCasediff(bconf->passwd, aconf->passwd))
+        && 0 != ircd_strcmp(bconf->passwd, aconf->passwd))
       continue;
 
-    if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
-       (BadPtr(aconf->name) && !BadPtr(bconf->name)))
+    if ((EmptyString(bconf->name) && !EmptyString(aconf->name)) ||
+        (EmptyString(aconf->name) && !EmptyString(bconf->name)))
       continue;
-    if (!BadPtr(bconf->name) && strCasediff(bconf->name, aconf->name))
+    if (!EmptyString(bconf->name) && 0 != ircd_strcmp(bconf->name, aconf->name))
       continue;
     break;
   }
@@ -634,57 +884,45 @@ static aConfItem *find_conf_entry(aConfItem *aconf, unsigned int mask)
  * as a result of an operator issuing this command, else assume it has been
  * called as a result of the server receiving a HUP signal.
  */
-int rehash(aClient *cptr, int sig)
+int rehash(struct Client *cptr, int sig)
 {
-  Reg1 aConfItem **tmp = &conf, *tmp2;
-  Reg2 aConfClass *cltmp;
-  Reg1 aClient *acptr;
-  Reg2 aMotdItem *temp;
-  Reg2 int i;
-  int ret = 0, found_g;
-
-  if (sig == 1)
+  struct ConfItem** tmp = &GlobalConfList;
+  struct ConfItem*  tmp2;
+  struct ConfClass* cltmp;
+  struct Client*    acptr;
+  struct MotdItem*  temp;
+  int               i;
+  int               ret = 0;
+  int               found_g = 0;
+
+  if (1 == sig)
     sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
 
-  for (i = 0; i <= highest_fd; i++)
-    if ((acptr = loc_clients[i]) && !IsMe(acptr))
-    {
-      /*
-       * Nullify any references from client structures to
-       * this host structure which is about to be freed.
-       * Could always keep reference counts instead of
-       * this....-avalon
-       */
-      acptr->hostp = NULL;
-    }
-
-  while ((tmp2 = *tmp))
-    if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT)
-    {
+  while ((tmp2 = *tmp)) {
+    if (tmp2->clients) {
       /*
        * Configuration entry is still in use by some
        * local clients, cannot delete it--mark it so
        * that it will be deleted when the last client
        * exits...
        */
-      if (!(tmp2->status & (CONF_LISTEN_PORT | CONF_CLIENT)))
-      {
-       *tmp = tmp2->next;
-       tmp2->next = NULL;
+      if (!(tmp2->status & CONF_CLIENT)) {
+        *tmp = tmp2->next;
+        tmp2->next = 0;
       }
       else
-       tmp = &tmp2->next;
+        tmp = &tmp2->next;
       tmp2->status |= CONF_ILLEGAL;
     }
-    else
-    {
+    else {
       *tmp = tmp2->next;
       /* free expression trees of connect rules */
       if ((tmp2->status & (CONF_CRULEALL | CONF_CRULEAUTO)) &&
-         (tmp2->passwd != NULL))
-       crule_free(&(tmp2->passwd));
+          (tmp2->passwd != NULL))
+        crule_free(&(tmp2->passwd));
       free_conf(tmp2);
     }
+  }
 
   /*
    * We don't delete the class table, rather mark all entries
@@ -699,15 +937,23 @@ int rehash(aClient *cptr, int sig)
   clearNickJupes();
 
   if (sig != 2)
-    flush_cache();
-  if (initconf(0) == -1)       /* This calls check_class(), */
-    check_class();             /* unless it fails */
+    flush_resolver_cache();
+
+  mark_listeners_closing();
+
+  if (initconf(0) == -1)        /* This calls check_class(), */
+    check_class();                /* unless it fails */
+
+  /*
+   * make sure that the server listener is re-added so it doesn't get
+   * closed
+   */
   close_listeners();
 
   /*
    * Flush out deleted I and P lines although still in use.
    */
-  for (tmp = &conf; (tmp2 = *tmp);)
+  for (tmp = &GlobalConfList; (tmp2 = *tmp);) {
     if (!(tmp2->status & CONF_ILLEGAL))
       tmp = &tmp2->next;
     else
@@ -715,50 +961,45 @@ int rehash(aClient *cptr, int sig)
       *tmp = tmp2->next;
       tmp2->next = NULL;
       if (!tmp2->clients)
-       free_conf(tmp2);
+        free_conf(tmp2);
     }
-
-  for (i = 0; i <= highest_fd; i++) {
-    if ((acptr = loc_clients[i]) && !IsMe(acptr)) {
+  }
+  for (i = 0; i <= HighestFd; i++) {
+    if ((acptr = LocalClientArray[i])) {
+      assert(!IsMe(acptr));
       if (IsServer(acptr)) {
-       det_confs_butmask(acptr,
-           ~(CONF_HUB | CONF_LEAF | CONF_UWORLD | CONF_ILLEGAL));
-       attach_confs(acptr, acptr->name, CONF_HUB | CONF_LEAF | CONF_UWORLD);
+        det_confs_butmask(acptr,
+            ~(CONF_HUB | CONF_LEAF | CONF_UWORLD | CONF_ILLEGAL));
+        attach_confs_byname(acptr, acptr->name,
+                            CONF_HUB | CONF_LEAF | CONF_UWORLD);
       }
       if ((found_g = find_kill(acptr))) {
-       sendto_op_mask(found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
-           found_g == -2 ? "G-line active for %s" : "K-line active for %s",
-           get_client_name(acptr, FALSE));
-       if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" :
-           "K-lined") == CPTR_KILLED)
-         ret = CPTR_KILLED;
-      }
-#if defined(R_LINES) && defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN)
-      if (find_restrict(acptr)) {
-       sendto_ops("Restricting %s, closing lp", get_client_name(acptr, FALSE));
-       if (exit_client(cptr, acptr, &me, "R-lined") == CPTR_KILLED)
-         ret = CPTR_KILLED;
+        sendto_op_mask(found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
+            found_g == -2 ? "G-line active for %s" : "K-line active for %s",
+            get_client_name(acptr, HIDE_IP));
+        if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" :
+            "K-lined") == CPTR_KILLED)
+          ret = CPTR_KILLED;
       }
-#endif
     }
   }
-
-  /* free old motd structs */
+  /* 
+   * free old motd structs
+   */
   while (motd) {
     temp = motd->next;
-    RunFree(motd);
+    MyFree(motd);
     motd = temp;
   }
   while (rmotd) {
     temp = rmotd->next;
-    RunFree(rmotd);
+    MyFree(rmotd);
     rmotd = temp;
   }
   /* reload motd files */
   read_tlines();
   rmotd = read_motd(RPATH);
   motd = read_motd(MPATH);
-
   return ret;
 }
 
@@ -773,7 +1014,6 @@ int rehash(aClient *cptr, int sig)
 
 #define MAXCONFLINKS 150
 
-unsigned short server_port;
 
 int initconf(int opt)
 {
@@ -787,52 +1027,48 @@ int initconf(int opt)
     {'\\', '\\'},
     {0, 0}
   };
-  Reg1 char *tmp, *s;
+  char *tmp, *s;
   FBFILE *file;
   int i;
   char line[512];
-  int ccount = 0, ncount = 0;
-  aConfItem *aconf = NULL;
+  int ccount = 0;
+  struct ConfItem *aconf = 0;
 
   Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
-  if (NULL == (file = fbopen(configfile, "r")))
-  {
+  if (0 == (file = fbopen(configfile, "r"))) {
     return -1;
   }
-  while (fbgets(line, sizeof(line) - 1, file))
-  {
+  while (fbgets(line, sizeof(line) - 1, file)) {
     if ((tmp = strchr(line, '\n')))
       *tmp = '\0';
     /*
      * Do quoting of characters and # detection.
      */
-    for (tmp = line; *tmp; tmp++)
-    {
-      if (*tmp == '\\')
-      {
-       for (i = 0; quotes[i][0]; i++)
-         if (quotes[i][0] == *(tmp + 1))
-         {
-           *tmp = quotes[i][1];
-           break;
-         }
-       if (!quotes[i][0])
-         *tmp = *(tmp + 1);
-       if (!*(tmp + 1))
-         break;
-       else
-         for (s = tmp; (*s = *(s + 1)); s++)
-           ;
+    for (tmp = line; *tmp; tmp++) {
+      if (*tmp == '\\') {
+        for (i = 0; quotes[i][0]; i++) {
+          if (quotes[i][0] == *(tmp + 1)) {
+            *tmp = quotes[i][1];
+            break;
+          }
+        }
+        if (!quotes[i][0])
+          *tmp = *(tmp + 1);
+        if (!*(tmp + 1))
+          break;
+        else {
+          for (s = tmp; (*s = *(s + 1)); s++)
+            ;
+        }
       }
       else if (*tmp == '#')
-       *tmp = '\0';
+        *tmp = '\0';
     }
     if (!*line || line[0] == '#' || line[0] == '\n' ||
-       line[0] == ' ' || line[0] == '\t')
+        line[0] == ' ' || line[0] == '\t')
       continue;
     /* Could we test if it's conf line at all?      -Vesa */
-    if (line[1] != ':')
-    {
+    if (line[1] != ':') {
       Debug((DEBUG_ERROR, "Bad config line: %s", line));
       continue;
     }
@@ -843,207 +1079,197 @@ int initconf(int opt)
     tmp = getfield(line, ':');
     if (!tmp)
       continue;
-    switch (*tmp)
-    {
-      case 'A':                /* Name, e-mail address of administrator */
-      case 'a':                /* of this server. */
-       aconf->status = CONF_ADMIN;
-       break;
-      case 'C':                /* Server where I should try to connect */
-      case 'c':                /* in case of lp failures             */
-       ccount++;
-       aconf->status = CONF_CONNECT_SERVER;
-       break;
-       /* Connect rule */
-      case 'D':
-       aconf->status = CONF_CRULEALL;
-       break;
-       /* Connect rule - autos only */
-      case 'd':
-       aconf->status = CONF_CRULEAUTO;
-       break;
-      case 'H':                /* Hub server line */
-      case 'h':
-       aconf->status = CONF_HUB;
-       break;
-      case 'I':                /* Just plain normal irc client trying  */
-      case 'i':                /* to connect me */
-       aconf->status = CONF_CLIENT;
-       break;
-      case 'K':                /* Kill user line on irc.conf           */
-       aconf->status = CONF_KILL;
-       break;
-      case 'k':                /* Kill user line based on IP in ircd.conf */
-       aconf->status = CONF_IPKILL;
-       break;
-       /* Operator. Line should contain at least */
-       /* password and host where connection is  */
-      case 'L':                /* guaranteed leaf server */
-      case 'l':
-       aconf->status = CONF_LEAF;
-       break;
-       /* Me. Host field is name used for this host */
-       /* and port number is the number of the port */
-      case 'M':
-      case 'm':
-       aconf->status = CONF_ME;
-       break;
-      case 'N':                /* Server where I should NOT try to     */
-      case 'n':                /* connect in case of lp failures     */
-       /* but which tries to connect ME        */
-       ++ncount;
-       aconf->status = CONF_NOCONNECT_SERVER;
-       break;
-      case 'O':
-       aconf->status = CONF_OPERATOR;
-       break;
-       /* Local Operator, (limited privs --SRB) */
-      case 'o':
-       aconf->status = CONF_LOCOP;
-       break;
-      case 'P':                /* listen port line */
-      case 'p':
-       aconf->status = CONF_LISTEN_PORT;
-       break;
-#ifdef R_LINES
-      case 'R':                /* extended K line */
-      case 'r':                /* Offers more options of how to restrict */
-       aconf->status = CONF_RESTRICT;
-       break;
-#endif
-      case 'T':                /* print out different motd's */
-      case 't':                /* based on hostmask */
-       aconf->status = CONF_TLINES;
-       break;
-      case 'U':                /* Underworld server, allowed to hack modes */
-      case 'u':                /* *Every* server on the net must define the same !!! */
-       aconf->status = CONF_UWORLD;
-       break;
-      case 'Y':
-      case 'y':
-       aconf->status = CONF_CLASS;
-       break;
-      default:
-       Debug((DEBUG_ERROR, "Error in config file: %s", line));
-       break;
+    switch (*tmp) {
+    case 'A':                /* Name, e-mail address of administrator */
+    case 'a':                /* of this server. */
+      aconf->status = CONF_ADMIN;
+      break;
+    case 'C':                /* Server where I should try to connect */
+    case 'c':                /* in case of lp failures             */
+      ++ccount;
+      aconf->status = CONF_SERVER;
+      break;
+      /* Connect rule */
+    case 'D':
+      aconf->status = CONF_CRULEALL;
+      break;
+      /* Connect rule - autos only */
+    case 'd':
+      aconf->status = CONF_CRULEAUTO;
+      break;
+    case 'H':                /* Hub server line */
+    case 'h':
+      aconf->status = CONF_HUB;
+      break;
+    case 'I':                /* Just plain normal irc client trying  */
+    case 'i':                /* to connect me */
+      aconf->status = CONF_CLIENT;
+      break;
+    case 'K':                /* Kill user line on irc.conf           */
+      aconf->status = CONF_KILL;
+      break;
+    case 'k':                /* Kill user line based on IP in ircd.conf */
+      aconf->status = CONF_IPKILL;
+      break;
+      /* Operator. Line should contain at least */
+      /* password and host where connection is  */
+    case 'L':                /* guaranteed leaf server */
+    case 'l':
+      aconf->status = CONF_LEAF;
+      break;
+      /* Me. Host field is name used for this host */
+      /* and port number is the number of the port */
+    case 'M':
+    case 'm':
+      aconf->status = CONF_ME;
+      break;
+    case 'O':
+      aconf->status = CONF_OPERATOR;
+      break;
+      /* Local Operator, (limited privs --SRB) */
+    case 'o':
+      aconf->status = CONF_LOCOP;
+      break;
+    case 'P':                /* listen port line */
+    case 'p':
+      aconf->status = CONF_LISTEN_PORT;
+      break;
+    case 'T':                /* print out different motd's */
+    case 't':                /* based on hostmask */
+      aconf->status = CONF_TLINES;
+      break;
+    case 'U':      /* Underworld server, allowed to hack modes */
+    case 'u':      /* *Every* server on the net must define the same !!! */
+      aconf->status = CONF_UWORLD;
+      break;
+    case 'Y':
+    case 'y':
+      aconf->status = CONF_CLASS;
+      break;
+    default:
+      Debug((DEBUG_ERROR, "Error in config file: %s", line));
+      break;
     }
     if (IsIllegal(aconf))
       continue;
 
-    for (;;)                   /* Fake loop, that I can use break here --msa */
-    {
+    for (;;) {            /* Fake loop, that I can use break here --msa */
       if ((tmp = getfield(NULL, ':')) == NULL)
-       break;
+        break;
       DupString(aconf->host, tmp);
       if ((tmp = getfield(NULL, (aconf->status == CONF_KILL
-         || aconf->status == CONF_IPKILL) ? '"' : ':')) == NULL)
-       break;
+          || aconf->status == CONF_IPKILL) ? '"' : ':')) == NULL)
+        break;
       DupString(aconf->passwd, tmp);
       if ((tmp = getfield(NULL, ':')) == NULL)
-       break;
+        break;
       DupString(aconf->name, tmp);
       if ((tmp = getfield(NULL, ':')) == NULL)
-       break;
+        break;
       aconf->port = atoi(tmp);
       tmp = getfield(NULL, ':');
-      if (aconf->status & CONF_ME)
-      {
-       server_port = aconf->port;
-       if (!tmp)
-       {
-         Debug((DEBUG_FATAL, "Your M: line must have the Numeric, "
-             "assigned to you by routing-com, behind the port number!\n"));
-#ifdef USE_SYSLOG
-         syslog(LOG_WARNING, "Your M: line must have the Numeric, "
-             "assigned to you by routing-com, behind the port number!\n");
-#endif
-         exit(-1);
-       }
-       SetYXXServerName(&me, atoi(tmp));       /* Our Numeric Nick */
+      if (aconf->status & CONF_ME) {
+        if (!tmp) {
+          Debug((DEBUG_FATAL, "Your M: line must have the Numeric, "
+              "assigned to you by routing-com, behind the port number!\n"));
+          ircd_log(L_WARNING, "Your M: line must have the Numeric, "
+              "assigned to you by routing-com, behind the port number!\n");
+          exit(-1);
+        }
+        SetYXXServerName(&me, atoi(tmp));        /* Our Numeric Nick */
       }
       else if (tmp)
-       aconf->confClass = find_class(atoi(tmp));
+        aconf->confClass = find_class(atoi(tmp));
       break;
     }
     /*
      * If conf line is a class definition, create a class entry
      * for it and make the conf_line illegal and delete it.
      */
-    if (aconf->status & CONF_CLASS)
-    {
+    if (aconf->status & CONF_CLASS) {
       add_class(atoi(aconf->host), atoi(aconf->passwd),
-         atoi(aconf->name), aconf->port, tmp ? atoi(tmp) : 0);
+          atoi(aconf->name), aconf->port, tmp ? atoi(tmp) : 0);
       continue;
     }
     /*
      * Associate each conf line with a class by using a pointer
      * to the correct class record. -avalon
      */
-    if (aconf->status & (CONF_CLIENT_MASK | CONF_LISTEN_PORT))
-    {
+    if (aconf->status & CONF_CLIENT_MASK) {
       if (aconf->confClass == 0)
-       aconf->confClass = find_class(0);
+        aconf->confClass = find_class(0);
     }
-    if (aconf->status & (CONF_LISTEN_PORT | CONF_CLIENT))
-    {
-      aConfItem *bconf;
-
-      if ((bconf = find_conf_entry(aconf, aconf->status)))
-      {
-       delist_conf(bconf);
-       bconf->status &= ~CONF_ILLEGAL;
-       if (aconf->status == CONF_CLIENT)
-       {
-         char *passwd = bconf->passwd;
-         bconf->passwd = aconf->passwd;
-         aconf->passwd = passwd;
-         ConfLinks(bconf) -= bconf->clients;
-         bconf->confClass = aconf->confClass;
-         if (bconf->confClass)
-           ConfLinks(bconf) += bconf->clients;
-       }
-       free_conf(aconf);
-       aconf = bconf;
+    if (aconf->status & CONF_LISTEN_PORT) {
+      int         is_server = 0;
+      int         is_hidden = 0;
+      if (!EmptyString(aconf->name)) {
+        const char* x = aconf->name;
+        if ('S' == ToUpper(*x))
+          is_server = 1;
+        ++x;
+        if ('H' == ToUpper(*x))
+          is_hidden = 1;
+      }
+      add_listener(aconf->port, aconf->passwd, aconf->host, 
+                   is_server, is_hidden);
+      continue;
+    } 
+    if (aconf->status & CONF_CLIENT) {
+      struct ConfItem *bconf;
+
+      if ((bconf = find_conf_entry(aconf, aconf->status))) {
+        delist_conf(bconf);
+        bconf->status &= ~CONF_ILLEGAL;
+        if (aconf->status == CONF_CLIENT) {
+          /*
+           * copy the password field in case it changed
+           */
+          MyFree(bconf->passwd);
+          bconf->passwd = aconf->passwd;
+          aconf->passwd = 0;
+
+          ConfLinks(bconf) -= bconf->clients;
+          bconf->confClass = aconf->confClass;
+          if (bconf->confClass)
+            ConfLinks(bconf) += bconf->clients;
+        }
+        free_conf(aconf);
+        aconf = bconf;
       }
-      else if (aconf->host && aconf->status == CONF_LISTEN_PORT)
-       add_listener(aconf);
     }
-    if (aconf->status & CONF_SERVER_MASK)
-      if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS ||
-         !aconf->host || strchr(aconf->host, '*') ||
-         strchr(aconf->host, '?') || !aconf->name)
-       continue;
-
-    if (aconf->status & (CONF_SERVER_MASK | CONF_LOCOP | CONF_OPERATOR))
-      if (!strchr(aconf->host, '@') && *aconf->host != '/')
-      {
-       char *newhost;
-       int len = 3;            /* *@\0 = 3 */
-
-       len += strlen(aconf->host);
-       newhost = (char *)RunMalloc(len);
-       sprintf_irc(newhost, "*@%s", aconf->host);
-       RunFree(aconf->host);
-       aconf->host = newhost;
+    if (aconf->status & CONF_SERVER) {
+      if (ccount > MAXCONFLINKS || !aconf->host || strchr(aconf->host, '*') ||
+          strchr(aconf->host, '?') || !aconf->name)
+        continue;
+    }
+    if (aconf->status & (CONF_LOCOP | CONF_OPERATOR)) {
+      if (!strchr(aconf->host, '@')) {
+        char* newhost;
+        int len = 3;                /* *@\0 = 3 */
+
+        len += strlen(aconf->host);
+        newhost = (char*) MyMalloc(len);
+        assert(0 != newhost);
+        sprintf_irc(newhost, "*@%s", aconf->host);
+        MyFree(aconf->host);
+        aconf->host = newhost;
       }
-    if (aconf->status & CONF_SERVER_MASK)
-    {
-      if (BadPtr(aconf->passwd))
-       continue;
+    }
+    if (aconf->status & CONF_SERVER) {
+      if (EmptyString(aconf->passwd))
+        continue;
       else if (!(opt & BOOT_QUICK))
-       lookup_confhost(aconf);
+        lookup_confhost(aconf);
     }
 
     /* Create expression tree from connect rule...
      * If there's a parsing error, nuke the conf structure */
-    if (aconf->status & (CONF_CRULEALL | CONF_CRULEAUTO))
-    {
-      RunFree(aconf->passwd);
-      if ((aconf->passwd = (char *)crule_parse(aconf->name)) == NULL)
-      {
-       free_conf(aconf);
-       aconf = NULL;
-       continue;
+    if (aconf->status & (CONF_CRULEALL | CONF_CRULEAUTO)) {
+      MyFree(aconf->passwd);
+      if ((aconf->passwd = (char *)crule_parse(aconf->name)) == NULL) {
+        free_conf(aconf);
+        aconf = NULL;
+        continue;
       }
     }
 
@@ -1054,11 +1280,8 @@ int initconf(int opt)
      * if previously defined. Note, that "info"-field can be
      * changed by "/rehash".
      */
-    if (aconf->status == CONF_ME)
-    {
-      strncpy(me.info, aconf->name, sizeof(me.info) - 1);
-      if (portnum == 0)
-       portnum = aconf->port;
+    if (aconf->status == CONF_ME) {
+      ircd_strncpy(me.info, aconf->name, REALLEN);
     }
 
     /*
@@ -1070,92 +1293,42 @@ int initconf(int opt)
     if ((aconf->status == CONF_UWORLD) && (aconf->passwd) && (*aconf->passwd))
       addNickJupes(aconf->passwd);
 
-    if (aconf->status & CONF_ADMIN)
-      if (!aconf->host || !aconf->passwd || !aconf->name)
-      {
-       Debug((DEBUG_FATAL, "Your A: line must have 4 fields!\n"));
-#ifdef USE_SYSLOG
-       syslog(LOG_WARNING, "Your A: line must have 4 fields!\n");
-#endif
-       exit(-1);
+    if (aconf->status & CONF_ADMIN) {
+      if (!aconf->host || !aconf->passwd || !aconf->name) {
+        Debug((DEBUG_FATAL, "Your A: line must have 4 fields!\n"));
+        ircd_log(L_WARNING, "Your A: line must have 4 fields!\n");
+        exit(-1);
       }
-
+    }
     collapse(aconf->host);
     collapse(aconf->name);
     Debug((DEBUG_NOTICE,
-       "Read Init: (%d) (%s) (%s) (%s) (%u) (%p)",
-       aconf->status, aconf->host, aconf->passwd,
-       aconf->name, aconf->port, aconf->confClass));
-    aconf->next = conf;
-    conf = aconf;
+        "Read Init: (%d) (%s) (%s) (%s) (%u) (%p)",
+        aconf->status, aconf->host, aconf->passwd,
+        aconf->name, aconf->port, aconf->confClass));
+    aconf->next = GlobalConfList;
+    GlobalConfList = aconf;
     aconf = NULL;
   }
   if (aconf)
     free_conf(aconf);
   fbclose(file);
   check_class();
-  nextping = nextconnect = now;
-  return 0;
-}
-
-/*
- * lookup_confhost
- *
- * Do (start) DNS lookups of all hostnames in the conf line and convert
- * an IP addresses in a.b.c.d number for to IP#s.
- */
-static int lookup_confhost(aConfItem *aconf)
-{
-  Reg2 char *s;
-  Reg3 struct hostent *hp;
-  Link ln;
-
-  if (BadPtr(aconf->host) || BadPtr(aconf->name))
-    goto badlookup;
-  if ((s = strchr(aconf->host, '@')))
-    s++;
-  else
-    s = aconf->host;
-  /*
-   * Do name lookup now on hostnames given and store the
-   * ip numbers in conf structure.
-   */
-  if (!isAlpha(*s) && !isDigit(*s))
-    goto badlookup;
-
-  /*
-   * Prepare structure in case we have to wait for a
-   * reply which we get later and store away.
-   */
-  ln.value.aconf = aconf;
-  ln.flags = ASYNC_CONF;
-
-  if (isDigit(*s))
-    aconf->ipnum.s_addr = inet_addr(s);
-  else if ((hp = gethost_byname(s, &ln)))
-    memcpy(&(aconf->ipnum), hp->h_addr, sizeof(struct in_addr));
-
-  if (aconf->ipnum.s_addr == INADDR_NONE)
-    goto badlookup;
+  nextping = nextconnect = CurrentTime;
   return 0;
-badlookup:
-  if (aconf->ipnum.s_addr == INADDR_NONE)
-    memset(&aconf->ipnum, 0, sizeof(struct in_addr));
-  Debug((DEBUG_ERROR, "Host/server name error: (%s) (%s)",
-      aconf->host, aconf->name));
-  return -1;
 }
 
 /* read_tlines 
- * Read info from T:lines into trecords which include the file 
+ * Read info from T:lines into TRecords which include the file 
  * timestamp, the hostmask, and the contents of the motd file 
  * -Ghostwolf 7sep97
  */
 void read_tlines()
 {
-  aConfItem *tmp;
-  atrecord *temp, *last = NULL;        /* Init. to avoid compiler warning */
-  aMotdItem *amotd;
+  struct ConfItem *tmp;
+  struct TRecord *temp;
+  struct TRecord *last = NULL;        /* Init. to avoid compiler warning */
+  struct MotdItem *amotd;
 
   /* Free the old trecords and the associated motd contents first */
   while (tdata)
@@ -1164,36 +1337,40 @@ void read_tlines()
     while (tdata->tmotd)
     {
       amotd = tdata->tmotd->next;
-      RunFree(tdata->tmotd);
+      MyFree(tdata->tmotd);
       tdata->tmotd = amotd;
     }
-    RunFree(tdata);
+    MyFree(tdata);
     tdata = last;
   }
 
-  for (tmp = conf; tmp; tmp = tmp->next)
-    if (tmp->status == CONF_TLINES && tmp->host && tmp->passwd)
-    {
-      temp = (atrecord *) RunMalloc(sizeof(atrecord));
-      if (!temp)
-       outofmemory();
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
+    if (tmp->status == CONF_TLINES && tmp->host && tmp->passwd) {
+      temp = (struct TRecord*) MyMalloc(sizeof(struct TRecord));
+      assert(0 != temp);
+
       temp->hostmask = tmp->host;
       temp->tmotd = read_motd(tmp->passwd);
       temp->tmotd_tm = motd_tm;
       temp->next = NULL;
       if (!tdata)
-       tdata = temp;
+        tdata = temp;
       else
-       last->next = temp;
+        last->next = temp;
       last = temp;
     }
+  }
 }
 
-int find_kill(aClient *cptr)
+int find_kill(struct Client *cptr)
 {
-  char reply[256], *host, *name;
-  aConfItem *tmp;
-  aGline *agline = NULL;
+  char             reply[256];
+  const char*      host;
+  const char*      name;
+  struct ConfItem* tmp;
+  struct Gline*    agline = NULL;
+
+  assert(0 != cptr);
 
   if (!cptr->user)
     return 0;
@@ -1201,64 +1378,67 @@ int find_kill(aClient *cptr)
   host = cptr->sockhost;
   name = cptr->user->username;
 
+#if 0
+  /*
+   * whee :)
+   * XXX - if this ever happens, we're already screwed
+   */
   if (strlen(host) > (size_t)HOSTLEN ||
       (name ? strlen(name) : 0) > (size_t)HOSTLEN)
     return (0);
+#endif
 
   reply[0] = '\0';
 
-  for (tmp = conf; tmp; tmp = tmp->next)
+  for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
     /* Added a check against the user's IP address as well.
      * If the line is either CONF_KILL or CONF_IPKILL, check it; if and only
      * if it's CONF_IPKILL, check the IP address as well (the && below will
      * short circuit and the match won't even get run) -Kev
      */
     if ((tmp->status & CONF_KLINE) && tmp->host && tmp->name &&
-       (match(tmp->host, host) == 0 ||
-       ((tmp->status == CONF_IPKILL) &&
-       match(tmp->host, inetntoa(cptr->ip)) == 0)) &&
-       (!name || match(tmp->name, name) == 0) &&
-       (!tmp->port || (tmp->port == cptr->acpt->port)))
+        (match(tmp->host, host) == 0 ||
+        ((tmp->status == CONF_IPKILL) &&
+        match(tmp->host, ircd_ntoa((const char*) &cptr->ip)) == 0)) &&
+        (!name || match(tmp->name, name) == 0) &&
+        (!tmp->port || (tmp->port == cptr->listener->port)))
     {
       /*
        * Can short-circuit evaluation - not taking chances
        * because check_time_interval destroys tmp->passwd
        * - Mmmm
        */
-      if (BadPtr(tmp->passwd))
-       break;
+      if (EmptyString(tmp->passwd))
+        break;
       else if (is_comment(tmp->passwd))
-       break;
+        break;
       else if (check_time_interval(tmp->passwd, reply))
-       break;
+        break;
     }
-
+  }
   if (reply[0])
     sendto_one(cptr, reply, me.name, ERR_YOUREBANNEDCREEP, cptr->name);
-  else if (tmp)
-  {
-    if (BadPtr(tmp->passwd))
+  else if (tmp) {
+    if (EmptyString(tmp->passwd))
       sendto_one(cptr,
-         ":%s %d %s :Connection from your host is refused on this server.",
-         me.name, ERR_YOUREBANNEDCREEP, cptr->name);
-    else
-    {
-      if (*tmp->passwd == '"')
-      {
-       char *sbuf =
-           sprintf_irc(sendbuf, ":%s %d %s :%s", me.name, ERR_YOUREBANNEDCREEP,
-           cptr->name, &tmp->passwd[1]);
-       sbuf[-1] = '.';         /* Overwrite last quote with a dot */
-       sendbufto_one(cptr);
+          ":%s %d %s :Connection from your host is refused on this server.",
+          me.name, ERR_YOUREBANNEDCREEP, cptr->name);
+    else {
+      if (*tmp->passwd == '"') {
+        char *sbuf =
+            sprintf_irc(sendbuf, ":%s %d %s :%s", me.name, ERR_YOUREBANNEDCREEP,
+            cptr->name, &tmp->passwd[1]);
+        sbuf[-1] = '.';                /* Overwrite last quote with a dot */
+        sendbufto_one(cptr);
       }
       else if (*tmp->passwd == '!')
-       killcomment(cptr, cptr->name, &tmp->passwd[1]);
+        killcomment(cptr, cptr->name, &tmp->passwd[1]);
       else
 #ifdef COMMENT_IS_FILE
-       killcomment(cptr, cptr->name, tmp->passwd);
+        killcomment(cptr, cptr->name, tmp->passwd);
 #else
-       sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
-           cptr->name, tmp->passwd);
+        sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
+            cptr->name, tmp->passwd);
 #endif
     }
   }
@@ -1267,274 +1447,175 @@ int find_kill(aClient *cptr)
   /* added a check against the user's IP address to find_gline() -Kev */
   else if ((agline = find_gline(cptr, NULL)) && GlineIsActive(agline))
     sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
-       cptr->name, agline->reason);
+        cptr->name, agline->reason);
   else
-    agline = NULL;             /* if a gline was found, it was inactive */
+    agline = NULL;                /* if a gline was found, it was inactive */
 
   return (tmp ? -1 : (agline ? -2 : 0));
 }
 
-#ifdef R_LINES
-/*
- * find_restrict
- *
- * Works against host/name and calls an outside program
- * to determine whether a client is allowed to connect.  This allows
- * more freedom to determine who is legal and who isn't, for example
- * machine load considerations.  The outside program is expected to
- * return a reply line where the first word is either 'Y' or 'N' meaning
- * "Yes Let them in" or "No don't let them in."  If the first word
- * begins with neither 'Y' or 'N' the default is to let the person on.
- * It returns a value of 0 if the user is to be let through -Hoppie
- */
-int find_restrict(aClient *cptr)
+struct MotdItem* read_motd(const char* motdfile)
 {
-  aConfItem *tmp;
-  char reply[80], temprpl[80];
-  char *rplhold = reply, *host, *name, *s;
-  char rplchar = 'Y';
-  int pi[2], rc = 0, n;
-  FBFILE *file = NULL;
-
-  if (!cptr->user)
-    return 0;
-  name = cptr->user->username;
-  host = cptr->sockhost;
-  Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host));
-
-  for (tmp = conf; tmp; tmp = tmp->next)
-  {
-    if (tmp->status != CONF_RESTRICT ||
-       (tmp->host && host && match(tmp->host, host)) ||
-       (tmp->name && name && match(tmp->name, name)))
-      continue;
-
-    if (BadPtr(tmp->passwd))
-    {
-      sendto_ops("Program missing on R-line %s/%s, ignoring", name, host);
-      continue;
-    }
-
-    if (pipe(pi) == -1)
-    {
-      report_error("Error creating pipe for R-line %s: %s", &me);
-      return 0;
-    }
-    switch (rc = fork())
-    {
-      case -1:
-       report_error("Error forking for R-line %s: %s", &me);
-       return 0;
-      case 0:
-      {
-       Reg1 int i;
-
-       close(pi[0]);
-       for (i = 2; i < MAXCONNECTIONS; i++)
-         if (i != pi[1])
-           close(i);
-       if (pi[1] != 2)
-         dup2(pi[1], 2);
-       dup2(2, 1);
-       if (pi[1] != 2 && pi[1] != 1)
-         close(pi[1]);
-       execlp(tmp->passwd, tmp->passwd, name, host, 0);
-       exit(-1);
-      }
-      default:
-       close(pi[1]);
-       break;
-    }
-    *reply = '\0';
-    file = fdbopen(pi[0], "r");
-    while (fbgets(temprpl, sizeof(temprpl) - 1, file))
-    {
-      if ((s = strchr(temprpl, '\n')))
-       *s = '\0';
-      if (strlen(temprpl) + strlen(reply) < sizeof(reply) - 2)
-       sprintf_irc(rplhold, "%s %s", rplhold, temprpl);
-      else
-      {
-       sendto_ops("R-line %s/%s: reply too long!", name, host);
-       break;
-      }
-    }
-    fbclose(file);
-    kill(rc, SIGKILL);         /* cleanup time */
-    wait(0);
-
-    rc = 0;
-    while (*rplhold == ' ')
-      rplhold++;
-    rplchar = *rplhold;                /* Pull out the yes or no */
-    while (*rplhold != ' ')
-      rplhold++;
-    while (*rplhold == ' ')
-      rplhold++;
-    strcpy(reply, rplhold);
-    rplhold = reply;
-
-    if ((rc = (rplchar == 'n' || rplchar == 'N')))
-      break;
-  }
-  if (rc)
-  {
-    sendto_one(cptr, ":%s %d %s :Restriction: %s",
-       me.name, ERR_YOUREBANNEDCREEP, cptr->name, reply);
-    return -1;
+  FBFILE*          file = NULL;
+  struct MotdItem* temp;
+  struct MotdItem* newmotd;
+  struct MotdItem* last;
+  struct stat      sb;
+  char             line[80];
+  char*            tmp;
+
+  if (NULL == (file = fbopen(motdfile, "r"))) {
+    Debug((DEBUG_ERROR, "Couldn't open \"%s\": %s", motdfile, strerror(errno)));
+    return NULL;
   }
-  return 0;
-}
-#endif
-
-/*
- * output the reason for being k lined from a file  - Mmmm
- * sptr is server
- * parv is the sender prefix
- * filename is the file that is to be output to the K lined client
- */
-static void killcomment(aClient *sptr, char *parv, char *filename)
-{
-  FBFILE *file = NULL;
-  char line[80];
-  Reg1 char *tmp;
-  struct stat sb;
-  struct tm *tm;
-
-  if (NULL == (file = fbopen(filename, "r")))
-  {
-    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
-    sendto_one(sptr,
-       ":%s %d %s :Connection from your host is refused on this server.",
-       me.name, ERR_YOUREBANNEDCREEP, parv);
-    return;
+  if (-1 == fbstat(&sb, file)) {
+    fbclose(file);
+    return NULL;
   }
-  fbstat(&sb, file);
-  tm = localtime((time_t *) & sb.st_mtime);    /* NetBSD needs cast */
-  while (fbgets(line, sizeof(line) - 1, file))
-  {
-    if ((tmp = strchr(line, '\n')))
+  newmotd = last = NULL;
+  motd_tm = *localtime((time_t *) & sb.st_mtime);        /* NetBSD needs cast */
+  while (fbgets(line, sizeof(line) - 1, file)) {
+    if ((tmp = (char *)strchr(line, '\n')))
       *tmp = '\0';
-    if ((tmp = strchr(line, '\r')))
+    if ((tmp = (char *)strchr(line, '\r')))
       *tmp = '\0';
-    /* sendto_one(sptr,
-     * ":%s %d %s : %s.",
-     * me.name, ERR_YOUREBANNEDCREEP, parv,line); */
-    sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line);
+    temp = (struct MotdItem*) MyMalloc(sizeof(struct MotdItem));
+    assert(0 != temp);
+    strcpy(temp->line, line);
+    temp->next = NULL;
+    if (!newmotd)
+      newmotd = temp;
+    else
+      last->next = temp;
+    last = temp;
   }
-  sendto_one(sptr,
-      ":%s %d %s :Connection from your host is refused on this server.",
-      me.name, ERR_YOUREBANNEDCREEP, parv);
   fbclose(file);
-  return;
+  return newmotd;
 }
 
+
 /*
- *  is the K line field an interval or a comment? - Mmmm
+ * Ordinary client access check. Look for conf lines which have the same
+ * status as the flags passed.
  */
-static int is_comment(char *comment)
+enum AuthorizationCheckResult conf_check_client(struct Client *cptr)
 {
-  size_t i;
-  for (i = 0; i < strlen(comment); i++)
-    if ((comment[i] != ' ') && (comment[i] != '-')
-       && (comment[i] != ',') && ((comment[i] < '0') || (comment[i] > '9')))
-      return (1);
+  int acr;
+
+  ClearAccess(cptr);
 
-  return (0);
+  if ((acr = attach_iline(cptr))) {
+    Debug((DEBUG_DNS, "ch_cl: access denied: %s[%s]", 
+          cptr->name, cptr->sockhost));
+    return acr;
+  }
+  return ACR_OK;
 }
 
 /*
- *  check against a set of time intervals
+ * check_server()
+ *
+ * Check access for a server given its name (passed in cptr struct).
+ * Must check for all C/N lines which have a name which matches the
+ * name given and a host which matches. A host alias which is the
+ * same as the server name is also acceptable in the host field of a
+ * C/N line.
+ *
+ * Returns
+ *  0 = Success
+ * -1 = Access denied
+ * -2 = Bad socket.
  */
-static int check_time_interval(char *interval, char *reply)
+int conf_check_server(struct Client *cptr)
 {
-  struct tm *tptr;
-  char *p;
-  int perm_min_hours, perm_min_minutes, perm_max_hours, perm_max_minutes;
-  int nowm, perm_min, perm_max;
+  struct ConfItem* c_conf = NULL;
+  struct SLink*    lp;
 
-  tptr = localtime(&now);
-  nowm = tptr->tm_hour * 60 + tptr->tm_min;
+  Debug((DEBUG_DNS, "sv_cl: check access for %s[%s]", 
+        cptr->name, cptr->sockhost));
 
-  while (interval)
-  {
-    p = strchr(interval, ',');
-    if (p)
-      *p = '\0';
-    if (sscanf(interval, "%2d%2d-%2d%2d", &perm_min_hours, &perm_min_minutes,
-       &perm_max_hours, &perm_max_minutes) != 4)
-    {
-      if (p)
-       *p = ',';
-      return (0);
-    }
-    if (p)
-      *(p++) = ',';
-    perm_min = 60 * perm_min_hours + perm_min_minutes;
-    perm_max = 60 * perm_max_hours + perm_max_minutes;
-    /*
-     * The following check allows intervals over midnight ...
-     */
-    if ((perm_min < perm_max)
-       ? (perm_min <= nowm && nowm <= perm_max)
-       : (perm_min <= nowm || nowm <= perm_max))
-    {
-      printf(reply,
-         ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
-         "You are not allowed to connect from",
-         perm_min_hours, perm_min_minutes, perm_max_hours, perm_max_minutes);
-      return (ERR_YOUREBANNEDCREEP);
-    }
-    if ((perm_min < perm_max)
-       ? (perm_min <= nowm + 5 && nowm + 5 <= perm_max)
-       : (perm_min <= nowm + 5 || nowm + 5 <= perm_max))
-    {
-      sprintf_irc(reply, ":%%s %%d %%s :%d minute%s%s",
-         perm_min - nowm, (perm_min - nowm) > 1 ? "s " : " ",
-         "and you will be denied for further access");
-      return (ERR_YOUWILLBEBANNED);
+  if (IsUnknown(cptr) && !attach_confs_byname(cptr, cptr->name, CONF_SERVER)) {
+    Debug((DEBUG_DNS, "No C/N lines for %s", cptr->sockhost));
+    return -1;
+  }
+  lp = cptr->confs;
+  /*
+   * We initiated this connection so the client should have a C and N
+   * line already attached after passing through the connect_server()
+   * function earlier.
+   */
+  if (IsConnecting(cptr) || IsHandshake(cptr)) {
+    c_conf = find_conf_byname(lp, cptr->name, CONF_SERVER);
+    if (!c_conf) {
+      sendto_ops("Connect Error: lost C:line for %s", cptr->name);
+      det_confs_butmask(cptr, 0);
+      return -1;
     }
-    interval = p;
   }
-  return (0);
-}
 
-aMotdItem *read_motd(char *motdfile)
-{
-  FBFILE *file = NULL;
-  register aMotdItem *temp, *newmotd, *last;
-  struct stat sb;
-  char line[80];
-  register char *tmp;
+  ClearAccess(cptr);
 
-  if (NULL == (file = fbopen(motdfile, "r")))
-  {
-    Debug((DEBUG_ERROR, "Couldn't open \"%s\": %s", motdfile, strerror(errno)));
-    return NULL;
-  }
-  if (-1 == fbstat(&sb, file))
-  {
-    return NULL;
+  if (!c_conf) {
+    if (cptr->dns_reply) {
+      int             i;
+      struct hostent* hp = cptr->dns_reply->hp;
+      const char*     name = hp->h_name;
+      /*
+       * If we are missing a C or N line from above, search for
+       * it under all known hostnames we have for this ip#.
+       */
+      for (i = 0; name; name = hp->h_aliases[i++]) {
+        if ((c_conf = find_conf_byhost(lp, name, CONF_SERVER))) {
+          ircd_strncpy(cptr->sockhost, name, HOSTLEN);
+          break;
+        }
+      }
+      if (!c_conf) {
+        for (i = 0; hp->h_addr_list[i]; i++) {
+          if ((c_conf = find_conf_byip(lp, hp->h_addr_list[i], CONF_SERVER)))
+            break;
+        }
+      }
+    }
+    else {
+      /*
+       * Check for C lines with the hostname portion the ip number
+       * of the host the server runs on. This also checks the case where
+       * there is a server connecting from 'localhost'.
+       */
+      c_conf = find_conf_byhost(lp, cptr->sockhost, CONF_SERVER);
+    }
   }
-  newmotd = last = NULL;
-  motd_tm = *localtime((time_t *) & sb.st_mtime);      /* NetBSD needs cast */
-  while (fbgets(line, sizeof(line) - 1, file))
-  {
-    if ((tmp = (char *)strchr(line, '\n')))
-      *tmp = '\0';
-    if ((tmp = (char *)strchr(line, '\r')))
-      *tmp = '\0';
-    temp = (aMotdItem *) RunMalloc(sizeof(aMotdItem));
-    if (!temp)
-      outofmemory();
-    strcpy(temp->line, line);
-    temp->next = NULL;
-    if (!newmotd)
-      newmotd = temp;
-    else
-      last->next = temp;
-    last = temp;
+  /*
+   * Attach by IP# only if all other checks have failed.
+   * It is quite possible to get here with the strange things that can
+   * happen when using DNS in the way the irc server does. -avalon
+   */
+  if (!c_conf)
+    c_conf = find_conf_byip(lp, (const char*) &cptr->ip, CONF_SERVER);
+  /*
+   * detach all conf lines that got attached by attach_confs()
+   */
+  det_confs_butmask(cptr, 0);
+  /*
+   * if no C or no N lines, then deny access
+   */
+  if (!c_conf) {
+    Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s]",
+          cptr->name, cptr->username, cptr->sockhost));
+    return -1;
   }
-  fbclose(file);
-  return newmotd;
+  ircd_strncpy(cptr->name, c_conf->name, HOSTLEN);
+  /*
+   * attach the C and N lines to the client structure for later use.
+   */
+  attach_conf(cptr, c_conf);
+  attach_confs_byname(cptr, cptr->name, CONF_HUB | CONF_LEAF | CONF_UWORLD);
+
+  if (INADDR_NONE == c_conf->ipnum.s_addr)
+    c_conf->ipnum.s_addr = cptr->ip.s_addr;
+
+  Debug((DEBUG_DNS, "sv_cl: access ok: %s[%s]", cptr->name, cptr->sockhost));
+  return 0;
 }
+
index 5ba170503a9182e5c8ab2fb90f962c342d637627..d1d66a857badb03fe8a0fa0cd8ff8bcfcc5289de 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
  */
-
-#include "sys.h"
-#if HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-#if defined(HPUX) && HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HPUX
-#include <sys/syscall.h>
-#define getrusage(a,b) syscall(SYS_GETRUSAGE, a, b)
-#endif
-#if HAVE_GETRUSAGE
-#include <sys/resource.h>
-#else
-#if HAVE_TIMES
-#include <sys/times.h>
-#endif
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdarg.h>
-#include "h.h"
-#include "struct.h"
-#include "numeric.h"
-#include "hash.h"
-#include "send.h"
-#include "s_conf.h"
+#include "s_debug.h"
+#include "channel.h"
 #include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd_alloc.h"
+#include "ircd_osdep.h"
 #include "ircd.h"
+#include "list.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "res.h"
 #include "s_bsd.h"
-#include "bsd.h"
+#include "s_conf.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
 #include "whowas.h"
-#include "s_serv.h"
-#include "res.h"
-#include "channel.h"
-#include "numnicks.h"
 
-RCSTAG_CC("$Id$");
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>     /* offsetof */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
 
 /* *INDENT-OFF* */
 
@@ -83,22 +73,22 @@ char serveropts[] = {
 #endif
     (char)('0' + (BUFFERPOOL/1000000) % 10),
 #endif
-#ifdef CHROOTDIR
+#ifdef  CHROOTDIR
     'c',
 #endif
-#ifdef CMDLINE_CONFIG
+#ifdef  CMDLINE_CONFIG
     'C',
 #endif
-#ifdef DO_ID
+#ifdef  DO_ID
     'd',
 #endif
-#ifdef DEBUGMODE
+#ifdef  DEBUGMODE
     'D',
 #endif
-#ifdef LOCOP_REHASH
+#ifdef  LOCOP_REHASH
     'e',
 #endif
-#ifdef OPER_REHASH
+#ifdef  OPER_REHASH
     'E',
 #endif
 #ifdef OPER_NO_CHAN_LIMIT
@@ -107,79 +97,76 @@ char serveropts[] = {
 #ifdef OPER_MODE_LCHAN
     'f',
 #endif
-#ifdef HUB
+#ifdef  HUB
     'H',
 #endif
 #if defined(SHOW_INVISIBLE_USERS) ||  defined(SHOW_ALL_INVISIBLE_USERS)
-#ifdef SHOW_ALL_INVISIBLE_USERS
+#ifdef  SHOW_ALL_INVISIBLE_USERS
     'I',
 #else
     'i',
 #endif
 #endif
-#ifdef OPER_KILL
-#ifdef LOCAL_KILL_ONLY
+#ifdef  OPER_KILL
+#ifdef  LOCAL_KILL_ONLY
     'k',
 #else
     'K',
 #endif
 #endif
-#ifdef LEAST_IDLE
+#ifdef  LEAST_IDLE
     'L',
 #endif
 #ifdef OPER_WALK_THROUGH_LMODES
     'l',
 #endif
-#ifdef IDLE_FROM_MSG
+#ifdef  IDLE_FROM_MSG
     'M',
 #endif
-#ifdef USEONE
+#ifdef  USEONE
     'O',
 #endif
 #ifdef NO_OPER_DEOP_LCHAN
     'o',
 #endif
-#ifdef CRYPT_OPER_PASSWORD
+#ifdef  CRYPT_OPER_PASSWORD
     'p',
 #endif
-#ifdef CRYPT_LINK_PASSWORD
+#ifdef  CRYPT_LINK_PASSWORD
     'P',
 #endif
-#ifdef DEBUGMALLOC
-#ifdef MEMLEAKSTATS
+#ifdef  DEBUGMALLOC
+#ifdef  MEMLEAKSTATS
     'Q',
 #else
     'q',
 #endif
 #endif
-#ifdef RELIABLE_CLOCK
+#ifdef  RELIABLE_CLOCK
     'R',
 #endif
-#ifdef LOCOP_RESTART
+#ifdef  LOCOP_RESTART
     's',
 #endif
-#ifdef OPER_RESTART
+#ifdef  OPER_RESTART
     'S',
 #endif
-#ifdef OPER_REMOTE
+#ifdef  OPER_REMOTE
     't',
 #endif
 #if defined(USE_POLL) && defined(HAVE_POLL_H)
     'U',
 #endif
-#ifdef VIRTUAL_HOST
+#ifdef  VIRTUAL_HOST
     'v',
 #endif
 #ifdef BADCHAN
-   'W',
+    'W',
 #ifdef LOCAL_BADCHAN
-   'w',
-#endif
+    'x',
 #endif
-#ifdef UNIXPORT
-    'X',
 #endif
-#ifdef USE_SYSLOG
+#ifdef  USE_SYSLOG
     'Y',
 #endif
     '\0'
@@ -187,6 +174,40 @@ char serveropts[] = {
 
 /* *INDENT-ON* */
 
+
+/*
+ * open_debugfile
+ *
+ * If the -t option is not given on the command line when the server is
+ * started, all debugging output is sent to the file set by LPATH in config.h
+ * Here we just open that file and make sure it is opened to fd 2 so that
+ * any fprintf's to stderr also goto the logfile.  If the debuglevel is not
+ * set from the command line by -x, use /dev/null as the dummy logfile as long
+ * as DEBUGMODE has been defined, else dont waste the fd.
+ */
+void open_debugfile(void)
+{
+#ifdef  DEBUGMODE
+  if (debuglevel >= 0) {
+    printf("isatty = %d ttyname = %#x\n", isatty(2), (unsigned int)ttyname(2));
+    if (!(bootopt & BOOT_TTY)) {
+      int fd;
+      /* 
+       * leave debugging output on fd 2
+       */
+      if ((fd = open(LOGFILE, O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0) {
+        if ((fd = open("/dev/null", O_WRONLY)) < 0)
+          exit(-1);
+      }
+      if (fd != 2) {
+        dup2(fd, 2);
+        close(fd);
+      }
+    }
+  }
+#endif
+}
+
 #ifdef DEBUGMODE
 static char debugbuf[1024];
 
@@ -197,13 +218,7 @@ void vdebug(int level, const char *form, va_list vl)
   if ((debuglevel >= 0) && (level <= debuglevel))
   {
     vsprintf(debugbuf, form, vl);
-    if (loc_clients[2])
-    {
-      loc_clients[2]->sendM++;
-      loc_clients[2]->sendB += strlen(debugbuf);
-    }
-    fprintf(stderr, "%s", debugbuf);
-    fputc('\n', stderr);
+    fprintf(stderr, "%s\n", debugbuf);
   }
   errno = err;
 }
@@ -216,6 +231,12 @@ void debug(int level, const char *form, ...)
   va_end(vl);
 }
 
+static void debug_enumerator(struct Client* cptr, const char* msg)
+{
+  assert(0 != cptr);
+  sendto_one(cptr, ":%s %d %s :%s", me.name, RPL_STATSDEBUG, cptr->name, msg);
+}
+
 /*
  * 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.
@@ -223,161 +244,64 @@ void debug(int level, const char *form, ...)
  * different field names for "struct rusage".
  * -avalon
  */
-void send_usage(aClient *cptr, char *nick)
+void send_usage(struct Client *cptr, char *nick)
 {
+  os_get_rusage(cptr, CurrentTime - me.since, debug_enumerator);
 
-#if HAVE_GETRUSAGE
-  struct rusage rus;
-  time_t secs, rup;
-#ifdef hz
-#define hzz hz
-#else
-#ifdef HZ
-#define hzz HZ
-#else
-  int hzz = 1;
-#ifdef HPUX
-  hzz = (int)sysconf(_SC_CLK_TCK);
-#endif
-#endif
-#endif
-
-  if (getrusage(RUSAGE_SELF, &rus) == -1)
-  {
-    if (MyUser(cptr) || Protocol(cptr->from) < 10)
-      sendto_one(cptr, ":%s NOTICE %s :Getruseage error: %s.",
-         me.name, nick, sys_errlist[errno]);
-    else
-      sendto_one(cptr, "%s NOTICE %s%s :Getruseage error: %s.",
-         NumServ(&me), NumNick(cptr), sys_errlist[errno]);
-    return;
-  }
-  secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
-  rup = now - me.since;
-  if (secs == 0)
-    secs = 1;
-
-#if defined(__sun__) || defined(__bsdi__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
-  sendto_one(cptr, ":%s %d %s :CPU Secs %ld:%ld User %ld:%ld System %ld:%ld",
-#else
-  sendto_one(cptr, ":%s %d %s :CPU Secs %ld:%ld User %d:%d System %d:%d",
-#endif
-      me.name, RPL_STATSDEBUG, nick, secs / 60, secs % 60,
-      rus.ru_utime.tv_sec / 60, rus.ru_utime.tv_sec % 60,
-      rus.ru_stime.tv_sec / 60, rus.ru_stime.tv_sec % 60);
-  sendto_one(cptr, ":%s %d %s :RSS %ld ShMem %ld Data %ld Stack %ld",
-      me.name, RPL_STATSDEBUG, nick, rus.ru_maxrss,
-      rus.ru_ixrss / (rup * hzz), rus.ru_idrss / (rup * hzz),
-      rus.ru_isrss / (rup * hzz));
-  sendto_one(cptr, ":%s %d %s :Swaps %ld Reclaims %ld Faults %ld",
-      me.name, RPL_STATSDEBUG, nick, rus.ru_nswap,
-      rus.ru_minflt, rus.ru_majflt);
-  sendto_one(cptr, ":%s %d %s :Block in %ld out %ld",
-      me.name, RPL_STATSDEBUG, nick, rus.ru_inblock, rus.ru_oublock);
-  sendto_one(cptr, ":%s %d %s :Msg Rcv %ld Send %ld",
-      me.name, RPL_STATSDEBUG, nick, rus.ru_msgrcv, rus.ru_msgsnd);
-  sendto_one(cptr, ":%s %d %s :Signals %ld Context Vol. %ld Invol %ld",
-      me.name, RPL_STATSDEBUG, nick, rus.ru_nsignals,
-      rus.ru_nvcsw, rus.ru_nivcsw);
-#else /* HAVE_GETRUSAGE */
-#if HAVE_TIMES
-  struct tms tmsbuf;
-  time_t secs, mins;
-  int hzz = 1, ticpermin;
-  int umin, smin, usec, ssec;
-
-#ifdef HPUX
-  hzz = sysconf(_SC_CLK_TCK);
-#endif
-  ticpermin = hzz * 60;
-
-  umin = tmsbuf.tms_utime / ticpermin;
-  usec = (tmsbuf.tms_utime % ticpermin) / (float)hzz;
-  smin = tmsbuf.tms_stime / ticpermin;
-  ssec = (tmsbuf.tms_stime % ticpermin) / (float)hzz;
-  secs = usec + ssec;
-  mins = (secs / 60) + umin + smin;
-  secs %= hzz;
-
-  if (times(&tmsbuf) == -1)
-  {
-    sendto_one(cptr, ":%s %d %s :times(2) error: %s.",
-       me.name, RPL_STATSDEBUG, nick, strerror(errno));
-    return;
-  }
-  secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
-
-  sendto_one(cptr, ":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
-      me.name, RPL_STATSDEBUG, nick, mins, secs, umin, usec, smin, ssec);
-#endif /* HAVE_TIMES */
-#endif /* HAVE_GETRUSAGE */
-  sendto_one(cptr, ":%s %d %s :Reads %d Writes %d",
-      me.name, RPL_STATSDEBUG, nick, readcalls, writecalls);
   sendto_one(cptr, ":%s %d %s :DBUF alloc %d used %d",
       me.name, RPL_STATSDEBUG, nick, DBufAllocCount, DBufUsedCount);
-  sendto_one(cptr,
-      ":%s %d %s :Writes:  <0 %d 0 %d <16 %d <32 %d <64 %d",
-      me.name, RPL_STATSDEBUG, nick,
-      writeb[0], writeb[1], writeb[2], writeb[3], writeb[4]);
-  sendto_one(cptr,
-      ":%s %d %s :<128 %d <256 %d <512 %d <1024 %d >1024 %d",
-      me.name, RPL_STATSDEBUG, nick,
-      writeb[5], writeb[6], writeb[7], writeb[8], writeb[9]);
-  return;
 }
 #endif /* DEBUGMODE */
 
-void count_memory(aClient *cptr, char *nick)
+void count_memory(struct Client *cptr, char *nick)
 {
-  Reg1 aClient *acptr;
-  Reg2 Link *link;
-  Reg3 aChannel *chptr;
-  Reg4 aConfItem *aconf;
-  Reg5 aConfClass *cltmp;
-
-  int lc = 0,                  /* local clients */
-      ch = 0,                  /* channels */
-      lcc = 0,                 /* local client conf links */
-      rc = 0,                  /* remote clients */
-      us = 0,                  /* user structs */
-      chu = 0,                 /* channel users */
-      chi = 0,                 /* channel invites */
-      chb = 0,                 /* channel bans */
-      wwu = 0,                 /* whowas users */
-      cl = 0,                  /* classes */
-      co = 0;                  /* conf lines */
-
-  int usi = 0,                 /* users invited */
-      usc = 0,                 /* users in channels */
-      aw = 0,                  /* aways set */
-      wwa = 0;                 /* whowas aways */
-
-  size_t chm = 0,              /* memory used by channels */
-      chbm = 0,                        /* memory used by channel bans */
-      lcm = 0,                 /* memory used by local clients */
-      rcm = 0,                 /* memory used by remote clients */
-      awm = 0,                 /* memory used by aways */
-      wwam = 0,                        /* whowas away memory used */
-      wwm = 0,                 /* whowas array memory used */
-      com = 0,                 /* memory used by conf lines */
-      dbufs_allocated = 0,     /* memory used by dbufs */
-      dbufs_used = 0,          /* memory used by dbufs */
-      rm = 0,                  /* res memory used */
+  struct Client *acptr;
+  struct SLink *link;
+  struct Channel *chptr;
+  struct ConfItem *aconf;
+  struct ConfClass *cltmp;
+  struct Membership* member;
+
+  int lc = 0,                   /* local clients */
+      ch = 0,                   /* channels */
+      lcc = 0,                  /* local client conf links */
+      rc = 0,                   /* remote clients */
+      us = 0,                   /* user structs */
+      chi = 0,                  /* channel invites */
+      chb = 0,                  /* channel bans */
+      wwu = 0,                  /* whowas users */
+      cl = 0,                   /* classes */
+      co = 0                  /* conf lines */
+      memberships = 0;          /* channel memberships */
+
+  int usi = 0,                  /* users invited */
+      aw = 0,                   /* aways set */
+      wwa = 0;                  /* whowas aways */
+
+  size_t chm = 0,               /* memory used by channels */
+      chbm = 0,                 /* memory used by channel bans */
+      lcm = 0,                  /* memory used by local clients */
+      rcm = 0,                  /* memory used by remote clients */
+      awm = 0,                  /* memory used by aways */
+      wwam = 0,                 /* whowas away memory used */
+      wwm = 0,                  /* whowas array memory used */
+      com = 0,                  /* memory used by conf lines */
+      dbufs_allocated = 0,      /* memory used by dbufs */
+      dbufs_used = 0,           /* memory used by dbufs */
+      rm = 0,                   /* res memory used */
       totcl = 0, totch = 0, totww = 0, tot = 0;
 
   count_whowas_memory(&wwu, &wwm, &wwa, &wwam);
-  wwm += sizeof(aWhowas) * NICKNAMEHISTORYLENGTH;
-  wwm += sizeof(aWhowas *) * WW_MAX;
+  wwm += sizeof(struct Whowas) * NICKNAMEHISTORYLENGTH;
+  wwm += sizeof(struct Whowas *) * WW_MAX;
 
-  for (acptr = client; acptr; acptr = acptr->next)
+  for (acptr = GlobalClientList; acptr; acptr = acptr->next)
   {
-    if (IsPing(acptr))
-      continue;
     if (MyConnect(acptr))
     {
       lc++;
       for (link = acptr->confs; link; link = link->next)
-       lcc++;
+        lcc++;
     }
     else
       rc++;
@@ -385,41 +309,46 @@ void count_memory(aClient *cptr, char *nick)
     {
       us++;
       for (link = acptr->user->invited; link; link = link->next)
-       usi++;
-      for (link = acptr->user->channel; link; link = link->next)
-       usc++;
+        usi++;
+      for (member = acptr->user->channel; member; member = member->next_channel)
+        ++memberships;
       if (acptr->user->away)
       {
-       aw++;
-       awm += (strlen(acptr->user->away) + 1);
+        aw++;
+        awm += (strlen(acptr->user->away) + 1);
       }
     }
   }
   lcm = lc * CLIENT_LOCAL_SIZE;
   rcm = rc * CLIENT_REMOTE_SIZE;
 
-  for (chptr = channel; chptr; chptr = chptr->nextch)
+  for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
   {
     ch++;
-    chm += (strlen(chptr->chname) + sizeof(aChannel));
-    for (link = chptr->members; link; link = link->next)
+    chm += (strlen(chptr->chname) + sizeof(struct Channel));
+#if 0
+    /*
+     * XXX - Members already counted in clients, don't count twice
+     */
+    for (member = chptr->members; member; member = member->next_member)
       chu++;
+#endif
     for (link = chptr->invites; link; link = link->next)
       chi++;
     for (link = chptr->banlist; link; link = link->next)
     {
       chb++;
-      chbm += (strlen(link->value.cp) + 1 + sizeof(Link));
+      chbm += (strlen(link->value.cp) + 1 + sizeof(struct SLink));
     }
   }
 
-  for (aconf = conf; aconf; aconf = aconf->next)
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next)
   {
     co++;
     com += aconf->host ? strlen(aconf->host) + 1 : 0;
     com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0;
     com += aconf->name ? strlen(aconf->name) + 1 : 0;
-    com += sizeof(aConfItem);
+    com += sizeof(struct ConfItem);
   }
 
   for (cltmp = classes; cltmp; cltmp = cltmp->next)
@@ -430,40 +359,40 @@ void count_memory(aClient *cptr, char *nick)
       me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm);
   sendto_one(cptr, ":%s %d %s :Users %d(" SIZE_T_FMT
       ") Invites %d(" SIZE_T_FMT ")",
-      me.name, RPL_STATSDEBUG, nick, us, us * sizeof(anUser), usi,
-      usi * sizeof(Link));
-  sendto_one(cptr, ":%s %d %s :User channels %d(" SIZE_T_FMT
-      ") Aways %d(" SIZE_T_FMT ")",
-      me.name, RPL_STATSDEBUG, nick, usc, usc * sizeof(Link), aw, awm);
+      me.name, RPL_STATSDEBUG, nick, us, us * sizeof(struct User), usi,
+      usi * sizeof(struct SLink));
+  sendto_one(cptr, 
+             ":%s %d %s :User channels %d(" SIZE_T_FMT ") Aways %d(" SIZE_T_FMT ")",
+             me.name, RPL_STATSDEBUG, nick, memberships,
+             memberships * sizeof(struct Membership), aw, awm);
   sendto_one(cptr, ":%s %d %s :Attached confs %d(" SIZE_T_FMT ")",
-      me.name, RPL_STATSDEBUG, nick, lcc, lcc * sizeof(Link));
+      me.name, RPL_STATSDEBUG, nick, lcc, lcc * sizeof(struct SLink));
 
-  totcl = lcm + rcm + us * sizeof(anUser) + usc * sizeof(Link) + awm;
-  totcl += lcc * sizeof(Link) + usi * sizeof(Link);
+  totcl = lcm + rcm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm;
+  totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink);
 
   sendto_one(cptr, ":%s %d %s :Conflines %d(" SIZE_T_FMT ")",
       me.name, RPL_STATSDEBUG, nick, co, com);
 
   sendto_one(cptr, ":%s %d %s :Classes %d(" SIZE_T_FMT ")",
-      me.name, RPL_STATSDEBUG, nick, cl, cl * sizeof(aConfClass));
+      me.name, RPL_STATSDEBUG, nick, cl, cl * sizeof(struct ConfClass));
 
   sendto_one(cptr, ":%s %d %s :Channels %d(" SIZE_T_FMT
       ") Bans %d(" SIZE_T_FMT ")",
       me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm);
-  sendto_one(cptr, ":%s %d %s :Channel membrs %d(" SIZE_T_FMT
-      ") invite %d(" SIZE_T_FMT ")",
-      me.name, RPL_STATSDEBUG, nick, chu, chu * sizeof(Link),
-      chi, chi * sizeof(Link));
+  sendto_one(cptr, ":%s %d %s :Channel membrs %d(" SIZE_T_FMT ") invite %d(" SIZE_T_FMT ")",
+      me.name, RPL_STATSDEBUG, nick, memberships, memberships * sizeof(struct Membership),
+      chi, chi * sizeof(struct SLink));
 
-  totch = chm + chbm + chu * sizeof(Link) + chi * sizeof(Link);
+  totch = chm + chbm + chi * sizeof(struct SLink);
 
   sendto_one(cptr, ":%s %d %s :Whowas users %d(" SIZE_T_FMT
       ") away %d(" SIZE_T_FMT ")",
-      me.name, RPL_STATSDEBUG, nick, wwu, wwu * sizeof(anUser), wwa, wwam);
+      me.name, RPL_STATSDEBUG, nick, wwu, wwu * sizeof(struct User), wwa, wwam);
   sendto_one(cptr, ":%s %d %s :Whowas array %d(" SIZE_T_FMT ")",
       me.name, RPL_STATSDEBUG, nick, NICKNAMEHISTORYLENGTH, wwm);
 
-  totww = wwu * sizeof(anUser) + wwam + wwm;
+  totww = wwu * sizeof(struct User) + wwam + wwm;
 
   sendto_one(cptr, ":%s %d %s :Hash: client %d(" SIZE_T_FMT
       "), chan is the same",
@@ -486,139 +415,18 @@ void count_memory(aClient *cptr, char *nick)
   rm = cres_mem(cptr);
 
   tot =
-      totww + totch + totcl + com + cl * sizeof(aConfClass) + dbufs_allocated +
+      totww + totch + totcl + com + cl * sizeof(struct ConfClass) + dbufs_allocated +
       rm;
   tot += sizeof(void *) * HASHSIZE * 3;
 
+#if !defined(NDEBUG)
+  sendto_one(cptr, ":%s %d %s :Allocations: " SIZE_T_FMT "(" SIZE_T_FMT ")",
+             me.name, RPL_STATSDEBUG, nick, fda_get_block_count(),
+             fda_get_byte_count());
+#endif
+
   sendto_one(cptr, ":%s %d %s :Total: ww " SIZE_T_FMT " ch " SIZE_T_FMT
       " cl " SIZE_T_FMT " co " SIZE_T_FMT " db " SIZE_T_FMT,
       me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, com, dbufs_allocated);
-  return;
-}
-
-#ifdef MSGLOG_ENABLED
-
-/* Define here what level of messages you want to log */
-#define LOG_MASK_LEVEL LEVEL_MODE      /* This that change some data */
-
-static struct log_entry log_table[MSGLOG_SIZE];
-
-static int unused_log_entries = MSGLOG_SIZE;
-static int last_log_entry = -1;        /* Nothing stored yet */
-static int entry_stored_forlog = 0;    /* Just a flag */
-
-/*
- * RollBackMsgLog
- *
- * Just a little utility function used to retract
- * an half stored Message log entry
- */
-void RollBackMsgLog(void)
-{
-  /* We won't log this, abort and free the entry */
-  last_log_entry--;
-  unused_log_entries++;
-  return;
-}
-
-/*
- * Log_Message (macroed as LogMessage)
- *
- * Permanently stores a log entry into the recent log memory area
- * Store_Buffer MUST have been called before calling Log_Message
- */
-void Log_Message(aClient *sptr, int msgclass)
-{
-  register int n = last_log_entry;
-
-  /* Clear our flag, since we are going to
-   * finish the processing of this entry */
-  entry_stored_forlog = 0;
-
-  /* Check  if the level of this message is high enough */
-  if (msgclass < LOG_MASK_LEVEL)
-  {
-    RollBackMsgLog();
-    return;
-  }
-
-  /* Check if we wanna log the type of connection from
-   * where this message did come from */
-  if (!((0x8000 >> (8 + log_table[n].cptr_status)) & LOG_MASK_TYPE))
-  {
-    RollBackMsgLog();
-    return;
-  }
-
-  /* Complete the entry */
-  if (sptr)
-  {
-    log_table[n].sptr_status = sptr->status;
-    strncpy(log_table[n].sptr_name, sptr->name, HOSTLEN);
-    log_table[n].sptr_name[HOSTLEN] = '\0';
-    strncpy(log_table[n].sptr_yxx, sptr->yxx, 4);
-    log_table[n].sptr = sptr;
-
-    if (sptr->from)
-    {
-      strncpy(log_table[n].sptr_from_name, sptr->name, HOSTLEN);
-      log_table[n].sptr_from_name[HOSTLEN] = '\0';
-    }
-    else
-    {
-      memset(log_table[n].sptr_from_name, 0, HOSTLEN);
-    }
-  }
-  else
-  {
-    log_table[n].sptr_status = 0xFF;   /* Dummy value */
-    memset(&log_table[n].sptr_name, 0, HOSTLEN);
-    memset(log_table[n].sptr_yxx, 0, 4);
-
-    log_table[n].sptr = 0;
-    memset(&log_table[n].sptr_from_name, 0, HOSTLEN);
-  }
-}
-
-/*
- * Store_Buffer (macroed as StoreBuffer)
- *
- * Saves the buffer and cptr info at the very first stage
- * of parsing, if Log_Message doesn't get called between
- * two Store_Buffer calls this function assumes that the parser
- * has rejected the message and therefore calls Log_Message
- * as if the message class was 0 and the sptr null
- */
-void Store_Buffer(char *buf, aClient *cptr)
-{
-  register int n;
-
-  /* Check if we have an entry pending, if so
-   * complete it's processing */
-  if (entry_stored_forlog)
-    Log_Message((aClient *)NULL, 0);
-
-  /* Update the "half used entry" flag */
-  entry_stored_forlog = 1;
-
-  /* First update the free entries counter */
-  if (unused_log_entries)
-    unused_log_entries--;
-
-  /* Get an entry */
-  n = (last_log_entry + 1) % MSGLOG_SIZE;
-
-  /* Update the last_log_entry index */
-  last_log_entry = n;
-
-  /* Store what we have by now in it */
-  log_table[n].cptr_status = cptr->status;
-  strncpy(log_table[n].cptr_name, cptr->name, HOSTLEN);
-  log_table[n].cptr_name[HOSTLEN] = '\0';
-  strncpy(log_table[n].cptr_yxx, cptr->yxx, 4);
-  log_table[n].cptr_fd = cptr->fd;
-  log_table[n].cptr = cptr;    /* No checking for this, is lossy */
-  strncpy(log_table[n].buffer, buf, 511);
 }
 
-#endif /* MSGLOG_ENABLED */
index 96894158677f5d564345e1596ef9edfd6359e7fc..a9ba4cd7a5495098ff7f7526b57ff01e1d647395 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
 #include "numeric.h"
-#include "s_err.h"
+#include "s_debug.h"
 #include "sprintf_irc.h"
 
-RCSTAG_CC("$Id$");
-
-typedef struct {
-  int num_val;
-  char *num_form;
-} Numeric;
-
-/* *INDENT-OFF* */
+#include <assert.h>
 
 static Numeric local_replies[] = {
 /* 000 */
-    {0, (char *)NULL},
+  { 0 },
 /* 001 */
-    {RPL_WELCOME, ":Welcome to the Internet Relay Network %s"},
+  { RPL_WELCOME, ":Welcome to the Internet Relay Network %s", "001" },
 /* 002 */
-    {RPL_YOURHOST, ":Your host is %s, running version %s"},
+  { RPL_YOURHOST, ":Your host is %s, running version %s", "002" },
 /* 003 */
-    {RPL_CREATED, ":This server was created %s"},
+  { RPL_CREATED, ":This server was created %s", "003" },
 /* 004 */
-    {RPL_MYINFO, "%s %s dioswkg biklmnopstv"},
+  { RPL_MYINFO, "%s %s dioswkg biklmnopstv", "004" },
 /* 005 */
-    {RPL_MAP, ":%s%s"},
+  { RPL_ISUPPORT, "%s :are supported by this server", "005" },
 /* 006 */
-    {RPL_MAPMORE, ":%s%s --> *more*"},
+  { 0 },
 /* 007 */
-    {RPL_MAPEND, ":End of /MAP"},
+  { 0 },
 /* 008 */
-    {RPL_SNOMASK, "%d :: Server notice mask (%#x)"},
+  { RPL_SNOMASK, "%d :: Server notice mask (%#x)", "008" },
 /* 009 */
-    {RPL_STATMEMTOT, "%u %u :Bytes Blocks"},
+  { RPL_STATMEMTOT, "%u %u :Bytes Blocks", "009" },
 /* 010 */
 #ifdef MEMSIZESTATS
-    {RPL_STATMEM, "%u %u %s %u"},
+  { RPL_STATMEM, "%u %u %s %u", "010" },
 #else
-    {RPL_STATMEM, "%u %u %s"},
+  { RPL_STATMEM, "%u %u %s", "010" },
 #endif
-    {0, (char *)NULL}
+/* 011 */
+  { 0 },
+/* 012 */
+  { 0 },
+/* 013 */
+  { 0 },
+/* 014 */
+  { 0 },
+/* 015 */
+  { RPL_MAP, ":%s%s:%s (%is) [%i clients]", "015" },
+/* 016 */
+  { RPL_MAPMORE, ":%s%s --> *more*", "016" },
+/* 017 */
+  { RPL_MAPEND, ":End of /MAP", "017" },
+  { 0 }
 };
 
 static Numeric numeric_errors[] = {
+/* 400 */
+  { ERR_FIRSTERROR, "", "400" },
 /* 401 */
-    {ERR_NOSUCHNICK, "%s :No such nick"},
+  { ERR_NOSUCHNICK, "%s :No such nick", "401" },
 /* 402 */
-    {ERR_NOSUCHSERVER, "%s :No such server"},
+  { ERR_NOSUCHSERVER, "%s :No such server", "402" },
 /* 403 */
-    {ERR_NOSUCHCHANNEL, "%s :No such channel"},
+  { ERR_NOSUCHCHANNEL, "%s :No such channel", "403" },
 /* 404 */
-    {ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel"},
+  { ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel", "404" },
 /* 405 */
-    {ERR_TOOMANYCHANNELS, "%s :You have joined too many channels"},
+  { ERR_TOOMANYCHANNELS, "%s :You have joined too many channels", "405" },
 /* 406 */
-    {ERR_WASNOSUCHNICK, "%s :There was no such nickname"},
+  { ERR_WASNOSUCHNICK, "%s :There was no such nickname", "406" },
 /* 407 */
-    {ERR_TOOMANYTARGETS, "%s :Duplicate recipients. No message delivered"},
+  { ERR_TOOMANYTARGETS, "%s :Duplicate recipients. No message delivered", "407" },
 /* 408 */
-    {0, (char *)NULL},
+  { 0 },
 /* 409 */
-    {ERR_NOORIGIN, ":No origin specified"},
+  { ERR_NOORIGIN, ":No origin specified", "409" },
 /* 410 */
-    {0, (char *)NULL},
+  { 0 },
 /* 411 */
-    {ERR_NORECIPIENT, ":No recipient given (%s)"},
+  { ERR_NORECIPIENT, ":No recipient given (%s)", "411" },
 /* 412 */
-    {ERR_NOTEXTTOSEND, ":No text to send"},
+  { ERR_NOTEXTTOSEND, ":No text to send", "412" },
 /* 413 */
-    {ERR_NOTOPLEVEL, "%s :No toplevel domain specified"},
+  { ERR_NOTOPLEVEL, "%s :No toplevel domain specified", "413" },
 /* 414 */
-    {ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain"},
+  { ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain", "414" },
 /* 415 */
-    {0, (char *)NULL},
+  { 0 },
 /* 416 */
-    {ERR_QUERYTOOLONG, "%s :Too many lines in the output, restrict your query"},
+  { ERR_QUERYTOOLONG, "%s :Too many lines in the output, restrict your query", "416" },
 /* 417 */
-    {0, (char *)NULL},
+  { 0 },
 /* 418 */
-    {0, (char *)NULL},
+  { 0 },
 /* 419 */
-    {0, (char *)NULL},
+  { 0 },
 /* 420 */
-    {0, (char *)NULL},
+  { 0 },
 /* 421 */
-    {ERR_UNKNOWNCOMMAND, "%s :Unknown command"},
+  { ERR_UNKNOWNCOMMAND, "%s :Unknown command", "421" },
 /* 422 */
-    {ERR_NOMOTD, ":MOTD File is missing"},
+  { ERR_NOMOTD, ":MOTD File is missing", "422" },
 /* 423 */
-    {ERR_NOADMININFO, "%s :No administrative info available"},
+  { ERR_NOADMININFO, "%s :No administrative info available", "423" },
 /* 424 */
-    {0, (char *)NULL},
+  { 0 },
 /* 425 */
-    {0, (char *)NULL},
+  { 0 },
 /* 426 */
-    {0, (char *)NULL},
+  { 0 },
 /* 427 */
-    {0, (char *)NULL},
+  { 0 },
 /* 428 */
-    {0, (char *)NULL},
+  { 0 },
 /* 429 */
-    {0, (char *)NULL},
+  { 0 },
 /* 430 */
-    {0, (char *)NULL},
+  { 0 },
 /* 431 */
-    {ERR_NONICKNAMEGIVEN, ":No nickname given"},
+  { ERR_NONICKNAMEGIVEN, ":No nickname given", "431" },
 /* 432 */
-    {ERR_ERRONEUSNICKNAME, "%s :Erroneus Nickname"},
+  { ERR_ERRONEUSNICKNAME, "%s :Erroneus Nickname", "432" },
 /* 433 */
-    {ERR_NICKNAMEINUSE, "%s :Nickname is already in use."},
+  { ERR_NICKNAMEINUSE, "%s :Nickname is already in use.", "433" },
 /* 434 */
-    {0, (char *)NULL},
+  { 0 },
 /* 435 */
-    {0, (char *)NULL},
+  { 0 },
 /* 436 */
-    {ERR_NICKCOLLISION, "%s :Nickname collision KILL"},
+  { ERR_NICKCOLLISION, "%s :Nickname collision KILL", "436" },
 /* 437 */
-    {ERR_BANNICKCHANGE, "%s :Cannot change nickname while banned on channel"},
+  { ERR_BANNICKCHANGE, "%s :Cannot change nickname while banned on channel", "437" },
 /* 438 */
-    {ERR_NICKTOOFAST, "%s :Nick change too fast. Please wait %d seconds."},
+  { ERR_NICKTOOFAST, "%s :Nick change too fast. Please wait %d seconds.", "438" },
 /* 439 */
-    {ERR_TARGETTOOFAST, "%s :Target change too fast. Please wait %d seconds."},
+  { ERR_TARGETTOOFAST, "%s :Target change too fast. Please wait %d seconds.", "439" },
 /* 440 */
-    {0, (char *)NULL},
+  { 0 },
 /* 441 */
-    {ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel"},
+  { ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel", "441" },
 /* 442 */
-    {ERR_NOTONCHANNEL, "%s :You're not on that channel"},
+  { ERR_NOTONCHANNEL, "%s :You're not on that channel", "442" },
 /* 443 */
-    {ERR_USERONCHANNEL, "%s %s :is already on channel"},
+  { ERR_USERONCHANNEL, "%s %s :is already on channel", "443" },
 /* 444 */
-    {0, (char *)NULL},
+  { 0 },
 /* 445 */
-    {0, (char *)NULL},
+  { 0 },
 /* 446 */
-    {0, (char *)NULL},
+  { 0 },
 /* 447 */
-    {0, (char *)NULL},
+  { 0 },
 /* 448 */
-    {0, (char *)NULL},
+  { 0 },
 /* 449 */
-    {0, (char *)NULL},
+  { 0 },
 /* 450 */
-    {0, (char *)NULL},
+  { 0 },
 /* 451 */
-    {ERR_NOTREGISTERED, ":You have not registered"},
+  { ERR_NOTREGISTERED, ":You have not registered", "451" },
 /* 452 */
-    {0, (char *)NULL},
+  { 0 },
 /* 453 */
-    {0, (char *)NULL},
+  { 0 },
 /* 454 */
-    {0, (char *)NULL},
+  { 0 },
 /* 455 */
-    {0, (char *)NULL},
+  { 0 },
 /* 456 */
-    {0, (char *)NULL},
+  { 0 },
 /* 457 */
-    {0, (char *)NULL},
+  { 0 },
 /* 458 */
-    {0, (char *)NULL},
+  { 0 },
 /* 459 */
-    {0, (char *)NULL},
+  { 0 },
 /* 460 */
-    {0, (char *)NULL},
+  { 0 },
 /* 461 */
-    {ERR_NEEDMOREPARAMS, "%s :Not enough parameters"},
+  { ERR_NEEDMOREPARAMS, "%s :Not enough parameters", "461" },
 /* 462 */
-    {ERR_ALREADYREGISTRED, ":You may not reregister"},
+  { ERR_ALREADYREGISTRED, ":You may not reregister", "462" },
 /* 463 */
-    {ERR_NOPERMFORHOST, ":Your host isn't among the privileged"},
+  { ERR_NOPERMFORHOST, ":Your host isn't among the privileged", "463" },
 /* 464 */
-    {ERR_PASSWDMISMATCH, ":Password Incorrect"},
+  { ERR_PASSWDMISMATCH, ":Password Incorrect", "464" },
 /* 465 */
-    {ERR_YOUREBANNEDCREEP, ":You are banned from this server"},
+  { ERR_YOUREBANNEDCREEP, ":You are banned from this server", "465" },
 /* 466 */
-    {ERR_YOUWILLBEBANNED, (char *)NULL},
+  { ERR_YOUWILLBEBANNED, "", "466" },
 /* 467 */
-    {ERR_KEYSET, "%s :Channel key already set"},
+  { ERR_KEYSET, "%s :Channel key already set", "467" },
 /* 468 */
-    {ERR_INVALIDUSERNAME, (char *)NULL},
+  { ERR_INVALIDUSERNAME, "", "468" },
 /* 469 */
-    {0, (char *)NULL},
+  { 0 },
 /* 470 */
-    {0, (char *)NULL},
+  { 0 },
 /* 471 */
-    {ERR_CHANNELISFULL, "%s :Cannot join channel (+l)"},
+  { ERR_CHANNELISFULL, "%s :Cannot join channel (+l)", "471" },
 /* 472 */
-    {ERR_UNKNOWNMODE, "%c :is unknown mode char to me"},
+  { ERR_UNKNOWNMODE, "%c :is unknown mode char to me", "472" },
 /* 473 */
-    {ERR_INVITEONLYCHAN, "%s :Cannot join channel (+i)"},
+  { ERR_INVITEONLYCHAN, "%s :Cannot join channel (+i)", "473" },
 /* 474 */
-    {ERR_BANNEDFROMCHAN, "%s :Cannot join channel (+b)"},
+  { ERR_BANNEDFROMCHAN, "%s :Cannot join channel (+b)", "474" },
 /* 475 */
-    {ERR_BADCHANNELKEY, "%s :Cannot join channel (+k)"},
+  { ERR_BADCHANNELKEY, "%s :Cannot join channel (+k)", "475" },
 /* 476 */
-    {ERR_BADCHANMASK, "%s :Bad Channel Mask"},
+  { ERR_BADCHANMASK, "%s :Bad Channel Mask", "476" },
 /* 477 */
-    {0, (char *)NULL},
+  { 0 },
 /* 478 */
-    {ERR_BANLISTFULL, "%s %s :Channel ban/ignore list is full"},
+  { ERR_BANLISTFULL, "%s %s :Channel ban/ignore list is full", "478" },
 /* 479 */
-    {ERR_BADCHANNAME, "%s :Cannot join channel (access denied on this server)"},
+  { ERR_BADCHANNAME, "%s :Cannot join channel (access denied on this server)", "479" },
 /* 480 */
-    {0, (char *)NULL},
+  { 0 },
 /* 481 */
-    {ERR_NOPRIVILEGES, ":Permission Denied- You're not an IRC operator"},
+  { ERR_NOPRIVILEGES, ":Permission Denied: You're not an IRC operator", "481" },
 /* 482 */
-    {ERR_CHANOPRIVSNEEDED, "%s :You're not channel operator"},
+  { ERR_CHANOPRIVSNEEDED, "%s :You're not channel operator", "482" },
 /* 483 */
-    {ERR_CANTKILLSERVER, ":You cant kill a server!"},
+  { ERR_CANTKILLSERVER, ":You cant kill a server!", "483" },
 /* 484 */
-    {ERR_ISCHANSERVICE, "%s %s :Cannot kill, kick or deop channel service"},
+  { ERR_ISCHANSERVICE, "%s %s :Cannot kill, kick or deop channel service", "484" },
 /* 485 */
-    {0, (char *)NULL},
+  { 0 },
 /* 486 */
-    {0, (char *)NULL},
+  { 0 },
 /* 487 */
-    {0, (char *)NULL},
+  { 0 },
 /* 488 */
-    {0, (char *)NULL},
+  { 0 },
 /* 489 */
-    {ERR_VOICENEEDED, "%s :You're neither voiced nor channel operator"},
+  { ERR_VOICENEEDED, "%s :You're neither voiced nor channel operator", "489" },
 /* 490 */
-    {0, (char *)NULL},
+  { 0 },
 /* 491 */
-    {ERR_NOOPERHOST, ":No O-lines for your host"},
+  { ERR_NOOPERHOST, ":No O-lines for your host", "491" },
 /* 492 */
-    {0, (char *)NULL},
+  { 0 },
 /* 493 */
-    {0, (char *)NULL},
+  { 0 },
 /* 494 */
-    {0, (char *)NULL},
+  { 0 },
 /* 495 */
-    {0, (char *)NULL},
+  { 0 },
 /* 496 */
-    {0, (char *)NULL},
+  { 0 },
 /* 497 */
-    {0, (char *)NULL},
+  { 0 },
 /* 498 */
-    {ERR_ISOPERLCHAN, "%s %s :Cannot kick or deop an IRC Operator on a local channel"},
+  { ERR_ISOPERLCHAN, "%s %s :Cannot kick or deop an IRC Operator on a local channel", "498" },
 /* 499 */
-    {0, (char *)NULL},
+  { 0 },
 /* 500 */
-    {0, (char *)NULL},
+  { 0 },
 /* 501 */
-    {ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag"},
+  { ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag", "501" },
 /* 502 */
-    {ERR_USERSDONTMATCH, ":Cant change mode for other users"},
+  { ERR_USERSDONTMATCH, ":Cant change mode for other users", "502" },
 /* 503 */
-    {0, (char *)NULL},
+  { 0 },
 /* 504 */
-    {0, (char *)NULL},
+  { 0 },
 /* 505 */
-    {0, (char *)NULL},
+  { 0 },
 /* 506 */
-    {0, (char *)NULL},
+  { 0 },
 /* 507 */
-    {0, (char *)NULL},
+  { 0 },
 /* 508 */
-    {0, (char *)NULL},
+  { 0 },
 /* 509 */
-    {0, (char *)NULL},
+  { 0 },
 /* 510 */
-    {0, (char *)NULL},
+  { 0 },
 /* 511 */
-    {ERR_SILELISTFULL, "%s :Your silence list is full"},
+  { ERR_SILELISTFULL, "%s :Your silence list is full", "511" },
 /* 512 */
-    {ERR_NOSUCHGLINE, "%s@%s :No such gline"},
+  { ERR_NOSUCHGLINE, "%s@%s :No such gline", "512" },
 /* 513 */
-    {ERR_BADPING, (char *)NULL}
+  { ERR_BADPING, "", "513" }
 };
 
 static Numeric numeric_replies[] = {
 /* 300 */
-    {RPL_NONE, (char *)NULL},
+  { RPL_NONE, 0, "300" },
 /* 301 */
-    {RPL_AWAY, "%s :%s"},
+  { RPL_AWAY, "%s :%s", "301" },
 /* 302 */
-    {RPL_USERHOST, ":"},
+  { RPL_USERHOST, ":", "302" },
 /* 303 */
-    {RPL_ISON, ":"},
+  { RPL_ISON, ":", "303" },
 /* 304 */
-    {RPL_TEXT, (char *)NULL},
+  { RPL_TEXT, 0, "304" },
 /* 305 */
-    {RPL_UNAWAY, ":You are no longer marked as being away"},
+  { RPL_UNAWAY, ":You are no longer marked as being away", "305" },
 /* 306 */
-    {RPL_NOWAWAY, ":You have been marked as being away"},
+  { RPL_NOWAWAY, ":You have been marked as being away", "306" },
 /* 307 */
-    {RPL_USERIP, ":"},
+  { RPL_USERIP, ":", "307" },
 /* 308 */
-    {0, (char *)NULL},
+  { 0 },
 /* 309 */
-    {0, (char *)NULL},
+  { 0 },
 /* 310 */
-    {0, (char *)NULL},
+  { 0 },
 /* 311 */
-    {RPL_WHOISUSER, "%s %s %s * :%s"},
+  { RPL_WHOISUSER, "%s %s %s * :%s", "311" },
 /* 312 */
-    {RPL_WHOISSERVER, "%s %s :%s"},
+  { RPL_WHOISSERVER, "%s %s :%s", "312" },
 /* 313 */
-    {RPL_WHOISOPERATOR, "%s :is an IRC Operator"},
+  { RPL_WHOISOPERATOR, "%s :is an IRC Operator", "313" },
 /* 314 */
-    {RPL_WHOWASUSER, "%s %s %s * :%s"},
+  { RPL_WHOWASUSER, "%s %s %s * :%s", "314" },
 /* 315 */
-    {RPL_ENDOFWHO, "%s :End of /WHO list."},
+  { RPL_ENDOFWHO, "%s :End of /WHO list.", "315" },
 /* 316 */
-    {0, (char *)NULL},
+  { 0 },
 /* 317 */
-    {RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time"},
+  { RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time", "317" },
 /* 318 */
-    {RPL_ENDOFWHOIS, "%s :End of /WHOIS list."},
+  { RPL_ENDOFWHOIS, "%s :End of /WHOIS list.", "318" },
 /* 319 */
-    {RPL_WHOISCHANNELS, "%s :%s"},
+  { RPL_WHOISCHANNELS, "%s :%s", "319" },
 /* 320 */
-    {0, (char *)NULL},
+  { 0 },
 /* 321 */
-    {RPL_LISTSTART, "Channel :Users  Name"},
+  { RPL_LISTSTART, "Channel :Users  Name", "321" },
 /* 322 */
-    {RPL_LIST, "%s %d :%s"},
+  { RPL_LIST, "%s %d :%s", "322" },
 /* 323 */
-    {RPL_LISTEND, ":End of /LIST"},
+  { RPL_LISTEND, ":End of /LIST", "323" },
 /* 324 */
-    {RPL_CHANNELMODEIS, "%s %s %s"},
+  { RPL_CHANNELMODEIS, "%s %s %s", "324" },
 /* 325 */
-    {0, (char *)NULL},
+  { 0 },
 /* 326 */
-    {0, (char *)NULL},
+  { 0 },
 /* 327 */
-    {0, (char *)NULL},
+  { 0 },
 /* 328 */
-    {0, (char *)NULL},
+  { 0 },
 /* 329 */
-    {RPL_CREATIONTIME, "%s " TIME_T_FMT},
+  { RPL_CREATIONTIME, "%s " TIME_T_FMT, "329" },
 /* 330 */
-    {0, (char *)NULL},
+  { 0 },
 /* 331 */
-    {RPL_NOTOPIC, "%s :No topic is set."},
+  { RPL_NOTOPIC, "%s :No topic is set.", "331" },
 /* 332 */
-    {RPL_TOPIC, "%s :%s"},
+  { RPL_TOPIC, "%s :%s", "332" },
 /* 333 */
-    {RPL_TOPICWHOTIME, "%s %s " TIME_T_FMT},
+  { RPL_TOPICWHOTIME, "%s %s " TIME_T_FMT, "333" },
 /* 334 */
-    {RPL_LISTUSAGE, ":%s"},
+  { RPL_LISTUSAGE, ":%s", "334" },
 /* 335 */
-    {0, (char *)NULL},
+  { 0 },
 /* 336 */
-    {0, (char *)NULL},
+  { 0 },
 /* 337 */
-    {0, (char *)NULL},
+  { 0 },
 /* 338 */
-    {0, (char *)NULL},
+  { 0 },
 /* 339 */
-    {0, (char *)NULL},
+  { 0 },
 /* 340 */
-    {0, (char *)NULL},
+  { 0 },
 /* 341 */
-    {RPL_INVITING, "%s %s"},
+  { RPL_INVITING, "%s %s", "341" },
 /* 342 */
-    {0, (char *)NULL},
+  { 0 },
 /* 343 */
-    {0, (char *)NULL},
+  { 0 },
 /* 344 */
-    {0, (char *)NULL},
+  { 0 },
 /* 345 */
-    {0, (char *)NULL},
+  { 0 },
 /* 346 */
-    {0, (char *)NULL},
+  { RPL_INVITELIST, ":%s", "346" },
 /* 347 */
-    {0, (char *)NULL},
+  { RPL_ENDOFINVITELIST, ":End of Invite List", "347" },
 /* 348 */
-    {0, (char *)NULL},
+  { 0 },
 /* 349 */
-    {0, (char *)NULL},
+  { 0 },
 /* 350 */
-    {0, (char *)NULL},
+  { 0 },
 /* 351 */
-    {RPL_VERSION, "%s.%s %s :%s"},
+  { RPL_VERSION, "%s.%s %s :%s", "351" },
 /* 352 */
-    {RPL_WHOREPLY, "%s"},
+  { RPL_WHOREPLY, "%s", "352" },
 /* 353 */
-    {RPL_NAMREPLY, "%s"},
+  { RPL_NAMREPLY, "%s", "353" },
 /* 354 */
-    {RPL_WHOSPCRPL, "%s"},
+  { RPL_WHOSPCRPL, "%s", "354" },
 /* 355 */
-    {0, (char *)NULL},
+  { 0 },
 /* 356 */
-    {0, (char *)NULL},
+  { 0 },
 /* 357 */
-    {0, (char *)NULL},
+  { 0 },
 /* 358 */
-    {0, (char *)NULL},
+  { 0 },
 /* 359 */
-    {0, (char *)NULL},
+  { 0 },
 /* 360 */
-    {0, (char *)NULL},
+  { 0 },
 /* 361 */
-    {RPL_KILLDONE, (char *)NULL},
+  { RPL_KILLDONE, 0, "361" },
 /* 362 */
-    {RPL_CLOSING, "%s :Closed. Status = %d"},
+  { RPL_CLOSING, "%s :Closed. Status = %d", "362" },
 /* 363 */
-    {RPL_CLOSEEND, "%d: Connections Closed"},
+  { RPL_CLOSEEND, "%d: Connections Closed", "363" },
 /* 364 */
 #ifndef GODMODE
-    {RPL_LINKS, "%s %s :%d P%u %s"},
+  { RPL_LINKS, "%s %s :%d P%u %s", "364" },
 #else /* GODMODE */
-    {RPL_LINKS, "%s %s :%d P%u " TIME_T_FMT " (%s) %s"},
+  { RPL_LINKS, "%s %s :%d P%u " TIME_T_FMT " (%s) %s", "364" },
 #endif /* GODMODE */
 /* 365 */
-    {RPL_ENDOFLINKS, "%s :End of /LINKS list."},
+  { RPL_ENDOFLINKS, "%s :End of /LINKS list.", "365" },
 /* 366 */
-    {RPL_ENDOFNAMES, "%s :End of /NAMES list."},
+  { RPL_ENDOFNAMES, "%s :End of /NAMES list.", "366" },
 /* 367 */
-    {RPL_BANLIST, "%s %s %s " TIME_T_FMT},
+  { RPL_BANLIST, "%s %s %s " TIME_T_FMT, "367" },
 /* 368 */
-    {RPL_ENDOFBANLIST, "%s :End of Channel Ban List"},
+  { RPL_ENDOFBANLIST, "%s :End of Channel Ban List", "368" },
 /* 369 */
-    {RPL_ENDOFWHOWAS, "%s :End of WHOWAS"},
+  { RPL_ENDOFWHOWAS, "%s :End of WHOWAS", "369" },
 /* 370 */
-    {0, (char *)NULL},
+  { 0 },
 /* 371 */
-    {RPL_INFO, ":%s"},
+  { RPL_INFO, ":%s", "371" },
 /* 372 */
-    {RPL_MOTD, ":- %s"},
+  { RPL_MOTD, ":- %s", "372" },
 /* 373 */
-    {RPL_INFOSTART, ":Server INFO"},
+  { RPL_INFOSTART, ":Server INFO", "373" },
 /* 374 */
-    {RPL_ENDOFINFO, ":End of /INFO list."},
+  { RPL_ENDOFINFO, ":End of /INFO list.", "374" },
 /* 375 */
-    {RPL_MOTDSTART, ":- %s Message of the Day - "},
+  { RPL_MOTDSTART, ":- %s Message of the Day - ", "375" },
 /* 376 */
-    {RPL_ENDOFMOTD, ":End of /MOTD command."},
+  { RPL_ENDOFMOTD, ":End of /MOTD command.", "376" },
 /* 377 */
-    {0, (char *)NULL},
+  { 0 },
 /* 378 */
-    {0, (char *)NULL},
+  { 0 },
 /* 379 */
-    {0, (char *)NULL},
+  { 0 },
 /* 380 */
-    {0, (char *)NULL},
+  { 0 },
 /* 381 */
-    {RPL_YOUREOPER, ":You are now an IRC Operator"},
+  { RPL_YOUREOPER, ":You are now an IRC Operator", "381" },
 /* 382 */
-    {RPL_REHASHING, "%s :Rehashing"},
+  { RPL_REHASHING, "%s :Rehashing", "382" },
 /* 383 */
-    {0, (char *)NULL},
+  { 0 },
 /* 384 */
-    {RPL_MYPORTIS, "%d :Port to local server is\r\n"},
+  { RPL_MYPORTIS, "%d :Port to local server is", "384" },
 /* 385 */
-    {RPL_NOTOPERANYMORE, (char *)NULL},
+  { RPL_NOTOPERANYMORE, 0, "385" },
 /* 386 */
-    {0, (char *)NULL},
+  { 0 },
 /* 387 */
-    {0, (char *)NULL},
+  { 0 },
 /* 388 */
-    {0, (char *)NULL},
+  { 0 },
 /* 389 */
-    {0, (char *)NULL},
+  { 0 },
 /* 390 */
-    {0, (char *)NULL},
+  { 0 },
 /* 391 */
-    {RPL_TIME, "%s " TIME_T_FMT " %ld :%s"},
+  { RPL_TIME, "%s " TIME_T_FMT " %ld :%s", "391" },
 /* 392 */
-    {0, (char *)NULL},
+  { 0 },
 /* 393 */
-    {0, (char *)NULL},
+  { 0 },
 /* 394 */
-    {0, (char *)NULL},
+  { 0 },
 /* 395 */
-    {0, (char *)NULL},
+  { 0 },
 /* 396 */
-    {0, (char *)NULL},
+  { 0 },
 /* 397 */
-    {0, (char *)NULL},
+  { 0 },
 /* 398 */
-    {0, (char *)NULL},
+  { 0 },
 /* 399 */
-    {0, (char *)NULL},
+  { 0 },
 /* 200 */
 #ifndef GODMODE
-    {RPL_TRACELINK, "Link %s%s %s %s"},
+  { RPL_TRACELINK, "Link %s%s %s %s", "200" },
 #else /* GODMODE */
-    {RPL_TRACELINK, "Link %s%s %s %s " TIME_T_FMT},
+  { RPL_TRACELINK, "Link %s%s %s %s " TIME_T_FMT, "200" },
 #endif /* GODMODE */
 /* 201 */
-    {RPL_TRACECONNECTING, "Try. %d %s"},
+  { RPL_TRACECONNECTING, "Try. %d %s", "201" },
 /* 202 */
-    {RPL_TRACEHANDSHAKE, "H.S. %d %s"},
+  { RPL_TRACEHANDSHAKE, "H.S. %d %s", "202" },
 /* 203 */
-    {RPL_TRACEUNKNOWN, "???? %d %s"},
+  { RPL_TRACEUNKNOWN, "???? %d %s", "203" },
 /* 204 */
-    {RPL_TRACEOPERATOR, "Oper %d %s %ld"},
+  { RPL_TRACEOPERATOR, "Oper %d %s %ld", "204" },
 /* 205 */
-    {RPL_TRACEUSER, "User %d %s %ld"},
+  { RPL_TRACEUSER, "User %d %s %ld", "205" },
 /* 206 */
-    {RPL_TRACESERVER, "Serv %d %dS %dC %s %s!%s@%s %ld %ld"},
+  { RPL_TRACESERVER, "Serv %d %dS %dC %s %s!%s@%s %ld %ld", "206" },
 /* 207 */
-    {0, (char *)NULL},
+  { 0 },
 /* 208 */
-    {RPL_TRACENEWTYPE, "<newtype> 0 %s"},
+  { RPL_TRACENEWTYPE, "<newtype> 0 %s", "208" },
 /* 209 */
-    {RPL_TRACECLASS, "Class %d %d"},
+  { RPL_TRACECLASS, "Class %d %d", "209" },
 /* 210 */
-    {0, (char *)NULL},
+  { 0 },
 /* 211 */
-    {RPL_STATSLINKINFO, (char *)NULL},
+  { RPL_STATSLINKINFO, 0, "211" },
 /* 212 */
-    {RPL_STATSCOMMANDS, "%s %u %u"},
+  { RPL_STATSCOMMANDS, "%s %u %u", "212" },
 /* 213 */
-    {RPL_STATSCLINE, "%c %s * %s %d %d"},
+  { RPL_STATSCLINE, "%c %s * %s %d %d", "213" },
 /* 214 */
-    {RPL_STATSNLINE, "%c %s * %s %d %d"},
+  { RPL_STATSNLINE, "%c %s * %s %d %d", "214" },
 /* 215 */
-    {RPL_STATSILINE, "%c %s * %s %d %d"},
+  { RPL_STATSILINE, "%c %s * %s %d %d", "215" },
 /* 216 */
-    {RPL_STATSKLINE, "%c %s %s %s %d %d"},
+  { RPL_STATSKLINE, "%c %s %s %s %d %d", "216" },
 /* 217 */
-    {RPL_STATSPLINE, "%c %d %d %#x"},
+  { RPL_STATSPLINE, "P %d %d %s %s", "217" },
 /* 218 */
-    {RPL_STATSYLINE, "%c %d %d %d %d %ld"},
+  { RPL_STATSYLINE, "%c %d %d %d %d %ld", "218" },
 /* 219 */
-    {RPL_ENDOFSTATS, "%c :End of /STATS report"},
+  { RPL_ENDOFSTATS, "%c :End of /STATS report", "219" },
 /* 220 */
-    {0, (char *)NULL},
+  { 0 },
 /* 221 */
-    {RPL_UMODEIS, "%s"},
+  { RPL_UMODEIS, "%s", "221" },
 /* 222 */
-    {0, (char *)NULL},
+  { 0 },
 /* 223 */
-    {0, (char *)NULL},
+  { 0 },
 /* 224 */
-    {0, (char *)NULL},
+  { 0 },
 /* 225 */
-    {0, (char *)NULL},
+  { 0 },
 /* 226 */
-    {0, (char *)NULL},
+  { 0 },
 /* 227 */
-    {0, (char *)NULL},
+  { 0 },
 /* 228 */
-    {0, (char *)NULL},
+  { 0 },
 /* 229 */
-    {0, (char *)NULL},
+  { 0 },
 /* 230 */
-    {0, (char *)NULL},
+  { 0 },
 /* 231 */
-    {RPL_SERVICEINFO, (char *)NULL},
+  { RPL_SERVICEINFO, 0, "231" },
 /* 232 */
-    {RPL_ENDOFSERVICES, (char *)NULL},
+  { RPL_ENDOFSERVICES, 0, "232" },
 /* 233 */
-    {RPL_SERVICE, (char *)NULL},
+  { RPL_SERVICE, 0, "233" },
 /* 234 */
-    {RPL_SERVLIST, (char *)NULL},
+  { RPL_SERVLIST, 0, "234" },
 /* 235 */
-    {RPL_SERVLISTEND, (char *)NULL},
+  { RPL_SERVLISTEND, 0, "235" },
 /* 236 */
-    {0, (char *)NULL},
+  { 0 },
 /* 237 */
-    {0, (char *)NULL},
+  { 0 },
 /* 238 */
-    {0, (char *)NULL},
+  { 0 },
 /* 239 */
-    {0, (char *)NULL},
+  { 0 },
 /* 240 */
-    {0, (char *)NULL},
+  { 0 },
 /* 241 */
-    {RPL_STATSLLINE, "%c %s * %s %d %d"},
+  { RPL_STATSLLINE, "%c %s * %s %d %d", "241" },
 /* 242 */
-    {RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d"},
+  { RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d", "242" },
 /* 243 */
-    {RPL_STATSOLINE, "%c %s * %s %d %d"},
+  { RPL_STATSOLINE, "%c %s * %s %d %d", "243" },
 /* 244 */
-    {RPL_STATSHLINE, "%c %s * %s %d %d"},
+  { RPL_STATSHLINE, "%c %s * %s %d %d", "244" },
 /* 245 */
-    {0, (char *)NULL},
+  { 0 },
 /* 246 */
-    {RPL_STATSTLINE, "%c %s %s"},
+  { RPL_STATSTLINE, "%c %s %s", "246" },
 /* 247 */
-    {RPL_STATSGLINE, "%c %s@%s " TIME_T_FMT " :%s"},
+  { RPL_STATSGLINE, "%c %s@%s " TIME_T_FMT " :%s", "247" },
 /* 248 */
-    {RPL_STATSULINE, "%c %s %s %s %d %d"},
+  { RPL_STATSULINE, "%c %s %s %s %d %d", "248" },
 /* 249 */
-    {0, (char *)NULL},
+  { 0 },
 /* 250 */
-    {RPL_STATSCONN, ":Highest connection count: %d (%d clients)"},
+  { RPL_STATSCONN, ":Highest connection count: %d (%d clients)", "250" },
 /* 251 */
-    {RPL_LUSERCLIENT, ":There are %d users and %d invisible on %d servers"},
+  { RPL_LUSERCLIENT, ":There are %d users and %d invisible on %d servers", "251" },
 /* 252 */
-    {RPL_LUSEROP, "%d :operator(s) online"},
+  { RPL_LUSEROP, "%d :operator(s) online", "252" },
 /* 253 */
-    {RPL_LUSERUNKNOWN, "%d :unknown connection(s)"},
+  { RPL_LUSERUNKNOWN, "%d :unknown connection(s)", "253" },
 /* 254 */
-    {RPL_LUSERCHANNELS, "%d :channels formed"},
+  { RPL_LUSERCHANNELS, "%d :channels formed", "254" },
 /* 255 */
-    {RPL_LUSERME, ":I have %d clients and %d servers"},
+  { RPL_LUSERME, ":I have %d clients and %d servers", "255" },
 /* 256 */
-    {RPL_ADMINME, ":Administrative info about %s"},
+  { RPL_ADMINME, ":Administrative info about %s", "256" },
 /* 257 */
-    {RPL_ADMINLOC1, ":%s"},
+  { RPL_ADMINLOC1, ":%s", "257" },
 /* 258 */
-    {RPL_ADMINLOC2, ":%s"},
+  { RPL_ADMINLOC2, ":%s", "258" },
 /* 259 */
-    {RPL_ADMINEMAIL, ":%s"},
+  { RPL_ADMINEMAIL, ":%s", "259" },
 /* 260 */
-    {0, (char *)NULL},
+  { 0 },
 /* 261 */
-    {RPL_TRACELOG, "File %s %d"},
+  { RPL_TRACELOG, "File %s %d", "261" },
 /* 262 */
-    {RPL_TRACEPING, "Ping %s %s"},
+  { RPL_TRACEPING, "Ping %s %s", "262" },
 /* 263 */
-    {0, (char *)NULL},
+  { 0 },
 /* 264 */
-    {0, (char *)NULL},
+  { 0 },
 /* 265 */
-    {0, (char *)NULL},
+  { 0 },
 /* 266 */
-    {0, (char *)NULL},
+  { 0 },
 /* 267 */
-    {0, (char *)NULL},
+  { 0 },
 /* 268 */
-    {0, (char *)NULL},
+  { 0 },
 /* 269 */
-    {0, (char *)NULL},
+  { 0 },
 /* 270 */
-    {0, (char *)NULL},
+  { 0 },
 /* 271 */
-    {RPL_SILELIST, "%s %s"},
+  { RPL_SILELIST, "%s %s", "271" },
 /* 272 */
-    {RPL_ENDOFSILELIST, "%s :End of Silence List"},
+  { RPL_ENDOFSILELIST, "%s :End of Silence List", "272" },
 /* 273 */
-    {0, (char *)NULL},
+  { 0 },
 /* 274 */
-    {0, (char *)NULL},
+  { 0 },
 /* 275 */
-    {RPL_STATSDLINE, "%c %s %s"},
+  { RPL_STATSDLINE, "%c %s %s", "275" },
 /* 276 */
-    {0, (char *)NULL},
+  { 0 },
 /* 277 */
-    {0, (char *)NULL},
+  { 0 },
 /* 278 */
-    {0, (char *)NULL},
+  { 0 },
 /* 279 */
-    {0, (char *)NULL},
+  { 0 },
 /* 280 */
-    {RPL_GLIST, "%s@%s " TIME_T_FMT " %s%s"},
+  { RPL_GLIST, "%s@%s " TIME_T_FMT " %s%s", "280" },
 /* 281 */
-    {RPL_ENDOFGLIST, ":End of G-line List"}
+  { RPL_ENDOFGLIST, ":End of G-line List", "281" },
+/* 283 */
+  { 0 },
+/* 284 */
+  { 0 }
 };
 
-/* *INDENT-ON* */
+const struct Numeric* get_error_numeric(int numeric)
+{
+  int num = numeric;
+  assert(ERR_FIRSTERROR < num);
+  assert(num < ERR_INVALID_ERROR);
+
+  num -= ERR_FIRSTERROR;
+  assert(0 != numeric_errors[num].value);
+
+  return &numeric_errors[num];
+}
 
 static char numbuff[512];
 
 /* "inline" */
-#define prepbuf(buffer, num, tail)                     \
-{                                                      \
-  register char *s = buffer + 4;                       \
-  register const char *ap = atoi_tab + (num << 2);     \
-                                                       \
-  strcpy(buffer, ":%s 000 %s ");                       \
-  *s++ = *ap++;                                                \
-  *s++ = *ap++;                                                \
-  *s = *ap;                                            \
-  strcpy(s + 5, tail);                                 \
+#define prepbuf(buffer, num, tail)                      \
+{                                                       \
+  char *s = buffer + 4;                 \
+  const char *ap = atoi_tab + (num << 2);       \
+                                                        \
+  strcpy(buffer, ":%s 000 %s ");                        \
+  *s++ = *ap++;                                         \
+  *s++ = *ap++;                                         \
+  *s = *ap;                                             \
+  strcpy(s + 5, tail);                                  \
 }
 
 char *err_str(int numeric)
 {
-  Reg1 Numeric *nptr;
-  Reg2 int num = numeric;
+  Numeric *nptr;
+  int num = numeric;
 
-  num -= numeric_errors[0].num_val;
+  num -= numeric_errors[0].value;
 
 #ifdef DEBUGMODE
   if (num < 0 || num > ERR_USERSDONTMATCH)
     sprintf_irc(numbuff,
-       ":%%s %d %%s :INTERNAL ERROR: BAD NUMERIC! %d", numeric, num);
+        ":%%s %d %%s :INTERNAL ERROR: BAD NUMERIC! %d", numeric, num);
   else
   {
     nptr = &numeric_errors[num];
-    if (!nptr->num_form || !nptr->num_val)
+    if (!nptr->format || !nptr->value)
       sprintf_irc(numbuff, ":%%s %d %%s :NO ERROR FOR NUMERIC ERROR %d",
-         numeric, num);
+          numeric, num);
     else
-      prepbuf(numbuff, nptr->num_val, nptr->num_form);
+      prepbuf(numbuff, nptr->value, nptr->format);
   }
 #else
   nptr = &numeric_errors[num];
-  prepbuf(numbuff, nptr->num_val, nptr->num_form);
+  prepbuf(numbuff, nptr->value, nptr->format);
 #endif
 
   return numbuff;
@@ -713,8 +735,8 @@ char *err_str(int numeric)
 
 char *rpl_str(int numeric)
 {
-  Reg1 Numeric *nptr;
-  Reg2 int num = numeric;
+  Numeric *nptr;
+  int num = numeric;
 
   if (num > (int)(sizeof(local_replies) / sizeof(Numeric) - 2))
     num -= (num > 300) ? 300 : 100;
@@ -722,27 +744,27 @@ char *rpl_str(int numeric)
 #ifdef DEBUGMODE
   if (num < 0 || num > 200)
     sprintf_irc(numbuff, ":%%s %d %%s :INTERNAL REPLY ERROR: BAD NUMERIC! %d",
-       numeric, num);
+        numeric, num);
   else
   {
     if (numeric > 99)
       nptr = &numeric_replies[num];
     else
       nptr = &local_replies[num];
-    Debug((DEBUG_NUM, "rpl_str: numeric %d num %d nptr %p %d %p",
-       numeric, num, nptr, nptr->num_val, nptr->num_form));
-    if (!nptr->num_form || !nptr->num_val)
+    Debug((DEBUG_NUM, "rpl_str: numeric %d num %d %d %s",
+        numeric, num, nptr->value, nptr->format ? nptr->format : ""));
+    if (!nptr->format || !nptr->value)
       sprintf_irc(numbuff, ":%%s %d %%s :NO REPLY FOR NUMERIC ERROR %d",
-         numeric, num);
+          numeric, num);
     else
-      prepbuf(numbuff, nptr->num_val, nptr->num_form);
+      prepbuf(numbuff, nptr->value, nptr->format);
   }
 #else
   if (numeric > 99)
     nptr = &numeric_replies[num];
   else
     nptr = &local_replies[num];
-  prepbuf(numbuff, nptr->num_val, nptr->num_form);
+  prepbuf(numbuff, nptr->value, nptr->format);
 #endif
 
   return numbuff;
index f93aff2bbe78b281bb99bccb11167fdeaac04bcb..9283f9c35c0f25fe33166e804bf4442361929072 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <sys/stat.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include "h.h"
-#include "struct.h"
-#include "s_serv.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_conf.h"
 #include "s_misc.h"
-#include "common.h"
-#include "match.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "client.h"
 #include "hash.h"
-#include "s_bsd.h"
-#include "res.h"
-#include "list.h"
 #include "ircd.h"
-#include "s_ping.h"
-#include "channel.h"
-#include "s_err.h"
-#include "support.h"
-#include "userload.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numeric.h"
+#include "numnicks.h"
 #include "parse.h"
+#include "querycmds.h"
+#include "res.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
 #include "s_user.h"
-#include "numnicks.h"
+#include "send.h"
 #include "sprintf_irc.h"
-#include "querycmds.h"
-#include "IPcheck.h"
+#include "struct.h"
+#include "support.h"
+#include "sys.h"
+#include "userload.h"
 
 #include <assert.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-RCSTAG_CC("$Id$");
-
-static void exit_one_client(aClient *, char *);
+static void exit_one_client(struct Client *, char *);
 
 static char *months[] = {
   "January", "February", "March", "April",
@@ -78,17 +74,18 @@ static char *weekdays[] = {
 /*
  * stats stuff
  */
-struct stats ircst, *ircstp = &ircst;
+static struct ServerStatistics ircst;
+struct ServerStatistics* ServerStats = &ircst;
 
 char *date(time_t clock)
 {
   static char buf[80], plus;
-  Reg1 struct tm *lt, *gm;
+  struct tm *lt, *gm;
   struct tm gmbuf;
   int minswest;
 
   if (!clock)
-    clock = now;
+    clock = CurrentTime;
   gm = gmtime(&clock);
   memcpy(&gmbuf, gm, sizeof(gmbuf));
   gm = &gmbuf;
@@ -130,7 +127,7 @@ char *date(time_t clock)
 char *myctime(time_t value)
 {
   static char buf[28];
-  Reg1 char *p;
+  char *p;
 
   strcpy(buf, ctime(&value));
   if ((p = strchr(buf, '\n')) != NULL)
@@ -163,95 +160,42 @@ char *myctime(time_t value)
  *    to internal buffer (nbuf). *NEVER* use the returned pointer
  *    to modify what it points!!!
  */
-char *get_client_name(aClient *sptr, int showip)
+const char* get_client_name(const struct Client* sptr, int showip)
 {
   static char nbuf[HOSTLEN * 2 + USERLEN + 5];
 
-  if (MyConnect(sptr))
-  {
-    if (IsUnixSocket(sptr))
-    {
-      if (showip)
-       sprintf_irc(nbuf, "%s[%s]", sptr->name, sptr->sockhost);
+  if (MyConnect(sptr)) {
+    if (showip)
+      sprintf_irc(nbuf, "%s[%s@%s]", sptr->name,
+            (IsIdented(sptr)) ? sptr->username : "", sptr->sock_ip);
+    else {
+      if (0 != ircd_strcmp(sptr->name, sptr->sockhost))
+        sprintf_irc(nbuf, "%s[%s]", sptr->name, sptr->sockhost);
       else
-       sprintf_irc(nbuf, "%s[%s]", sptr->name, me.name);
-    }
-    else
-    {
-      if (showip)
-       sprintf_irc(nbuf, "%s[%s@%s]", sptr->name,
-           (!(sptr->flags & FLAGS_GOTID)) ? "" :
-           sptr->username, inetntoa(sptr->ip));
-      else
-      {
-       if (strCasediff(sptr->name, sptr->sockhost))
-         sprintf_irc(nbuf, "%s[%s]", sptr->name, sptr->sockhost);
-       else
-         return sptr->name;
-      }
+        return sptr->name;
     }
     return nbuf;
   }
   return sptr->name;
 }
 
-char *get_client_host(aClient *cptr)
+const char *get_client_host(const struct Client *cptr)
 {
-  static char nbuf[HOSTLEN * 2 + USERLEN + 5];
-
-  if (!MyConnect(cptr))
-    return cptr->name;
-  if (!cptr->hostp)
-    return get_client_name(cptr, FALSE);
-  if (IsUnixSocket(cptr))
-    sprintf_irc(nbuf, "%s[%s]", cptr->name, me.name);
-  else
-    sprintf(nbuf, "%s[%-.*s@%-.*s]", cptr->name, USERLEN,
-       (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->username,
-       HOSTLEN, cptr->hostp->h_name);
-  return nbuf;
+  return get_client_name(cptr, HIDE_IP);
 }
 
 /*
  * Form sockhost such that if the host is of form user@host, only the host
  * portion is copied.
  */
-void get_sockhost(aClient *cptr, char *host)
+void get_sockhost(struct Client *cptr, char *host)
 {
-  Reg3 char *s;
+  char *s;
   if ((s = strchr(host, '@')))
     s++;
   else
     s = host;
-  strncpy(cptr->sockhost, s, sizeof(cptr->sockhost) - 1);
-}
-
-/*
- * Return wildcard name of my server name according to given config entry
- * --Jto
- */
-char *my_name_for_link(char *name, aConfItem *aconf)
-{
-  static char namebuf[HOSTLEN];
-  register int count = aconf->port;
-  register char *start = name;
-
-  if (count <= 0 || count > 5)
-    return start;
-
-  while (count-- && name)
-  {
-    name++;
-    name = strchr(name, '.');
-  }
-  if (!name)
-    return start;
-
-  namebuf[0] = '*';
-  strncpy(&namebuf[1], name, HOSTLEN - 1);
-  namebuf[HOSTLEN - 1] = '\0';
-
-  return namebuf;
+  ircd_strncpy(cptr->sockhost, s, HOSTLEN);
 }
 
 /*
@@ -264,12 +208,12 @@ char *my_name_for_link(char *name, aConfItem *aconf)
  * sptr    : source who thought that this was a good idea
  * comment : comment sent as sign off message to local clients
  */
-static void exit_downlinks(aClient *cptr, aClient *sptr, char *comment)
+static void exit_downlinks(struct Client *cptr, struct Client *sptr, char *comment)
 {
-  Reg1 aClient *acptr;
-  Reg2 Dlink *next;
-  Reg3 Dlink *lp;
-  aClient **acptrp;
+  struct Client *acptr;
+  struct DLink *next;
+  struct DLink *lp;
+  struct Client **acptrp;
   int i;
 
   /* Run over all its downlinks */
@@ -284,9 +228,10 @@ static void exit_downlinks(aClient *cptr, aClient *sptr, char *comment)
   }
   /* Remove all clients of this server */
   acptrp = cptr->serv->client_list;
-  for (i = 0; i <= cptr->serv->nn_mask; ++acptrp, ++i)
+  for (i = 0; i <= cptr->serv->nn_mask; ++acptrp, ++i) {
     if (*acptrp)
       exit_one_client(*acptrp, comment);
+  }
 }
 
 /*
@@ -321,114 +266,122 @@ static void exit_downlinks(aClient *cptr, aClient *sptr, char *comment)
  *
  * --Run
  */
-int exit_client(aClient *cptr, /* Connection being handled by
-                                  read_message right now */
-    aClient *bcptr,            /* Client being killed */
-    aClient *sptr,             /* The client that made the decision
-                                  to remove this one, never NULL */
-    char *comment)             /* Reason for the exit */
+int exit_client(struct Client *cptr,    /* Connection being handled by
+                                   read_message right now */
+    struct Client* victim,              /* Client being killed */
+    struct Client* killer,              /* The client that made the decision
+                                   to remove this one, never NULL */
+    char *comment)              /* Reason for the exit */
 {
-  Reg1 aClient *acptr;
-  Reg3 Dlink *dlp;
-#ifdef FNAME_USERLOG
+  struct Client* acptr = 0;
+  struct DLink *dlp;
+#ifdef  FNAME_USERLOG
   time_t on_for;
 #endif
   char comment1[HOSTLEN + HOSTLEN + 2];
 
-  if (MyConnect(bcptr))
-  {
-    bcptr->flags |= FLAGS_CLOSING;
+  if (MyConnect(victim)) {
+    victim->flags |= FLAGS_CLOSING;
 #ifdef ALLOW_SNO_CONNEXIT
 #ifdef SNO_CONNEXIT_IP
-    if (IsUser(bcptr))
-    {
+    if (IsUser(victim)) {
       sprintf_irc(sendbuf,
-         ":%s NOTICE * :*** Notice -- Client exiting: %s (%s@%s) [%s] [%s]",
-         me.name, bcptr->name, bcptr->user->username, bcptr->user->host,
-         comment, inetntoa(bcptr->ip));
+          ":%s NOTICE * :*** Notice -- Client exiting: %s (%s@%s) [%s] [%s]",
+          me.name, victim->name, victim->user->username, victim->user->host,
+          comment, ircd_ntoa((const char*) &victim->ip));
       sendbufto_op_mask(SNO_CONNEXIT);
     }
 #else /* SNO_CONNEXIT_IP */
-    if (IsUser(bcptr))
-    {
+    if (IsUser(victim)) {
       sprintf_irc(sendbuf,
-         ":%s NOTICE * :*** Notice -- Client exiting: %s (%s@%s) [%s]",
-         me.name, bcptr->name, bcptr->user->username, bcptr->user->host,
-         comment);
+          ":%s NOTICE * :*** Notice -- Client exiting: %s (%s@%s) [%s]",
+          me.name, victim->name, victim->user->username, victim->user->host,
+          comment);
       sendbufto_op_mask(SNO_CONNEXIT);
     }
 #endif /* SNO_CONNEXIT_IP */
 #endif /* ALLOW_SNO_CONNEXIT */
     update_load();
 #ifdef FNAME_USERLOG
-    on_for = now - bcptr->firsttime;
+    on_for = CurrentTime - victim->firsttime;
 #if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
-    if (IsUser(bcptr))
-      syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s@%s (%s)\n",
-         myctime(bcptr->firsttime), on_for / 3600, (on_for % 3600) / 60,
-         on_for % 60, bcptr->user->username, bcptr->sockhost, bcptr->name);
+    if (IsUser(victim))
+      ircd_log(L_TRACE, "%s (%3d:%02d:%02d): %s@%s (%s)\n",
+               myctime(victim->firsttime), on_for / 3600, (on_for % 3600) / 60,
+               on_for % 60, victim->user->username, victim->sockhost, victim->name);
 #else
-    if (IsUser(bcptr))
+    if (IsUser(victim))
       write_log(FNAME_USERLOG,
-         "%s (%3d:%02d:%02d): %s@%s [%s]\n",
-         myctime(bcptr->firsttime),
-         on_for / 3600, (on_for % 3600) / 60,
-         on_for % 60,
-         bcptr->user->username, bcptr->user->host, bcptr->username);
+               "%s (%3d:%02d:%02d): %s@%s [%s]\n",
+               myctime(victim->firsttime),
+               on_for / 3600, (on_for % 3600) / 60,
+               on_for % 60,
+               victim->user->username, victim->user->host, victim->username);
 #endif
 #endif
-    if (bcptr != sptr->from    /* The source knows already */
-       && IsClient(bcptr))     /* Not a Ping struct or Log file */
+    if (victim != killer->from  /* The source knows already */
+        && IsClient(victim))    /* Not a Ping struct or Log file */
     {
-      if (IsServer(bcptr) || IsHandshake(bcptr))
-       sendto_one(bcptr, ":%s SQUIT %s 0 :%s", sptr->name, me.name, comment);
-      else if (!IsConnecting(bcptr))
-       sendto_one(bcptr, "ERROR :Closing Link: %s by %s (%s)",
-           get_client_name(bcptr, FALSE), sptr->name, comment);
-      if ((IsServer(bcptr) || IsHandshake(bcptr) || IsConnecting(bcptr)) &&
-         (sptr == &me || (IsServer(sptr) &&
-         (strncmp(comment, "Leaf-only link", 14) ||
-         strncmp(comment, "Non-Hub link", 12)))))
+      if (IsServer(victim) || IsHandshake(victim))
+        sendto_one(victim, ":%s SQUIT %s 0 :%s", killer->name, me.name, comment);
+      else if (!IsConnecting(victim)) {
+        if (!IsDead(victim))
+          sendto_one(victim, "ERROR :Closing Link: %s by %s (%s)",
+                     victim->name, killer->name, comment);
+      }
+      if ((IsServer(victim) || IsHandshake(victim) || IsConnecting(victim)) &&
+          (killer == &me || (IsServer(killer) &&
+          (strncmp(comment, "Leaf-only link", 14) ||
+          strncmp(comment, "Non-Hub link", 12)))))
       {
-       if (bcptr->serv->user && *bcptr->serv->by &&
-           (acptr = findNUser(bcptr->serv->by)) &&
-           acptr->user == bcptr->serv->user)
-       {
-         if (MyUser(acptr) || Protocol(acptr->from) < 10)
-           sendto_one(acptr,
-               ":%s NOTICE %s :Link with %s cancelled: %s",
-               me.name, acptr->name, bcptr->name, comment);
-         else
-           sendto_one(acptr,
-               "%s NOTICE %s%s :Link with %s cancelled: %s",
-               NumServ(&me), NumNick(acptr), bcptr->name, comment);
-       }
-       else
-         acptr = NULL;
-       if (sptr == &me)
-         sendto_lops_butone(acptr, "Link with %s cancelled: %s",
-             bcptr->name, comment);
+        /*
+         * Note: check user == user needed to make sure we have the same
+         * client
+         */
+        if (victim->serv->user && *victim->serv->by &&
+            (acptr = findNUser(victim->serv->by))) {
+          if (acptr->user == victim->serv->user) {
+            if (MyUser(acptr) || Protocol(acptr->from) < 10)
+              sendto_one(acptr,
+                         ":%s NOTICE %s :Link with %s cancelled: %s",
+                         me.name, acptr->name, victim->name, comment);
+            else
+              sendto_one(acptr,
+                         "%s NOTICE %s%s :Link with %s cancelled: %s",
+                         NumServ(&me), NumNick(acptr), victim->name, comment);
+          }
+          else {
+            /*
+             * not right client, set by to empty string
+             */
+            acptr = 0;
+            *victim->serv->by = '\0';
+          }
+        }
+        if (killer == &me)
+          sendto_lops_butone(acptr, "Link with %s cancelled: %s",
+                             victim->name, comment);
       }
     }
     /*
      *  Close the Client connection first.
      */
-    close_connection(bcptr);
+    close_connection(victim);
   }
 
-  if (IsServer(bcptr))
+  if (IsServer(victim))
   {
-    strcpy(comment1, bcptr->serv->up->name);
+    strcpy(comment1, victim->serv->up->name);
     strcat(comment1, " ");
-    strcat(comment1, bcptr->name);
-    if (IsUser(sptr))
-      sendto_lops_butone(sptr, "%s SQUIT by %s [%s]:",
-         (sptr->user->server == bcptr ||
-         sptr->user->server == bcptr->serv->up) ? "Local" : "Remote",
-         get_client_name(sptr, FALSE), sptr->user->server->name);
-    else if (sptr != &me && bcptr->serv->up != sptr)
-      sendto_ops("Received SQUIT %s from %s :", bcptr->name,
-         IsServer(sptr) ? sptr->name : get_client_name(sptr, FALSE));
+    strcat(comment1, victim->name);
+    if (IsUser(killer))
+      sendto_lops_butone(killer, "%s SQUIT by %s [%s]:",
+                         (killer->user->server == victim ||
+                         killer->user->server == victim->serv->up) ? "Local" : "Remote",
+                         get_client_name(killer, HIDE_IP), killer->user->server->name);
+    else if (killer != &me && victim->serv->up != killer)
+      sendto_ops("Received SQUIT %s from %s :", victim->name,
+                 IsServer(killer) ? killer->name : get_client_name(killer, HIDE_IP));
     sendto_op_mask(SNO_NETWORK, "Net break: %s (%s)", comment1, comment);
   }
 
@@ -436,32 +389,31 @@ int exit_client(aClient *cptr,    /* Connection being handled by
    * First generate the needed protocol for the other server links
    * except the source:
    */
-  for (dlp = me.serv->down; dlp; dlp = dlp->next)
-    if (dlp->value.cptr != sptr->from && dlp->value.cptr != bcptr)
-    {
-      if (IsServer(bcptr))
-       sendto_one(dlp->value.cptr, ":%s SQUIT %s " TIME_T_FMT " :%s",
-           sptr->name, bcptr->name, bcptr->serv->timestamp, comment);
-      else if (IsUser(bcptr) && (bcptr->flags & FLAGS_KILLED) == 0)
-       sendto_one(dlp->value.cptr, ":%s QUIT :%s", bcptr->name, comment);
+  for (dlp = me.serv->down; dlp; dlp = dlp->next) {
+    if (dlp->value.cptr != killer->from && dlp->value.cptr != victim) {
+      if (IsServer(victim))
+        sendto_one(dlp->value.cptr, ":%s SQUIT %s " TIME_T_FMT " :%s",
+                   killer->name, victim->name, victim->serv->timestamp, comment);
+      else if (IsUser(victim) && 0 == (victim->flags & FLAGS_KILLED))
+        sendto_one(dlp->value.cptr, "%s%s " TOK_QUIT " :%s", NumNick(victim), comment);
     }
-
+  }
   /* Then remove the client structures */
-  if (IsServer(bcptr))
-    exit_downlinks(bcptr, sptr, comment1);
-  exit_one_client(bcptr, comment);
+  if (IsServer(victim))
+    exit_downlinks(victim, killer, comment1);
+  exit_one_client(victim, comment);
 
   /*
    *  cptr can only have been killed if it was cptr itself that got killed here,
-   *  because cptr can never have been a dependant of bcptr    --Run
+   *  because cptr can never have been a dependant of victim    --Run
    */
-  return (cptr == bcptr) ? CPTR_KILLED : 0;
+  return (cptr == victim) ? CPTR_KILLED : 0;
 }
 
 /*
  * Exit client with formatted message, added 25-9-94 by Run
  */
-int vexit_client_msg(aClient *cptr, aClient *bcptr, aClient *sptr,
+int vexit_client_msg(struct Client *cptr, struct Client *bcptr, struct Client *sptr,
     char *pattern, va_list vl)
 {
   char msgbuf[1024];
@@ -469,8 +421,8 @@ int vexit_client_msg(aClient *cptr, aClient *bcptr, aClient *sptr,
   return exit_client(cptr, bcptr, sptr, msgbuf);
 }
 
-int exit_client_msg(aClient *cptr, aClient *bcptr,
-    aClient *sptr, char *pattern, ...)
+int exit_client_msg(struct Client *cptr, struct Client *bcptr,
+    struct Client *sptr, char *pattern, ...)
 {
   va_list vl;
   char msgbuf[1024];
@@ -493,24 +445,21 @@ int exit_client_msg(aClient *cptr, aClient *bcptr,
  *
  * --Run
  */
-static void exit_one_client(aClient *bcptr, char *comment)
+static void exit_one_client(struct Client *bcptr, char *comment)
 {
-  Link *lp;
+  struct SLink *lp;
 
-  if (bcptr->serv && bcptr->serv->client_list) /* Was SetServerYXX called ? */
-    ClearServerYXX(bcptr);     /* Removes server from server_list[] */
-  if (IsUser(bcptr))
-  {
-    /* Stop a running /LIST clean */
-    if (MyUser(bcptr) && bcptr->listing)
-    {
+  if (bcptr->serv && bcptr->serv->client_list)  /* Was SetServerYXX called ? */
+    ClearServerYXX(bcptr);      /* Removes server from server_list[] */
+  if (IsUser(bcptr)) {
+    /*
+     * Stop a running /LIST clean
+     */
+    if (MyUser(bcptr) && bcptr->listing) {
       bcptr->listing->chptr->mode.mode &= ~MODE_LISTED;
-      RunFree(bcptr->listing);
+      MyFree(bcptr->listing);
       bcptr->listing = NULL;
     }
-
-    if (AskedPing(bcptr))
-      cancel_ping(bcptr, NULL);
     /*
      * If a person is on a channel, send a QUIT notice
      * to every client (person) on the same channel (so
@@ -519,8 +468,7 @@ static void exit_one_client(aClient *bcptr, char *comment)
      */
     sendto_common_channels(bcptr, ":%s QUIT :%s", bcptr->name, comment);
 
-    while ((lp = bcptr->user->channel))
-      remove_user_from_channel(bcptr, lp->value.chptr);
+    remove_user_from_all_channels(bcptr);
 
     /* Clean up invitefield */
     while ((lp = bcptr->user->invited))
@@ -531,39 +479,36 @@ static void exit_one_client(aClient *bcptr, char *comment)
       del_silence(bcptr, lp->value.cp);
 
     if (IsInvisible(bcptr))
-      --nrof.inv_clients;
+      --UserStats.inv_clients;
     if (IsOper(bcptr))
-      --nrof.opers;
+      --UserStats.opers;
     if (MyConnect(bcptr))
-      Count_clientdisconnects(bcptr, nrof);
+      Count_clientdisconnects(bcptr, UserStats);
     else
-      Count_remoteclientquits(nrof);
+      Count_remoteclientquits(UserStats, bcptr);
   }
   else if (IsServer(bcptr))
   {
     /* Remove downlink list node of uplink */
     remove_dlink(&bcptr->serv->up->serv->down, bcptr->serv->updown);
+    bcptr->serv->updown = 0;
 
     if (MyConnect(bcptr))
-      Count_serverdisconnects(nrof);
+      Count_serverdisconnects(UserStats);
     else
-      Count_remoteserverquits(nrof);
-  }
-  else if (IsPing(bcptr))      /* Apperently, we are closing ALL links */
-  {
-    del_queries((char *)bcptr);
-    end_ping(bcptr);
-    return;
+      Count_remoteserverquits(UserStats);
   }
   else if (IsMe(bcptr))
   {
     sendto_ops("ERROR: tried to exit me! : %s", comment);
-    return;                    /* ...must *never* exit self! */
+    return;                     /* ...must *never* exit self! */
   }
   else if (IsUnknown(bcptr) || IsConnecting(bcptr) || IsHandshake(bcptr))
-    Count_unknowndisconnects(nrof);
+    Count_unknowndisconnects(UserStats);
 
-  /* Update IPregistry */
+  /*
+   * Update IPregistry
+   */
   if (IsIPChecked(bcptr))
     IPcheck_disconnect(bcptr);
 
@@ -571,8 +516,7 @@ static void exit_one_client(aClient *bcptr, char *comment)
    * Remove from serv->client_list
    * NOTE: user is *always* NULL if this is a server
    */
-  if (bcptr->user)
-  {
+  if (bcptr->user) {
     assert(!IsServer(bcptr));
     /* bcptr->user->server->serv->client_list[IndexYXX(bcptr)] = NULL; */
     RemoveYXXClient(bcptr->user->server, bcptr->yxx);
@@ -582,55 +526,33 @@ static void exit_one_client(aClient *bcptr, char *comment)
 #ifdef DEBUGMODE
   if (hRemClient(bcptr) != 0)
     Debug((DEBUG_ERROR, "%p !in tab %s[%s] %p %p %p %d %d %p",
-       bcptr, bcptr->name, bcptr->from ? bcptr->from->sockhost : "??host",
-       bcptr->from, bcptr->next, bcptr->prev, bcptr->fd,
-       bcptr->status, bcptr->user));
+          bcptr, bcptr->name, bcptr->from ? bcptr->from->sockhost : "??host",
+          bcptr->from, bcptr->next, bcptr->prev, bcptr->fd,
+          bcptr->status, bcptr->user));
 #else
   hRemClient(bcptr);
 #endif
   remove_client_from_list(bcptr);
-  return;
 }
 
-void checklist(void)
-{
-  Reg1 aClient *acptr;
-  Reg2 int i, j;
-
-  if (!(bootopt & BOOT_AUTODIE))
-    return;
-  for (j = i = 0; i <= highest_fd; i++)
-    if (!(acptr = loc_clients[i]))
-      continue;
-    else if (IsUser(acptr))
-      j++;
-  if (!j)
-  {
-#ifdef USE_SYSLOG
-    syslog(LOG_WARNING, "ircd exiting: autodie");
-#endif
-    exit(0);
-  }
-  return;
-}
 
 void initstats(void)
 {
   memset(&ircst, 0, sizeof(ircst));
 }
 
-void tstats(aClient *cptr, char *name)
+void tstats(struct Client *cptr, char *name)
 {
-  Reg1 aClient *acptr;
-  Reg2 int i;
-  Reg3 struct stats *sp;
-  struct stats tmp;
+  struct Client *acptr;
+  int i;
+  struct ServerStatistics *sp;
+  struct ServerStatistics tmp;
 
   sp = &tmp;
-  memcpy(sp, ircstp, sizeof(*sp));
+  memcpy(sp, ServerStats, sizeof(struct ServerStatistics));
   for (i = 0; i < MAXCONNECTIONS; i++)
   {
-    if (!(acptr = loc_clients[i]))
+    if (!(acptr = LocalClientArray[i]))
       continue;
     if (IsServer(acptr))
     {
@@ -638,17 +560,17 @@ void tstats(aClient *cptr, char *name)
       sp->is_sbr += acptr->receiveB;
       sp->is_sks += acptr->sendK;
       sp->is_skr += acptr->receiveK;
-      sp->is_sti += now - acptr->firsttime;
+      sp->is_sti += CurrentTime - acptr->firsttime;
       sp->is_sv++;
       if (sp->is_sbs > 1023)
       {
-       sp->is_sks += (sp->is_sbs >> 10);
-       sp->is_sbs &= 0x3ff;
+        sp->is_sks += (sp->is_sbs >> 10);
+        sp->is_sbs &= 0x3ff;
       }
       if (sp->is_sbr > 1023)
       {
-       sp->is_skr += (sp->is_sbr >> 10);
-       sp->is_sbr &= 0x3ff;
+        sp->is_skr += (sp->is_sbr >> 10);
+        sp->is_sbr &= 0x3ff;
       }
     }
     else if (IsUser(acptr))
@@ -657,17 +579,17 @@ void tstats(aClient *cptr, char *name)
       sp->is_cbr += acptr->receiveB;
       sp->is_cks += acptr->sendK;
       sp->is_ckr += acptr->receiveK;
-      sp->is_cti += now - acptr->firsttime;
+      sp->is_cti += CurrentTime - acptr->firsttime;
       sp->is_cl++;
       if (sp->is_cbs > 1023)
       {
-       sp->is_cks += (sp->is_cbs >> 10);
-       sp->is_cbs &= 0x3ff;
+        sp->is_cks += (sp->is_cbs >> 10);
+        sp->is_cbs &= 0x3ff;
       }
       if (sp->is_cbr > 1023)
       {
-       sp->is_ckr += (sp->is_cbr >> 10);
-       sp->is_cbr &= 0x3ff;
+        sp->is_ckr += (sp->is_cbr >> 10);
+        sp->is_cbr &= 0x3ff;
       }
     }
     else if (IsUnknown(acptr))
@@ -686,8 +608,8 @@ void tstats(aClient *cptr, char *name)
       me.name, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
   sendto_one(cptr, ":%s %d %s :auth successes %u fails %u",
       me.name, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
-  sendto_one(cptr, ":%s %d %s :local connections %u udp packets %u",
-      me.name, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udp);
+  sendto_one(cptr, ":%s %d %s :local connections %u",
+      me.name, RPL_STATSDEBUG, name, sp->is_loc);
   sendto_one(cptr, ":%s %d %s :Client Server", me.name, RPL_STATSDEBUG, name);
   sendto_one(cptr, ":%s %d %s :connected %u %u",
       me.name, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
index 7cf0feff7f37444939604de7c959ec123e07c8d2..993b1e235e31d34f86731468cba4af228270b339 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include "h.h"
-#include "struct.h"
-#include "s_serv.h"
-#include "s_bsd.h"
-#include "send.h"
-#include "support.h"
-#include "parse.h"
-#include "numeric.h"
+#include "s_numeric.h"
 #include "channel.h"
-#include "ircd.h"
+#include "client.h"
 #include "hash.h"
+#include "ircd.h"
 #include "numnicks.h"
-#include "s_numeric.h"
+#include "send.h"
+#include "struct.h"
 
-RCSTAG_CC("$Id$");
 
 static char buffer[1024];
 
@@ -48,11 +42,11 @@ static char buffer[1024];
  * the savy approach is NEVER generate an error in response to an... error :)
  */
 
-int do_numeric(int numeric, int nnn, aClient *cptr, aClient *sptr,
+int do_numeric(int numeric, int nnn, struct Client *cptr, struct Client *sptr,
     int parc, char *parv[])
 {
-  aClient *acptr = NULL;
-  aChannel *achptr = NULL;
+  struct Client *acptr = 0;
+  struct Channel *achptr = 0;
   char *p, *b;
   int i;
 
@@ -84,7 +78,7 @@ int do_numeric(int numeric, int nnn, aClient *cptr, aClient *sptr,
   {
     for (i = 2; i < (parc - 1); i++)
       for (*b++ = ' ', p = parv[i]; *p; p++)
-       *b++ = *p;
+        *b++ = *p;
     for (*b++ = ' ', *b++ = ':', p = parv[parc - 1]; *p; p++)
       *b++ = *p;
   }
@@ -94,10 +88,10 @@ int do_numeric(int numeric, int nnn, aClient *cptr, aClient *sptr,
 
   if (acptr)
     sendto_prefix_one(acptr, sptr, ":%s %d %s%s",
-       sptr->name, numeric, acptr->name, buffer);
+        sptr->name, numeric, acptr->name, buffer);
   else
     sendto_channel_butone(cptr, sptr, achptr, ":%s %d %s%s",
-       sptr->name, numeric, achptr->chname, buffer);
+        sptr->name, numeric, achptr->chname, buffer);
 
   return 0;
 }
diff --git a/ircd/s_ping.c b/ircd/s_ping.c
deleted file mode 100644 (file)
index aa10dd9..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * IRC - Internet Relay Chat, ircd/s_ping.c
- * Copyright (C) 1994 Carlo Wood ( Run @ undernet.org )
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "sys.h"
-#include <sys/socket.h>
-#if HAVE_SYS_FILE_H
-#include <sys/file.h>
-#endif
-#if HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef UNIXPORT
-#include <sys/un.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stdlib.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include "h.h"
-#include "struct.h"
-#include "send.h"
-#include "s_conf.h"
-#include "match.h"
-#include "res.h"
-#include "s_bsd.h"
-#include "s_serv.h"
-#include "ircd.h"
-#include "s_ping.h"
-#include "support.h"
-#include "numeric.h"
-#include "s_user.h"
-#include "s_err.h"
-#include "common.h"
-#include "s_user.h"
-#include "numnicks.h"
-
-RCSTAG_CC("$Id$");
-
-#define UPINGBUFSIZE 2000      /* Lot bigger then 1024,
-                                  bit smaller then 2048 */
-#define UPINGTIMEOUT 120       /* Timeout waitting for first ping response */
-
-/*
- * start_ping
- *
- * As for now, I am abusing the client structure for a ping connection.
- *                 .... And I really don't like this solution --Nemesi
- * Used members are:
- * These are used by existing routines as well, and do have their own meaning:
- *   fd       : The socket file descriptor.
- *   status   : To flag that this IS one of these abused ping structures
- *   sockhost : Name of requested server to ping (aconf->host).
- *   name     : aconf->name
- *   ip       : ip#
- * These have more or less their own meaning,
- * but are not used by existing routines:
- *   flags    : To flag that a next ping is requested.
- *   port     : Requested remote port.
- * These are only used by the 'uping' routines
- * and have totally different meanings:
- *   buffer   : buffer hold pingtimes of received packets
- *   confs    : recv/send (char *) buffer.
- *   hopcount : Total number of requested pings
- *   sendB    : Number of pings left to send.
- *   receiveB : Number of pings left to be received.
- *   acpt     : client asking for this ping
- *   lasttime : last time a ping was sent
- *   firsttime: recvfrom timeout
- *   since    : timeout in seconds to next recvfrom
- *   receiveK : minimum in ms
- *   sendM    : average in ms
- *   receiveM : maximum in ms
- */
-int start_ping(aClient *cptr)
-{
-  struct sockaddr_in remote_addr;
-
-  Debug((DEBUG_NOTICE, "start_ping(%p) status %d", cptr, cptr->status));
-
-  if (!(cptr->acpt))
-    return -1;
-
-  memcpy(&remote_addr.sin_addr, &cptr->ip, sizeof(struct in_addr));
-#ifdef TESTNET
-  remote_addr.sin_port = htons(cptr->port + 10000);
-#else
-  remote_addr.sin_port = htons(cptr->port);
-#endif
-  remote_addr.sin_family = AF_INET;
-
-  if (MyUser(cptr->acpt) || Protocol(cptr->acpt->from) < 10)
-  {
-    sendto_one(cptr->acpt,
-       ":%s NOTICE %s :Sending %d ping%s to %s[%s] port %u",
-       me.name, cptr->acpt->name, cptr->hopcount,
-       (cptr->hopcount == 1) ? "" : "s", cptr->name,
-#ifdef TESTNET
-       inetntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port) - 10000);
-#else
-       inetntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));
-#endif
-  }
-  else
-  {
-    sendto_one(cptr->acpt,
-       "%s NOTICE %s%s :Sending %d ping%s to %s[%s] port %u",
-       NumServ(&me), NumNick(cptr->acpt), cptr->hopcount,
-       (cptr->hopcount == 1) ? "" : "s", cptr->name,
-#ifdef TESTNET
-       inetntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port) - 10000);
-#else
-       inetntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));
-#endif
-  }
-
-  cptr->firsttime = now + UPINGTIMEOUT;
-  cptr->since = UPINGTIMEOUT;
-  cptr->flags |= (FLAGS_PING);
-
-  return 0;
-}
-
-/*
- * send_ping
- *
- */
-void send_ping(aClient *cptr)
-{
-  struct sockaddr_in remote_addr;
-  struct timeval tv;
-
-  memcpy(&remote_addr.sin_addr, &cptr->ip, sizeof(struct in_addr));
-#ifdef TESTNET
-  remote_addr.sin_port = htons(cptr->port + 10000);
-#else
-  remote_addr.sin_port = htons(cptr->port);
-#endif
-  remote_addr.sin_family = AF_INET;
-
-  gettimeofday(&tv, NULL);
-#if defined(__sun__) || (__GLIBC__ >= 2) || defined(__NetBSD__)
-  sprintf((char *)cptr->confs, " %10lu%c%6lu", tv.tv_sec, '\0', tv.tv_usec);
-#else
-  sprintf((char *)cptr->confs, " %10u%c%6u", tv.tv_sec, '\0', tv.tv_usec);
-#endif
-
-  Debug((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
-      (char *)cptr->confs, (char *)cptr->confs + 12,
-      inetntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port), cptr->fd));
-
-  if (sendto(cptr->fd, (char *)cptr->confs, 1024, 0,
-      (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_in)) != 1024)
-  {
-#ifdef DEBUGMODE
-    int err = errno;
-#endif
-    if (cptr->acpt)
-    {
-      if (MyUser(cptr->acpt)
-#ifndef NO_PROTOCOL9
-         || (IsServer(cptr->acpt->from) && Protocol(cptr->acpt->from) < 10)
-#endif
-         )
-       sendto_one(cptr->acpt, ":%s NOTICE %s :UPING: sendto() failed: %s",
-           me.name, cptr->acpt->name, strerror(get_sockerr(cptr)));
-      else
-       sendto_one(cptr->acpt, "%s NOTICE %s%s :UPING: sendto() failed: %s",
-           NumServ(&me), NumNick(cptr->acpt), strerror(get_sockerr(cptr)));
-    }
-    Debug((DEBUG_SEND, "send_ping: sendto failed on %d (%d)", cptr->fd, err));
-    end_ping(cptr);
-  }
-  else if (--(cptr->sendB) <= 0)
-  {
-    ClearPing(cptr);
-    if (cptr->receiveB <= 0)
-      end_ping(cptr);
-  }
-
-  return;
-}
-
-/*
- * read_ping
- */
-void read_ping(aClient *cptr)
-{
-  size_t addr_len = sizeof(struct sockaddr_in);
-  struct sockaddr_in remote_addr;
-  struct timeval tv;
-  int len;
-  unsigned long int pingtime;
-  char *s;
-
-  memcpy(&remote_addr.sin_addr, &cptr->ip, sizeof(struct in_addr));
-#ifdef TESTNET
-  remote_addr.sin_port = htons(cptr->port + 10000);
-#else
-  remote_addr.sin_port = htons(cptr->port);
-#endif
-  remote_addr.sin_family = AF_INET;
-
-  gettimeofday(&tv, NULL);
-
-  if ((len = recvfrom(cptr->fd, (char *)cptr->confs, UPINGBUFSIZE, 0,
-      (struct sockaddr *)&remote_addr, &addr_len)) == -1)
-  {
-    int err = errno;
-    if (MyUser(cptr->acpt)
-#ifndef NO_PROTOCOL9
-       || (IsServer(cptr->acpt->from) && Protocol(cptr->acpt->from) < 10)
-#endif
-       )
-      sendto_one(cptr->acpt, ":%s NOTICE %s :UPING: recvfrom: %s",
-         me.name, cptr->acpt->name, strerror(get_sockerr(cptr)));
-    else
-      sendto_one(cptr->acpt, "%s NOTICE %s%s :UPING: recvfrom: %s",
-         NumServ(&me), NumNick(cptr->acpt), strerror(get_sockerr(cptr)));
-    Debug((DEBUG_SEND, "read_ping: recvfrom: %d", err));
-    if (err != EAGAIN)
-      end_ping(cptr);
-    return;
-  }
-
-  if (len < 19)
-    return;                    /* Broken packet */
-
-  pingtime = (tv.tv_sec - atoi((char *)cptr->confs + 1)) * 1000 +
-      (tv.tv_usec - atoi((char *)cptr->confs + strlen((char *)cptr->confs) +
-      1)) / 1000;
-  cptr->sendM += pingtime;
-  if (!(cptr->receiveK) || (cptr->receiveK > pingtime))
-    cptr->receiveK = pingtime;
-  if (pingtime > cptr->receiveM)
-    cptr->receiveM = pingtime;
-  /* Wait at most 10 times the average pingtime for the next one: */
-  if ((cptr->since =
-      cptr->sendM / (100 * (cptr->hopcount - cptr->receiveB + 1))) < 2)
-    cptr->since = 2;
-  cptr->firsttime = tv.tv_sec + cptr->since;
-
-  Debug((DEBUG_SEND, "read_ping: %d bytes, ti " TIME_T_FMT ": [%s %s] %lu ms",
-      len, cptr->since, (char *)cptr->confs,
-      (char *)cptr->confs + strlen((char *)cptr->confs) + 1, pingtime));
-
-  s = cptr->buffer + strlen(cptr->buffer);
-  sprintf(s, " %lu", pingtime);
-
-  if ((--(cptr->receiveB) <= 0 && !DoPing(cptr)) || !(cptr->acpt))
-    end_ping(cptr);
-
-  return;
-}
-
-int ping_server(aClient *cptr)
-{
-  if ((!cptr->ip.s_addr)
-#ifdef UNIXPORT
-      && ((cptr->sockhost[2]) != '/')
-#endif
-      )
-  {
-    struct hostent *hp;
-    char *s;
-    Link lin;
-
-    if (!(cptr->acpt))
-      return -1;               /* Oper left already */
-
-    lin.flags = ASYNC_PING;
-    lin.value.cptr = cptr;
-    nextdnscheck = 1;
-    s = strchr(cptr->sockhost, '@');
-    s++;                       /* should never be NULL;
-                                  cptr->sockhost is actually a conf->host */
-    if ((cptr->ip.s_addr = inet_addr(s)) == INADDR_NONE)
-    {
-      cptr->ip.s_addr = INADDR_ANY;
-      hp = gethost_byname(s, &lin);
-      Debug((DEBUG_NOTICE, "ping_sv: hp %p ac %p ho %s", hp, cptr, s));
-      if (!hp)
-       return 0;
-      memcpy(&cptr->ip, hp->h_addr, sizeof(struct in_addr));
-    }
-  }
-
-  return start_ping(cptr);
-}
-
-/*
- * m_uping  -- by Run
- *
- * parv[0] = sender prefix
- * parv[1] = pinged server
- * parv[2] = port
- * parv[3] = hunted server
- * parv[4] = number of requested pings
- */
-int m_uping(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aConfItem *aconf;
-  unsigned short int port;
-  int fd, opt;
-
-  if (!IsPrivileged(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return -1;
-  }
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "UPING");
-    return 0;
-  }
-
-  if (MyUser(sptr))
-  {
-    if (parc == 2)
-    {
-      parv[parc++] = UDP_PORT;
-      parv[parc++] = me.name;
-      parv[parc++] = "5";
-    }
-    else if (parc == 3)
-    {
-      if (isDigit(*parv[2]))
-       parv[parc++] = me.name;
-      else
-      {
-       parv[parc++] = parv[2];
-       parv[2] = UDP_PORT;
-      }
-      parv[parc++] = "5";
-    }
-    else if (parc == 4)
-    {
-      if (isDigit(*parv[2]))
-      {
-       if (isDigit(*parv[3]))
-       {
-         parv[parc++] = parv[3];
-         parv[3] = me.name;
-       }
-       else
-         parv[parc++] = "5";
-      }
-      else
-      {
-       parv[parc++] = parv[3];
-       parv[3] = parv[2];
-       parv[2] = UDP_PORT;
-      }
-    }
-  }
-  if (hunt_server(1, cptr, sptr,
-      ":%s UPING %s %s %s %s", 3, parc, parv) != HUNTED_ISME)
-    return 0;
-
-  if (BadPtr(parv[4]) || atoi(parv[4]) <= 0)
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Invalid number of packets: %s",
-         me.name, parv[0], parv[4]);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :UPING: Invalid number of packets: %s",
-         NumServ(&me), NumNick(sptr), parv[4]);
-    return 0;
-  }
-
-  /* Check if a CONNECT would be possible at all (adapted from m_connect) */
-  for (aconf = conf; aconf; aconf = aconf->next)
-    if (aconf->status == CONF_CONNECT_SERVER &&
-       match(parv[1], aconf->name) == 0)
-      break;
-  if (!aconf)
-    for (aconf = conf; aconf; aconf = aconf->next)
-      if (aconf->status == CONF_CONNECT_SERVER &&
-         (match(parv[1], aconf->host) == 0 ||
-         match(parv[1], strchr(aconf->host, '@') + 1) == 0))
-       break;
-  if (!aconf)
-  {
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Host %s not listed in ircd.conf",
-         me.name, parv[0], parv[1]);
-    else
-      sendto_one(sptr,
-         "%s NOTICE %s%s :UPING: Host %s not listed in ircd.conf",
-         NumServ(&me), NumNick(sptr), parv[1]);
-    return 0;
-  }
-
-  if (AskedPing(sptr))
-    cancel_ping(sptr, sptr);   /* Cancel previous ping request */
-
-  /*
-   * Determine port: First user supplied, then default : 7007
-   */
-  if (BadPtr(parv[2]) || (port = atoi(parv[2])) <= 0)
-    port = atoi(UDP_PORT);
-
-  alarm(2);
-  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-  {
-    int err = errno;
-    alarm(0);
-    sendto_ops("m_uping: socket: %s", (err != EAGAIN) ?
-       strerror(err) : "No more sockets");
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Unable to create udp ping socket",
-         me.name, parv[0]);
-    else
-      sendto_one(sptr,
-         "%s NOTICE %s%s :UPING: Unable to create udp ping socket",
-         NumServ(&me), NumNick(sptr));
-#ifdef USE_SYSLOG
-    syslog(LOG_ERR, "Unable to create udp ping socket");
-#endif
-    return 0;
-  }
-  alarm(0);
-
-  if (fcntl(fd, F_SETFL, FNDELAY) == -1)
-  {
-    sendto_ops("m_uping: fcntl FNDELAY: %s", strerror(errno));
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: Can't set fd non-blocking",
-         me.name, parv[0]);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :UPING: Can't set fd non-blocking",
-         NumServ(&me), NumNick(sptr));
-    close(fd);
-    return 0;
-  }
-  /*
-   * On some systems, receive and send buffers must be equal in size.
-   * Others block select() when the buffers are too small
-   * (Linux 1.1.50 blocks when < 2048) --Run
-   */
-  opt = 2048;
-  if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (OPT_TYPE *)&opt,
-      sizeof(opt)) < 0 ||
-      setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (OPT_TYPE *)&opt, sizeof(opt)) < 0)
-  {
-    int err = errno;
-    sendto_ops("m_uping: setsockopt SO_SNDBUF|SO_RCVBUF: %s", strerror(err));
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: error in setsockopt: %s",
-         me.name, parv[0], strerror(err));
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :UPING: error in setsockopt: %s",
-         NumServ(&me), NumNick(sptr), strerror(err));
-    close(fd);
-    return 0;
-  }
-
-  if (fd >= MAXCONNECTIONS)
-  {
-    sendto_ops("Can't allocate fd for uping (all connections in use)");
-    if (MyUser(sptr) || Protocol(cptr) < 10)
-      sendto_one(sptr, ":%s NOTICE %s :UPING: All connections in use",
-         me.name, parv[0]);
-    else
-      sendto_one(sptr, "%s NOTICE %s%s :UPING: All connections in use",
-         NumServ(&me), NumNick(sptr));
-    close(fd);
-    return 0;
-  }
-
-  if (fd > highest_fd)
-    highest_fd = fd;
-  loc_clients[fd] = cptr = make_client(NULL, STAT_PING);
-  cptr->confs = (Link *)RunMalloc(UPINGBUFSIZE);       /* Really a (char *) */
-  cptr->fd = fd;
-  cptr->port = port;
-  cptr->hopcount = cptr->receiveB = cptr->sendB = MIN(20, atoi(parv[4]));
-  strcpy(cptr->sockhost, aconf->host);
-  cptr->acpt = sptr;
-  SetAskedPing(sptr);
-  memcpy(&cptr->ip, &aconf->ipnum, sizeof(struct in_addr));
-  strcpy(cptr->name, aconf->name);
-  cptr->firsttime = 0;
-
-  switch (ping_server(cptr))
-  {
-    case 0:
-      break;
-    case -1:
-      del_queries((char *)cptr);
-      end_ping(cptr);
-      break;
-  }
-  return 0;
-}
-
-void end_ping(aClient *cptr)
-{
-  Debug((DEBUG_DEBUG, "end_ping: %p", cptr));
-  if (cptr->acpt)
-  {
-    if (MyUser(cptr->acpt)
-       || (IsServer(cptr->acpt->from) && Protocol(cptr->acpt->from) < 10))
-    {
-      if (cptr->firsttime)     /* Started at all ? */
-      {
-       if (cptr->receiveB != cptr->hopcount)   /* Received any pings at all? */
-       {
-         sendto_one(cptr->acpt, ":%s NOTICE %s :UPING %s%s",
-             me.name, cptr->acpt->name, cptr->name, cptr->buffer);
-         sendto_one(cptr->acpt,
-             ":%s NOTICE %s :UPING Stats: sent %d recvd %d ; "
-             "min/avg/max = %u/%u/%u ms",
-             me.name, cptr->acpt->name, cptr->hopcount - cptr->sendB,
-             cptr->hopcount - cptr->receiveB, cptr->receiveK,
-             (2 * cptr->sendM + cptr->hopcount - cptr->receiveB) /
-             (2 * (cptr->hopcount - cptr->receiveB)), cptr->receiveM);
-       }
-       else
-         sendto_one(cptr->acpt,
-             ":%s NOTICE %s :UPING: no response from %s within %d seconds",
-             me.name, cptr->acpt->name, cptr->name,
-             (int)(now + cptr->since - cptr->firsttime));
-      }
-      else
-       sendto_one(cptr->acpt,
-           ":%s NOTICE %s :UPING: Could not start ping to %s %u",
-           me.name, cptr->acpt->name, cptr->name, cptr->port);
-    }
-    else
-    {
-      if (cptr->firsttime)     /* Started at all ? */
-      {
-       if (cptr->receiveB != cptr->hopcount)   /* Received any pings at all? */
-       {
-         sendto_one(cptr->acpt, "%s NOTICE %s%s :UPING %s%s",
-             NumServ(&me), NumNick(cptr->acpt), cptr->name, cptr->buffer);
-         sendto_one(cptr->acpt,
-             "%s NOTICE %s%s :UPING Stats: sent %d recvd %d ; "
-             "min/avg/max = %u/%u/%u ms",
-             NumServ(&me), NumNick(cptr->acpt), cptr->hopcount - cptr->sendB,
-             cptr->hopcount - cptr->receiveB, cptr->receiveK,
-             (2 * cptr->sendM + cptr->hopcount - cptr->receiveB) /
-             (2 * (cptr->hopcount - cptr->receiveB)), cptr->receiveM);
-       }
-       else
-         sendto_one(cptr->acpt,
-             "%s NOTICE %s%s :UPING: no response from %s within %d seconds",
-             NumServ(&me), NumNick(cptr->acpt), cptr->name,
-             (int)(now + cptr->since - cptr->firsttime));
-      }
-      else
-       sendto_one(cptr->acpt,
-           "%s NOTICE %s%s :UPING: Could not start ping to %s %d",
-           NumServ(&me), NumNick(cptr->acpt), cptr->name, cptr->port);
-    }
-  }
-  close(cptr->fd);
-  loc_clients[cptr->fd] = NULL;
-  if (cptr->acpt)
-    ClearAskedPing(cptr->acpt);
-  RunFree((char *)cptr->confs);
-  free_client(cptr);
-}
-
-void cancel_ping(aClient *sptr, aClient *acptr)
-{
-  int i;
-  aClient *cptr;
-
-  Debug((DEBUG_DEBUG, "Cancelling uping for %p (%s)", sptr, sptr->name));
-  for (i = highest_fd; i >= 0; i--)
-    if ((cptr = loc_clients[i]) && IsPing(cptr) && cptr->acpt == sptr)
-    {
-      cptr->acpt = acptr;
-      del_queries((char *)cptr);
-      end_ping(cptr);
-      break;
-    }
-
-  ClearAskedPing(sptr);
-}
index 77e97aaafd8bf091882126b64a555f73f9f49e52..f9304801324a9355f8d4d9fea1e5190c68172d2f 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdlib.h>
-#include "h.h"
-#include "struct.h"
-#include "ircd.h"
 #include "s_serv.h"
-#include "s_misc.h"
-#include "sprintf_irc.h"
-#include "send.h"
-#include "s_err.h"
-#include "numeric.h"
-#include "s_bsd.h"
-#include "s_conf.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "client.h"
+#include "crule.h"
 #include "hash.h"
-#include "common.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "ircd_xopen.h"
+#include "list.h"
+#include "msg.h"
 #include "match.h"
-#include "crule.h"
-#include "parse.h"
+#include "numeric.h"
 #include "numnicks.h"
-#include "userload.h"
-#include "s_user.h"
-#include "channel.h"
+#include "parse.h"
 #include "querycmds.h"
-#include "IPcheck.h"
-
-RCSTAG_CC("$Id$");
-
-static int exit_new_server(aClient *cptr, aClient *sptr,
-    char *host, time_t timestamp, char *fmt, ...)
-    __attribute__ ((format(printf, 5, 6)));
-
-/* *INDENT-OFF* */
-
-#ifdef CRYPT_LINK_PASSWORD
-__BEGIN_DECLS
-/* This is not ANSI, but we have it anyway... */
-char *crypt(const char *key, const char *salt);
-__END_DECLS
-#endif /* CRYPT_LINK_PASSWORD */
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sprintf_irc.h"
+#include "struct.h"
+#include "sys.h"
+#include "userload.h"
 
-/* *INDENT-ON* */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
 
-unsigned int max_connection_count = 0, max_client_count = 0;
+unsigned int max_connection_count = 0;
+unsigned int max_client_count = 0;
 
-static int exit_new_server(aClient *cptr, aClient *sptr,
+int exit_new_server(struct Client *cptr, struct Client *sptr,
     char *host, time_t timestamp, char *fmt, ...)
 {
   va_list vl;
   char *buf =
-      (char *)RunMalloc(strlen(me.name) + strlen(host) + 22 + strlen(fmt));
+      (char*) MyMalloc(strlen(me.name) + strlen(host) + 22 + strlen(fmt));
+  assert(0 != buf);
   va_start(vl, fmt);
   if (!IsServer(sptr))
     return vexit_client_msg(cptr, cptr, &me, fmt, vl);
@@ -78,763 +72,93 @@ static int exit_new_server(aClient *cptr, aClient *sptr,
   strcat(buf, fmt);
   vsendto_one(cptr, buf, vl);
   va_end(vl);
-  RunFree(buf);
+  MyFree(buf);
   return 0;
 }
 
-static int a_kills_b_too(aClient *a, aClient *b)
+int a_kills_b_too(struct Client *a, struct Client *b)
 {
   for (; b != a && b != &me; b = b->serv->up);
   return (a == b ? 1 : 0);
 }
 
-extern unsigned short server_port;
-
 /*
- *  m_server
+ * server_estab
  *
- *    parv[0] = sender prefix
- *    parv[1] = servername
- *    parv[2] = hopcount
- *    parv[3] = start timestamp
- *    parv[4] = link timestamp
- *    parv[5] = major protocol version: P09/P10
- *    parv[parc-1] = serverinfo
- *  If cptr is P10:
- *    parv[6] = "YMM", where 'Y' is the server numeric and "MM" is the
- *              numeric nick mask of this server.
- *    parv[7] = 0 (not used yet, mandatory unsigned int after u2.10.06)
+ * May only be called after a SERVER was received from cptr,
+ * and thus make_server was called, and serv->prot set. --Run
  */
-int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
+int server_estab(struct Client *cptr, struct ConfItem *aconf)
 {
-  Reg1 char *ch;
-  Reg2 int i;
-  char info[REALLEN + 1], *inpath, *host, *s;
-  aClient *acptr, *bcptr, *LHcptr = NULL;
-  aConfItem *aconf = NULL, *bconf = NULL, *cconf, *lhconf = NULL;
-  int hop, ret, active_lh_line = 0;
-  unsigned short int prot;
-  time_t start_timestamp, timestamp = 0, recv_time, ghost = 0;
-
-  if (IsUser(cptr))
-  {
-    sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
-    return 0;
-  }
+  struct Client* acptr = 0;
+  const char*    inpath;
+  int split,     i;
 
-  if (IsUserPort(cptr))
-    return exit_client_msg(cptr, cptr, &me,
-       "You cannot connect a server to a user port; connect to %s port %u",
-       me.name, server_port);
+  assert(0 != cptr);
+  assert(0 != cptr->local);
 
-  recv_time = TStime();
-  info[0] = '\0';
+  split = (0 != ircd_strcmp(cptr->name, cptr->sockhost)
+      &&   0 != ircd_strncmp(cptr->info, "JUPE", 4));
   inpath = cptr->name;
-  if (parc < 7)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SERVER");
-    return exit_client(cptr, cptr, &me, "Need more parameters");
-  }
-  host = parv[1];
-  /* Detect protocol */
-  if (strlen(parv[5]) != 3 || (parv[5][0] != 'P' && parv[5][0] != 'J'))
-    return exit_client_msg(cptr, sptr, &me, "Bogus protocol (%s)", parv[5]);
-  if (!IsServer(cptr))         /* Don't allow silently connecting a server */
-    *parv[5] = 'J';
-  prot = atoi(parv[5] + 1);
-  if (prot > atoi(MAJOR_PROTOCOL))
-    prot = atoi(MAJOR_PROTOCOL);
-  /* Because the previous test is only in 2.10, the following is needed
-   * till all servers are 2.10: */
-  if (IsServer(cptr) && prot > Protocol(cptr))
-    prot = Protocol(cptr);
-  hop = atoi(parv[2]);
-  start_timestamp = atoi(parv[3]);
-  timestamp = atoi(parv[4]);
-  Debug((DEBUG_INFO, "Got SERVER %s with timestamp [%s] age " TIME_T_FMT " ("
-      TIME_T_FMT ")", host, parv[4], start_timestamp, me.serv->timestamp));
-  if ((timestamp < 780000000 || (hop == 1 && start_timestamp < 780000000)))
-  {
-    return exit_client_msg(cptr, sptr, &me,
-       "Bogus timestamps (%s %s)", parv[3], parv[4]);
-  }
-  strncpy(info, parv[parc - 1], REALLEN);
-  info[REALLEN] = 0;
-  if (prot < atoi(MINOR_PROTOCOL))
-  {
-    sendto_ops("Got incompatible protocol version (%s) from %s",
-       parv[5], get_client_name(cptr, FALSE));
-    return exit_new_server(cptr, sptr, host, timestamp,
-       "Incompatible protocol: %s", parv[5]);
-  }
-  /*
-   * Check for "FRENCH " infection ;-) (actually this should
-   * be replaced with routine to check the hostname syntax in
-   * general). [ This check is still needed, even after the parse
-   * is fixed, because someone can send "SERVER :foo bar " ].
-   * Also, changed to check other "difficult" characters, now
-   * that parse lets all through... --msa
-   */
-  if (strlen(host) > HOSTLEN)
-    host[HOSTLEN] = '\0';
-  for (ch = host; *ch; ch++)
-    if (*ch <= ' ' || *ch > '~')
-      break;
-  if (*ch || !strchr(host, '.'))
-  {
-    sendto_ops("Bogus server name (%s) from %s",
-       host, get_client_name(cptr, FALSE));
-    return exit_client_msg(cptr, cptr, &me, "Bogus server name (%s)", host);
-  }
 
-  if (IsServer(cptr))
-  {
+  if (IsUnknown(cptr)) {
+    if (aconf->passwd[0])
+      sendto_one(cptr, "PASS :%s", aconf->passwd);
     /*
-     * A local server introduces a new server behind this link.
-     * Check if this is allowed according L:, H: and Q: lines.
+     *  Pass my info to the new server
      */
-    if (info[0] == '\0')
-      return exit_client_msg(cptr, cptr, &me,
-         "No server info specified for %s", host);
-
+    sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
+        me.name, me.serv->timestamp, cptr->serv->timestamp,
+        MAJOR_PROTOCOL, NumServCap(&me),
+        (me.info[0]) ? (me.info) : "IRCers United");
     /*
-     * See if the newly found server is behind a guaranteed
-     * leaf (L-line). If so, close the link.
+     * Don't charge this IP# for connecting
+     * XXX - if this comes from a server port, it will not have been added
+     * to the IP check registry, see add_connection in s_bsd.c 
      */
-    if ((lhconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
-       (!lhconf->port || (hop > lhconf->port)))
-    {
-      /*
-       * L: lines normally come in pairs, here we try to
-       * make sure that the oldest link is squitted, not
-       * both.
-       */
-      active_lh_line = 1;
-      if (timestamp <= cptr->serv->timestamp)
-       LHcptr = NULL;          /* Kill incoming server */
-      else
-       LHcptr = cptr;          /* Squit ourselfs */
-    }
-    else if (!(lhconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
-       (lhconf->port && (hop > lhconf->port)))
-    {
-      aClient *ac3ptr;
-      active_lh_line = 2;
-      /* Look for net junction causing this: */
-      LHcptr = NULL;           /* incoming server */
-      if (*parv[5] != 'J')
-       for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
-         if (IsJunction(ac3ptr))
-         {
-           LHcptr = ac3ptr;
-           break;
-         }
-    }
+    IPcheck_connect_fail(cptr->ip);
   }
 
-  if (IsUnknown(cptr) || IsHandshake(cptr))
-  {
-    char *encr;
-
-    /*
-     * A local link that is still in undefined state wants
-     * to be a SERVER. Check if this is allowed and change
-     * status accordingly...
-     */
-    /*
-     * If there is more then one server on the same machine
-     * that we try to connect to, it could be that the /CONNECT
-     * <mask> caused this connect to be put at the wrong place
-     * in the hashtable.        --Run
-     * Same thing for Unknown connections that first send NICK.
-     *                          --Xorath
-     * Better check if the two strings are (caseless) identical 
-     * and not mess with hash internals. 
-     *                          --Nemesi
-     */
-    if ((!(BadPtr(cptr->name)))
-       && (IsUnknown(cptr) || IsHandshake(cptr))
-       && strCasediff(cptr->name, host))
-      hChangeClient(cptr, host);
-    strncpy(cptr->name, host, sizeof(cptr->name) - 1);
-    strncpy(cptr->info, info[0] ? info : me.name, sizeof(cptr->info) - 1);
-    cptr->hopcount = hop;
-
-    /* check connection rules */
-    for (cconf = conf; cconf; cconf = cconf->next)
-      if ((cconf->status == CONF_CRULEALL) && (match(cconf->host, host) == 0))
-       if (crule_eval(cconf->passwd))
-       {
-         ircstp->is_ref++;
-         sendto_ops("Refused connection from %s.", cptr->name);
-         return exit_client(cptr, cptr, &me, "Disallowed by connection rule");
-       }
+  det_confs_butmask(cptr, CONF_LEAF | CONF_HUB | CONF_SERVER | CONF_UWORLD);
 
-    if (check_server(cptr))
-    {
-      ircstp->is_ref++;
-      sendto_ops("Received unauthorized connection from %s.", cptr->name);
-      return exit_client(cptr, cptr, &me, "No C/N conf lines");
-    }
-
-    host = cptr->name;
-
-    update_load();
-
-    if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
-    {
-      ircstp->is_ref++;
-#ifndef GODMODE
-      sendto_ops("Access denied. No N line for server %s", inpath);
-      return exit_client_msg(cptr, cptr, &me,
-         "Access denied. No N line for server %s", inpath);
-#else /* GODMODE */
-      sendto_ops("General C/N: line active: No N line for server %s", inpath);
-      aconf =
-         find_conf(cptr->confs, "general.undernet.org", CONF_NOCONNECT_SERVER);
-      bconf =
-         find_conf(cptr->confs, "general.undernet.org", CONF_CONNECT_SERVER);
-      if (!aconf || !bconf)
-      {
-       sendto_ops("Neither C/N lines for server %s nor "
-           "\"general.undernet.org\"", inpath);
-       return exit_client_msg(cptr, cptr, &me,
-           "No C/N lines for server %s", inpath);
-      }
-#endif /* GODMODE */
-    }
-    else if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
-    {
-      ircstp->is_ref++;
-      sendto_ops("Only N (no C) field for server %s", inpath);
-      return exit_client_msg(cptr, cptr, &me,
-         "Only N (no C) field for server %s", inpath);
-    }
+  if (!IsHandshake(cptr))
+    hAddClient(cptr);
+  SetServer(cptr);
+  cptr->handler = SERVER_HANDLER;
+  Count_unknownbecomesserver(UserStats);
 
-#ifdef CRYPT_LINK_PASSWORD
-    /* passwd may be NULL. Head it off at the pass... */
-    if (*cptr->passwd)
-    {
-      char salt[3];
+  release_dns_reply(cptr);
 
-      salt[0] = aconf->passwd[0];
-      salt[1] = aconf->passwd[1];
-      salt[2] = '\0';
-      encr = crypt(cptr->passwd, salt);
-    }
-    else
-      encr = "";
-#else
-    encr = cptr->passwd;
-#endif /* CRYPT_LINK_PASSWORD */
-#ifndef GODMODE
-    if (*aconf->passwd && !!strcmp(aconf->passwd, encr))
-    {
-      ircstp->is_ref++;
-      sendto_ops("Access denied (passwd mismatch) %s", inpath);
-      return exit_client_msg(cptr, cptr, &me,
-         "No Access (passwd mismatch) %s", inpath);
-    }
-#endif /* not GODMODE */
-    memset(cptr->passwd, 0, sizeof(cptr->passwd));
+  SetBurst(cptr);
 
-#ifndef HUB
-    for (i = 0; i <= highest_fd; i++)
-      if (loc_clients[i] && IsServer(loc_clients[i]))
-      {
-       active_lh_line = 3;
-       LHcptr = NULL;
-       break;
-      }
-#endif
-    if (!IsUnknown(cptr))
-    {
-      s = strchr(aconf->host, '@');
-      *s = '\0';               /* should never be NULL */
-      Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
-         aconf->host, cptr->username));
-      if (match(aconf->host, cptr->username))
-      {
-       *s = '@';
-       ircstp->is_ref++;
-       sendto_ops("Username mismatch [%s]v[%s] : %s",
-           aconf->host, cptr->username, get_client_name(cptr, FALSE));
-       return exit_client(cptr, cptr, &me, "Bad Username");
-      }
-      *s = '@';
-    }
-  }
+  nextping = CurrentTime;
 
   /*
-   *  We want to find IsConnecting() and IsHandshake() too,
-   *  use FindClient().
-   *  The second finds collisions with numeric representation of existing
-   *  servers - these shouldn't happen anymore when all upgraded to 2.10.
-   *  -- Run
+   * NOTE: check for acptr->user == cptr->serv->user is necessary to insure
+   * that we got the same one... bleah
    */
-  while ((acptr = FindClient(host)) ||
-      (parc > 7 && (acptr = FindNServer(parv[6]))))
-  {
-    /*
-     *  This link is trying feed me a server that I already have
-     *  access through another path
-     *
-     *  Do not allow Uworld to do this.
-     *  Do not allow servers that are juped.
-     *  Do not allow servers that have older link timestamps
-     *    then this try.
-     *  Do not allow servers that use the same numeric as an existing
-     *    server, but have a different name.
-     *
-     *  If my ircd.conf sucks, I can try to connect to myself:
-     */
-    if (acptr == &me)
-      return exit_client_msg(cptr, cptr, &me,
-         "nick collision with me (%s)", host);
-    /*
-     * Detect wrong numeric.
-     */
-    if (strCasediff(acptr->name, host))
-    {
-      sendto_serv_butone(cptr,
-         ":%s WALLOPS :SERVER Numeric Collision: %s != %s",
-         me.name, acptr->name, host);
-      return exit_client_msg(cptr, cptr, &me,
-         "NUMERIC collision between %s and %s."
-         " Is your server numeric correct ?", host, acptr->name);
-    }
-    /*
-     *  Kill our try, if we had one.
-     */
-    if (IsConnecting(acptr))
-    {
-      if (!active_lh_line && exit_client(cptr, acptr, &me,
-         "Just connected via another link") == CPTR_KILLED)
-       return CPTR_KILLED;
-      /*
-       * We can have only ONE 'IsConnecting', 'IsHandshake' or
-       * 'IsServer', because new 'IsConnecting's are refused to
-       * the same server if we already had it.
-       */
-      break;
-    }
-    /*
-     * Avoid other nick collisions...
-     * This is a doubtfull test though, what else would it be
-     * when it has a server.name ?
-     */
-    else if (!IsServer(acptr) && !IsHandshake(acptr))
-      return exit_client_msg(cptr, cptr, &me,
-         "Nickname %s already exists!", host);
-    /*
-     * Our new server might be a juped server,
-     * or someone trying abuse a second Uworld:
-     */
-    else if (IsServer(acptr) && (strnCasecmp(acptr->info, "JUPE", 4) == 0 ||
-       find_conf_host(cptr->confs, acptr->name, CONF_UWORLD)))
-    {
-      if (!IsServer(sptr))
-       return exit_client(cptr, sptr, &me, acptr->info);
-      sendto_one(cptr, ":%s WALLOPS :Received :%s SERVER %s from %s !?!",
-         me.name, parv[0], parv[1], cptr->name);
-      return exit_new_server(cptr, sptr, host, timestamp, "%s", acptr->info);
-    }
-    /*
-     * Of course we find the handshake this link was before :)
-     */
-    else if (IsHandshake(acptr) && acptr == cptr)
-      break;
-    /*
-     * Here we have a server nick collision...
-     * We don't want to kill the link that was last /connected,
-     * but we neither want to kill a good (old) link.
-     * Therefor we kill the second youngest link.
-     */
-    if (1)
-    {
-      aClient *c2ptr = NULL, *c3ptr = acptr;
-      aClient *ac2ptr, *ac3ptr;
-
-      /* Search youngest link: */
-      for (ac3ptr = acptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
-       if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
-         c3ptr = ac3ptr;
-      if (IsServer(sptr))
-      {
-       for (ac3ptr = sptr; ac3ptr != &me; ac3ptr = ac3ptr->serv->up)
-         if (ac3ptr->serv->timestamp > c3ptr->serv->timestamp)
-           c3ptr = ac3ptr;
-      }
-      if (timestamp > c3ptr->serv->timestamp)
-      {
-       c3ptr = NULL;
-       c2ptr = acptr;          /* Make sure they differ */
-      }
-      /* Search second youngest link: */
-      for (ac2ptr = acptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
-       if (ac2ptr != c3ptr &&
-           ac2ptr->serv->timestamp >
-           (c2ptr ? c2ptr->serv->timestamp : timestamp))
-         c2ptr = ac2ptr;
-      if (IsServer(sptr))
-      {
-       for (ac2ptr = sptr; ac2ptr != &me; ac2ptr = ac2ptr->serv->up)
-         if (ac2ptr != c3ptr &&
-             ac2ptr->serv->timestamp >
-             (c2ptr ? c2ptr->serv->timestamp : timestamp))
-           c2ptr = ac2ptr;
-      }
-      if (c3ptr && timestamp > (c2ptr ? c2ptr->serv->timestamp : timestamp))
-       c2ptr = NULL;
-      /* If timestamps are equal, decide which link to break
-       *  by name.
-       */
-      if ((c2ptr ? c2ptr->serv->timestamp : timestamp) ==
-         (c3ptr ? c3ptr->serv->timestamp : timestamp))
-      {
-       char *n2, *n2up;
-       char *n3, *n3up;
-       if (c2ptr)
-       {
-         n2 = c2ptr->name;
-         n2up = MyConnect(c2ptr) ? me.name : c2ptr->serv->up->name;
-       }
-       else
-       {
-         n2 = host;
-         n2up = IsServer(sptr) ? sptr->name : me.name;
-       }
-       if (c3ptr)
-       {
-         n3 = c3ptr->name;
-         n3up = MyConnect(c3ptr) ? me.name : c3ptr->serv->up->name;
-       }
-       else
-       {
-         n3 = host;
-         n3up = IsServer(sptr) ? sptr->name : me.name;
-       }
-       if (strcmp(n2, n2up) > 0)
-         n2 = n2up;
-       if (strcmp(n3, n3up) > 0)
-         n3 = n3up;
-       if (strcmp(n3, n2) > 0)
-       {
-         ac2ptr = c2ptr;
-         c2ptr = c3ptr;
-         c3ptr = ac2ptr;
-       }
-      }
-      /* Now squit the second youngest link: */
-      if (!c2ptr)
-       return exit_new_server(cptr, sptr, host, timestamp,
-           "server %s already exists and is %ld seconds younger.",
-           host, (long)acptr->serv->timestamp - (long)timestamp);
-      else if (c2ptr->from == cptr || IsServer(sptr))
-      {
-       aClient *killedptrfrom = c2ptr->from;
-       if (active_lh_line)
-       {
-         /*
-          * If the L: or H: line also gets rid of this link,
-          * we sent just one squit.
-          */
-         if (LHcptr && a_kills_b_too(LHcptr, c2ptr))
-           break;
-         /*
-          * If breaking the loop here solves the L: or H:
-          * line problem, we don't squit that.
-          */
-         if (c2ptr->from == cptr || (LHcptr && a_kills_b_too(c2ptr, LHcptr)))
-           active_lh_line = 0;
-         else
-         {
-           /*
-            * If we still have a L: or H: line problem,
-            * we prefer to squit the new server, solving
-            * loop and L:/H: line problem with only one squit.
-            */
-           LHcptr = NULL;
-           break;
-         }
-       }
-       /*
-        * If the new server was introduced by a server that caused a
-        * Ghost less then 20 seconds ago, this is probably also
-        * a Ghost... (20 seconds is more then enough because all
-        * SERVER messages are at the beginning of a net.burst). --Run
-        */
-       if (now - cptr->serv->ghost < 20)
-       {
-         killedptrfrom = acptr->from;
-         if (exit_client(cptr, acptr, &me, "Ghost loop") == CPTR_KILLED)
-           return CPTR_KILLED;
-       }
-       else if (exit_client_msg(cptr, c2ptr, &me,
-           "Loop <-- %s (new link is %ld seconds younger)", host,
-           (c3ptr ? (long)c3ptr->serv->timestamp : timestamp) -
-           (long)c2ptr->serv->timestamp) == CPTR_KILLED)
-         return CPTR_KILLED;
-       /*
-        * Did we kill the incoming server off already ?
-        */
-       if (killedptrfrom == cptr)
-         return 0;
-      }
+  if (cptr->serv->user && *cptr->serv->by &&
+      (acptr = findNUser(cptr->serv->by))) {
+    if (acptr->user == cptr->serv->user) {
+      if (MyUser(acptr))
+        sendto_one(acptr, ":%s NOTICE %s :Link with %s established.",
+                   me.name, acptr->name, inpath);
       else
-      {
-       if (active_lh_line)
-       {
-         if (LHcptr && a_kills_b_too(LHcptr, acptr))
-           break;
-         if (acptr->from == cptr || (LHcptr && a_kills_b_too(acptr, LHcptr)))
-           active_lh_line = 0;
-         else
-         {
-           LHcptr = NULL;
-           break;
-         }
-       }
-       /*
-        * We can't believe it is a lagged server message
-        * when it directly connects to us...
-        * kill the older link at the ghost, rather then
-        * at the second youngest link, assuming it isn't
-        * a REAL loop.
-        */
-       ghost = now;            /* Mark that it caused a ghost */
-       if (exit_client(cptr, acptr, &me, "Ghost") == CPTR_KILLED)
-         return CPTR_KILLED;
-       break;
-      }
+        sendto_one(acptr, "%s NOTICE %s%s :Link with %s established.",
+                   NumServ(&me), NumNick(acptr), inpath);
     }
-  }
-
-  if (active_lh_line)
-  {
-    if (LHcptr == NULL)
-      return exit_new_server(cptr, sptr, host, timestamp,
-         (active_lh_line == 2) ?
-         "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
-         cptr->name, host,
-         lhconf ? (lhconf->host ? lhconf->host : "*") : "!");
-    else
-    {
-      register int killed = a_kills_b_too(LHcptr, sptr);
-      if (active_lh_line < 3)
-      {
-       if (exit_client_msg(cptr, LHcptr, &me,
-           (active_lh_line == 2) ?
-           "Non-Hub link %s <- %s(%s)" : "Leaf-only link %s <- %s(%s)",
-           cptr->name, host,
-           lhconf ? (lhconf->host ? lhconf->host : "*") : "!") == CPTR_KILLED)
-         return CPTR_KILLED;
-      }
-      else
-      {
-       ircstp->is_ref++;
-       if (exit_client(cptr, LHcptr, &me, "I'm a leaf") == CPTR_KILLED)
-         return CPTR_KILLED;
-      }
+    else {
       /*
-       * Did we kill the incoming server off already ?
+       * if not the same client, set by to empty string
        */
-      if (killed)
-       return 0;
+      acptr = 0;
+      *cptr->serv->by = '\0';
     }
   }
 
-  if (IsServer(cptr))
-  {
-    /*
-     * Server is informing about a new server behind
-     * this link. Create REMOTE server structure,
-     * add it to list and propagate word to my other
-     * server links...
-     */
-
-    acptr = make_client(cptr, STAT_SERVER);
-    make_server(acptr);
-    acptr->serv->prot = prot;
-    acptr->serv->timestamp = timestamp;
-    acptr->hopcount = hop;
-    strncpy(acptr->name, host, sizeof(acptr->name) - 1);
-    strncpy(acptr->info, info, sizeof(acptr->info) - 1);
-    acptr->serv->up = sptr;
-    acptr->serv->updown = add_dlink(&sptr->serv->down, acptr);
-    /* Use cptr, because we do protocol 9 -> 10 translation
-       for numeric nicks ! */
-    SetServerYXX(cptr, acptr, parv[6]);
-    Count_newremoteserver(nrof);
-    if (Protocol(acptr) < 10)
-      acptr->flags |= FLAGS_TS8;
-    add_client_to_list(acptr);
-    hAddClient(acptr);
-    if (*parv[5] == 'J')
-    {
-      if (Protocol(acptr) > 9)
-       SetBurst(acptr);
-      sendto_op_mask(SNO_NETWORK, "Net junction: %s %s",
-         sptr->name, acptr->name);
-      SetJunction(acptr);
-    }
-    /*
-     * Old sendto_serv_but_one() call removed because we now need to send
-     * different names to different servers (domain name matching).
-     */
-    for (i = 0; i <= highest_fd; i++)
-    {
-      if (!(bcptr = loc_clients[i]) || !IsServer(bcptr) ||
-         bcptr == cptr || IsMe(bcptr))
-       continue;
-      if (!(cconf = bcptr->serv->nline))
-      {
-       sendto_ops("Lost N-line for %s on %s. Closing",
-           cptr->name, host);
-       return exit_client(cptr, cptr, &me, "Lost N line");
-      }
-      if (match(my_name_for_link(me.name, cconf), acptr->name) == 0)
-       continue;
-      if (Protocol(bcptr) > 9)
-       sendto_one(bcptr, "%s SERVER %s %d 0 %s %s %s%s 0 :%s",
-           NumServ(sptr), acptr->name, hop + 1, parv[4], parv[5],
-           NumServCap(acptr), acptr->info);
-      else
-       sendto_one(bcptr, ":%s SERVER %s %d 0 %s %s %s%s 0 :%s",
-           parv[0], acptr->name, hop + 1, parv[4], parv[5],
-           NumServCap(acptr), acptr->info);
-    }
-    return 0;
-  }
-
-  if (IsUnknown(cptr) || IsHandshake(cptr))
-  {
-    make_server(cptr);
-    cptr->serv->timestamp = timestamp;
-    cptr->serv->prot = prot;
-    cptr->serv->ghost = ghost;
-    SetServerYXX(cptr, cptr, parv[6]);
-    if (start_timestamp > 780000000)
-    {
-#ifndef RELIABLE_CLOCK
-#ifdef TESTNET
-      sendto_ops("Debug: my start time: " TIME_T_FMT " ; others start time: "
-         TIME_T_FMT, me.serv->timestamp, start_timestamp);
-      sendto_ops("Debug: receive time: " TIME_T_FMT " ; received timestamp: "
-         TIME_T_FMT " ; difference %ld",
-         recv_time, timestamp, timestamp - recv_time);
-#endif
-      if (start_timestamp < me.serv->timestamp)
-      {
-       sendto_ops("got earlier start time: " TIME_T_FMT " < " TIME_T_FMT,
-           start_timestamp, me.serv->timestamp);
-       me.serv->timestamp = start_timestamp;
-       TSoffset += timestamp - recv_time;
-       sendto_ops("clock adjusted by adding %d", (int)(timestamp - recv_time));
-      }
-      else if ((start_timestamp > me.serv->timestamp) && IsUnknown(cptr))
-       cptr->serv->timestamp = TStime();
-
-      else if (timestamp != recv_time)
-       /* Equal start times, we have a collision.  Let the connected-to server
-          decide. This assumes leafs issue more than half of the connection
-          attempts. */
-      {
-       if (IsUnknown(cptr))
-         cptr->serv->timestamp = TStime();
-       else if (IsHandshake(cptr))
-       {
-         sendto_ops("clock adjusted by adding %d",
-             (int)(timestamp - recv_time));
-         TSoffset += timestamp - recv_time;
-       }
-      }
-#else /* RELIABLE CLOCK IS TRUE, we _always_ use our own clock */
-      if (start_timestamp < me.serv->timestamp)
-       me.serv->timestamp = start_timestamp;
-      if (IsUnknown(cptr))
-       cptr->serv->timestamp = TStime();
-#endif
-    }
-
-    ret = m_server_estab(cptr, aconf, bconf);
-  }
-  else
-    ret = 0;
-#ifdef RELIABLE_CLOCK
-  if (abs(cptr->serv->timestamp - recv_time) > 30)
-  {
-    sendto_ops("Connected to a net with a timestamp-clock"
-       " difference of " STIME_T_FMT " seconds! Used SETTIME to correct"
-       " this.", timestamp - recv_time);
-    sendto_one(cptr, ":%s SETTIME " TIME_T_FMT " :%s",
-       me.name, TStime(), me.name);
-  }
-#endif
-
-  return ret;
-}
-
-/*
- * m_server_estab
- *
- * May only be called after a SERVER was received from cptr,
- * and thus make_server was called, and serv->prot set. --Run
- */
-int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
-{
-  Reg3 aClient *acptr;
-  char *inpath, *host;
-  int split, i;
-
-  split = (strCasediff(cptr->name, cptr->sockhost)
-      && strnCasecmp(cptr->info, "JUPE", 4));
-  inpath = cptr->name;
-  host = cptr->name;
-
-  if (IsUnknown(cptr))
-  {
-    if (bconf->passwd[0])
-      sendto_one(cptr, "PASS :%s", bconf->passwd);
-    /*
-     *  Pass my info to the new server
-     */
-    sendto_one(cptr, "SERVER %s 1 " TIME_T_FMT " " TIME_T_FMT " J%s %s%s :%s",
-       my_name_for_link(me.name, aconf), me.serv->timestamp,
-       cptr->serv->timestamp, MAJOR_PROTOCOL, NumServCap(&me),
-       (me.info[0]) ? (me.info) : "IRCers United");
-
-    IPcheck_connect_fail(cptr);        /* Don't charge this IP# for connecting */
-  }
-
-  det_confs_butmask(cptr,
-      CONF_LEAF | CONF_HUB | CONF_NOCONNECT_SERVER | CONF_UWORLD);
-
-  if (!IsHandshake(cptr))
-    hAddClient(cptr);
-  SetServer(cptr);
-  Count_unknownbecomesserver(nrof);
-  if (Protocol(cptr) > 9)
-    SetBurst(cptr);
-  else
-    cptr->flags |= FLAGS_TS8;
-  nextping = now;
-  if (cptr->serv->user && *cptr->serv->by &&
-      (acptr = findNUser(cptr->serv->by)) && acptr->user == cptr->serv->user)
-  {
-    if (MyUser(acptr) || Protocol(acptr->from) < 10)
-      sendto_one(acptr, ":%s NOTICE %s :Link with %s established.",
-         me.name, acptr->name, inpath);
-    else
-      sendto_one(acptr, "%s NOTICE %s%s :Link with %s established.",
-         NumServ(&me), NumNick(acptr), inpath);
-  }
-  else
-    acptr = NULL;
   sendto_lops_butone(acptr, "Link with %s established.", inpath);
   cptr->serv->up = &me;
   cptr->serv->updown = add_dlink(&me.serv->down, cptr);
-  cptr->serv->nline = aconf;
   sendto_op_mask(SNO_NETWORK, "Net junction: %s %s", me.name, cptr->name);
   SetJunction(cptr);
   /*
@@ -842,41 +166,26 @@ int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
    * need to send different names to different servers
    * (domain name matching) Send new server to other servers.
    */
-  for (i = 0; i <= highest_fd; i++)
+  for (i = 0; i <= HighestFd; i++)
   {
-    if (!(acptr = loc_clients[i]) || !IsServer(acptr) ||
-       acptr == cptr || IsMe(acptr))
+    if (!(acptr = LocalClientArray[i]) || !IsServer(acptr) ||
+        acptr == cptr || IsMe(acptr))
       continue;
-    if ((aconf = acptr->serv->nline) &&
-       !match(my_name_for_link(me.name, aconf), cptr->name))
+    if (!match(me.name, cptr->name))
       continue;
     if (split)
     {
-      if (Protocol(acptr) > 9)
-       sendto_one(acptr,
-           "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-           NumServ(&me), cptr->name, cptr->serv->timestamp,
-           (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
-           cptr->info);
-      else
-       sendto_one(acptr,
-           ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s", me.name,
-           cptr->name, cptr->serv->timestamp,
-           (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr), NumServCap(cptr),
-           cptr->info);
+        sendto_one(acptr, "%s " TOK_SERVER " %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
+            NumServ(&me), cptr->name, cptr->serv->timestamp,
+            (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
+            NumServCap(cptr), cptr->info);
     }
     else
     {
-      if (Protocol(acptr) > 9)
-       sendto_one(acptr, "%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-           NumServ(&me), cptr->name, cptr->serv->timestamp,
-           (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
-           NumServCap(cptr), cptr->info);
-      else
-       sendto_one(acptr, ":%s SERVER %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-           me.name, cptr->name, cptr->serv->timestamp,
-           (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
-           NumServCap(cptr), cptr->info);
+        sendto_one(acptr, "%s " TOK_SERVER " %s 2 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
+            NumServ(&me), cptr->name, cptr->serv->timestamp,
+            (Protocol(cptr) > 9) ? "J" : "J0", Protocol(cptr),
+            NumServCap(cptr), cptr->info);
     }
   }
 
@@ -895,51 +204,35 @@ int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
    * a race condition, not the normal way of operation...
    */
 
-  aconf = cptr->serv->nline;
-  for (acptr = &me; acptr; acptr = acptr->prev)
-  {
+  for (acptr = &me; acptr; acptr = acptr->prev) {
     /* acptr->from == acptr for acptr == cptr */
     if (acptr->from == cptr)
       continue;
     if (IsServer(acptr))
     {
-      char *protocol_str =
-         (Protocol(acptr) > 9) ? (IsBurst(acptr) ? "J" : "P") : "P0";
-      if (match(my_name_for_link(me.name, aconf), acptr->name) == 0)
-       continue;
-      split = (MyConnect(acptr) && strCasediff(acptr->name, acptr->sockhost) &&
-         strnCasecmp(acptr->info, "JUPE", 4));
+      char *protocol_str = IsBurst(acptr) ? "J" : "P";
+      if (0 == match(me.name, acptr->name))
+        continue;
+      split = (MyConnect(acptr) && 
+               0 != ircd_strcmp(acptr->name, acptr->sockhost) &&
+               0 != ircd_strncmp(acptr->info, "JUPE", 4));
       if (split)
       {
-       if (Protocol(cptr) > 9)
-         sendto_one(cptr,
-             "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-             NumServ(acptr->serv->up), acptr->name,
-             acptr->hopcount + 1, acptr->serv->timestamp,
-             protocol_str, Protocol(acptr),
-             NumServCap(acptr), acptr->info);
-       else
-         sendto_one(cptr,
-             ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-             acptr->serv->up->name, acptr->name,
-             acptr->hopcount + 1, acptr->serv->timestamp,
-             protocol_str, Protocol(acptr),
-             NumServCap(acptr), acptr->info);
+          sendto_one(cptr,
+              "%s " TOK_SERVER " %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
+              NumServ(acptr->serv->up), acptr->name,
+              acptr->hopcount + 1, acptr->serv->timestamp,
+              protocol_str, Protocol(acptr),
+              NumServCap(acptr), acptr->info);
       }
       else
       {
-       if (Protocol(cptr) > 9)
-         sendto_one(cptr,
-             "%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-             NumServ(acptr->serv->up), acptr->name,
-             acptr->hopcount + 1, acptr->serv->timestamp,
-             protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
-       else
-         sendto_one(cptr,
-             ":%s SERVER %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
-             acptr->serv->up->name, acptr->name,
-             acptr->hopcount + 1, acptr->serv->timestamp,
-             protocol_str, Protocol(acptr), NumServCap(acptr), acptr->info);
+          sendto_one(cptr,
+              "%s " TOK_SERVER " %s %d 0 " TIME_T_FMT " %s%u %s%s 0 :%s",
+              NumServ(acptr->serv->up), acptr->name,
+              acptr->hopcount + 1, acptr->serv->timestamp,
+              protocol_str, Protocol(acptr), 
+              NumServCap(acptr), acptr->info);
       }
     }
   }
@@ -951,34 +244,16 @@ int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
       continue;
     if (IsUser(acptr))
     {
-      if (Protocol(cptr) < 10)
-      {
-       /*
-        * IsUser(x) is true only *BOTH* NICK and USER have
-        * been received. -avalon
-        * Or only NICK in new format. --Run
-        */
-       sendto_one(cptr, ":%s NICK %s %d " TIME_T_FMT " %s %s %s :%s",
-           acptr->user->server->name,
-           acptr->name, acptr->hopcount + 1, acptr->lastnick,
-           acptr->user->username, acptr->user->host,
-           acptr->user->server->name, acptr->info);
-       send_umode(cptr, acptr, 0, SEND_UMODES);
-       send_user_joins(cptr, acptr);
-      }
-      else
-      {
-       char xxx_buf[8];
-       char *s = umode_str(acptr);
-       sendto_one(cptr, *s ?
-           "%s NICK %s %d " TIME_T_FMT " %s %s +%s %s %s%s :%s" :
-           "%s NICK %s %d " TIME_T_FMT " %s %s %s%s %s%s :%s",
-           NumServ(acptr->user->server),
-           acptr->name, acptr->hopcount + 1, acptr->lastnick,
-           acptr->user->username, acptr->user->host,
-           s, inttobase64(xxx_buf, ntohl(acptr->ip.s_addr), 6),
-           NumNick(acptr), acptr->info);
-      }
+      char xxx_buf[8];
+      char *s = umode_str(acptr);
+      sendto_one(cptr, *s ?
+            "%s N %s %d " TIME_T_FMT " %s %s +%s %s %s%s :%s" :
+            "%s N %s %d " TIME_T_FMT " %s %s %s%s %s%s :%s",
+            NumServ(acptr->user->server),
+            acptr->name, acptr->hopcount + 1, acptr->lastnick,
+            acptr->user->username, acptr->user->host,
+            s, inttobase64(xxx_buf, ntohl(acptr->ip.s_addr), 6),
+            NumNick(acptr), acptr->info);
     }
   }
   /*
@@ -986,131 +261,11 @@ int m_server_estab(aClient *cptr, aConfItem *aconf, aConfItem *bconf)
    * (Or for 2.9 servers: pass all channels plus statuses)
    */
   {
-    Reg1 aChannel *chptr;
-    for (chptr = channel; chptr; chptr = chptr->nextch)
+    struct Channel *chptr;
+    for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
       send_channel_modes(cptr, chptr);
   }
-  if (Protocol(cptr) >= 10)
-    sendto_one(cptr, "%s END_OF_BURST", NumServ(&me));
-  return 0;
-}
-
-/*
- * m_error
- *
- * parv[0] = sender prefix
- * parv[parc-1] = text
- */
-int m_error(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 char *para;
-
-  para = (parc > 1 && *parv[parc - 1] != '\0') ? parv[parc - 1] : "<>";
-
-  Debug((DEBUG_ERROR, "Received ERROR message from %s: %s", sptr->name, para));
-  /*
-   * Ignore error messages generated by normal user clients
-   * (because ill-behaving user clients would flood opers
-   * screen otherwise). Pass ERROR's from other sources to
-   * the local operator...
-   */
-  if (IsUser(cptr))
-    return 0;
-  if (IsUnknown(cptr))
-    return exit_client_msg(cptr, cptr, &me, "Register first");
-
-  if (cptr == sptr)
-    sendto_ops("ERROR :from %s -- %s", cptr->name, para);
-  else
-    sendto_ops("ERROR :from %s via %s -- %s",
-       sptr->name, cptr->name, para);
-
-  if (sptr->serv)
-  {
-    RunFree(sptr->serv->last_error_msg);
-    DupString(sptr->serv->last_error_msg, para);
-  }
-
-  return 0;
-}
-
-/*
- * m_end_of_burst  - Added Xorath 6-14-96, rewritten by Run 24-7-96
- *                 - and fixed by record and Kev 8/1/96
- *                 - and really fixed by Run 15/8/96 :p
- * This the last message in a net.burst.
- * It clears a flag for the server sending the burst.
- *
- * parv[0] - sender prefix
- */
-int m_end_of_burst(aClient *cptr, aClient *sptr, int UNUSED(parc),
-    char **UNUSED(parv))
-{
-  if (!IsServer(sptr))
-    return 0;
-
-  sendto_op_mask(SNO_NETWORK, "Completed net.burst from %s.", sptr->name);
-#ifdef NO_PROTOCOL9
-  sendto_serv_butone(cptr, "%s END_OF_BURST", NumServ(sptr));
-#else
-  sendto_highprot_butone(cptr, 10, "%s END_OF_BURST", NumServ(sptr));
-#endif
-  ClearBurst(sptr);
-  SetBurstAck(sptr);
-  if (MyConnect(sptr))
-    sendto_one(sptr, "%s EOB_ACK", NumServ(&me));
-
-  return 0;
-}
-
-/*
- * m_end_of_burst_ack
- *
- * This the acknowledge message of the `END_OF_BURST' message.
- * It clears a flag for the server receiving the burst.
- *
- * parv[0] - sender prefix
- */
-int m_end_of_burst_ack(aClient *cptr, aClient *sptr, int UNUSED(parc),
-    char **UNUSED(parv))
-{
-  if (!IsServer(sptr))
-    return 0;
-
-  sendto_op_mask(SNO_NETWORK, "%s acknowledged end of net.burst.", sptr->name);
-#ifdef NO_PROTOCOL9
-  sendto_serv_butone(cptr, "%s EOB_ACK", NumServ(sptr));
-#else
-  sendto_highprot_butone(cptr, 10, "%s EOB_ACK", NumServ(sptr));
-#endif
-  ClearBurstAck(sptr);
-
+  sendto_one(cptr, "%s EB", NumServ(&me));
   return 0;
 }
 
-/*
- * m_desynch
- *
- * Writes to all +g users; for sending wall type debugging/anti-hack info.
- * Added 23 Apr 1998  --Run
- *
- * parv[0] - sender prefix
- * parv[parc-1] - message text
- */
-int m_desynch(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  if (IsServer(sptr) && parc >= 2)
-  {
-    int i;
-    aClient *acptr;
-    /* Send message to local +g clients as if it were a wallops */
-    sprintf_irc(sendbuf, ":%s WALLOPS :%s", parv[0], parv[parc - 1]);
-    for (i = 0; i <= highest_fd; i++)
-      if ((acptr = loc_clients[i]) && !IsServer(acptr) && !IsMe(acptr) &&
-         SendDebug(acptr))
-       sendbufto_one(acptr);
-    /* Send message to remote +g clients */
-    sendto_g_serv_butone(cptr, "%s DESYNCH :%s", NumServ(sptr), parv[parc - 1]);
-  }
-  return 0;
-}
index 1a6dba59b6c8c4804d7ededf0bf1b96383149a5c..c6e195f5d2a6aaeb6bfaeaf9e8b73c73454b0009 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <sys/stat.h>
-#include <utmp.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stdlib.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include "h.h"
-#include "struct.h"
-#include "common.h"
-#include "s_serv.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_conf.h"
-#include "s_misc.h"
-#include "match.h"
-#include "hash.h"
-#include "s_bsd.h"
-#include "whowas.h"
-#include "list.h"
-#include "s_err.h"
-#include "parse.h"
-#include "ircd.h"
-#include "s_user.h"
-#include "support.h"
 #include "s_user.h"
+#include "IPcheck.h"
 #include "channel.h"
-#include "random.h"
-#include "version.h"
+#include "class.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
 #include "msg.h"
-#include "userload.h"
+#include "numeric.h"
 #include "numnicks.h"
-#include "sprintf_irc.h"
+#include "parse.h"
 #include "querycmds.h"
-#include "IPcheck.h"
-#include "class.h"
+#include "random.h"
+#include "s_bsd.h"
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_serv.h" /* max_client_count */
+#include "send.h"
+#include "sprintf_irc.h"
+#include "struct.h"
+#include "support.h"
+#include "supported.h"
+#include "sys.h"
+#include "userload.h"
+#include "version.h"
+#include "whowas.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
 
-RCSTAG_CC("$Id$");
 
-/* *INDENT-OFF* */
+static int userCount = 0;
 
-/* This is not ANSI, but we have it anyway... */
-__BEGIN_DECLS
-char *crypt(const char *key, const char *salt);
-__END_DECLS
+/*
+ * 'make_user' add's an User information block to a client
+ * if it was not previously allocated.
+ */
+struct User *make_user(struct Client *cptr)
+{
+  assert(0 != cptr);
 
-/* *INDENT-ON* */
+  if (!cptr->user) {
+    cptr->user = (struct User*) MyMalloc(sizeof(struct User));
+    assert(0 != cptr->user);
 
-static char buf[BUFSIZE], buf2[BUFSIZE];
+    /* All variables are 0 by default */
+    memset(cptr->user, 0, sizeof(struct User));
+#ifdef  DEBUGMODE
+    ++userCount;
+#endif
+    cptr->user->refcnt = 1;
+  }
+  return cptr->user;
+}
 
 /*
- * m_functions execute protocol messages on this server:
- *
- *    cptr    is always NON-NULL, pointing to a *LOCAL* client
- *            structure (with an open socket connected!). This
- *            identifies the physical socket where the message
- *            originated (or which caused the m_function to be
- *            executed--some m_functions may call others...).
- *
- *    sptr    is the source of the message, defined by the
- *            prefix part of the message if present. If not
- *            or prefix not found, then sptr==cptr.
- *
- *            (!IsServer(cptr)) => (cptr == sptr), because
- *            prefixes are taken *only* from servers...
- *
- *            (IsServer(cptr))
- *                    (sptr == cptr) => the message didn't
- *                    have the prefix.
- *
- *                    (sptr != cptr && IsServer(sptr) means
- *                    the prefix specified servername. (?)
+ * free_user
  *
- *                    (sptr != cptr && !IsServer(sptr) means
- *                    that message originated from a remote
- *                    user (not local).
- *
- *            combining
- *
- *            (!IsServer(sptr)) means that, sptr can safely
- *            taken as defining the target structure of the
- *            message in this server.
- *
- *    *Always* true (if 'parse' and others are working correct):
- *
- *    1)      sptr->from == cptr  (note: cptr->from == cptr)
- *
- *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
- *            *cannot* be a local connection, unless it's
- *            actually cptr!). [MyConnect(x) should probably
- *            be defined as (x == x->from) --msa ]
- *
- *    parc    number of variable parameter strings (if zero,
- *            parv is allowed to be NULL)
- *
- *    parv    a NULL terminated list of parameter pointers,
- *
- *                    parv[0], sender (prefix string), if not present
- *                            this points to an empty string.
- *                    parv[1]...parv[parc-1]
- *                            pointers to additional parameters
- *                    parv[parc] == NULL, *always*
- *
- *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
- *                    non-NULL pointers.
+ * Decrease user reference count by one and release block, if count reaches 0.
+ */
+void free_user(struct User* user)
+{
+  assert(0 != user);
+  assert(0 < user->refcnt);
+
+  if (--user->refcnt == 0) {
+    if (user->away)
+      MyFree(user->away);
+    /*
+     * sanity check
+     */
+    assert(0 == user->joined);
+    assert(0 == user->invited);
+    assert(0 == user->channel);
+
+    MyFree(user);
+#ifdef  DEBUGMODE
+    --userCount;
+#endif
+  }
+}
+
+void user_count_memory(size_t* count_out, size_t* bytes_out)
+{
+  assert(0 != count_out);
+  assert(0 != bytes_out);
+  *count_out = userCount;
+  *bytes_out = userCount * sizeof(struct User);
+}
+
+/*
+ * user_set_away - set user away state
+ * returns 1 if client is away or changed away message, 0 if 
+ * client is removing away status.
+ * NOTE: this function may modify user and message, so they
+ * must be mutable.
  */
+int user_set_away(struct User* user, char* message)
+{
+  char* away;
+  assert(0 != user);
+
+  away = user->away;
+
+  if (EmptyString(message)) {
+    /*
+     * Marking as not away
+     */
+    if (away) {
+      MyFree(away);
+      user->away = 0;
+    }
+  }
+  else {
+    /*
+     * Marking as away
+     */
+    size_t len = strlen(message);
+
+    if (len > TOPICLEN) {
+      message[TOPICLEN] = '\0';
+      len = TOPICLEN;
+    }
+    if (away)
+      away = (char*) MyRealloc(away, len + 1);
+    else
+      away = (char*) MyMalloc(len + 1);
+    assert(0 != away);
+
+    user->away = away;
+    strcpy(away, message);
+  }
+  return (user->away != 0);
+}
 
 /*
  * next_client
@@ -145,9 +180,9 @@ static char buf[BUFSIZE], buf2[BUFSIZE];
  *     HandleMatchingClient;
  *
  */
-aClient *next_client(aClient *next, char *ch)
+struct Client *next_client(struct Client *next, const char* ch)
 {
-  Reg3 aClient *tmp = next;
+  struct Client *tmp = next;
 
   if (!tmp)
     return NULL;
@@ -185,36 +220,35 @@ aClient *next_client(aClient *next, char *ch)
  *
  *    returns: (see #defines)
  */
-int hunt_server(int MustBeOper, aClient *cptr, aClient *sptr, char *command,
+int hunt_server(int MustBeOper, struct Client *cptr, struct Client *sptr, char *command,
     int server, int parc, char *parv[])
 {
-  aClient *acptr;
+  struct Client *acptr;
   char y[8];
 
   /* Assume it's me, if no server or an unregistered client */
-  if (parc <= server || BadPtr(parv[server]) || IsUnknown(sptr))
+  if (parc <= server || EmptyString(parv[server]) || IsUnknown(sptr))
     return (HUNTED_ISME);
 
   /* Make sure it's a server */
   if (MyUser(sptr) || Protocol(cptr) < 10)
   {
     /* Make sure it's a server */
-    if (!strchr(parv[server], '*'))
-    {
+    if (!strchr(parv[server], '*')) {
       if (0 == (acptr = FindClient(parv[server])))
-       return HUNTED_NOSUCH;
+        return HUNTED_NOSUCH;
       if (acptr->user)
-       acptr = acptr->user->server;
+        acptr = acptr->user->server;
     }
     else if (!(acptr = find_match_server(parv[server])))
     {
       sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
-         me.name, parv[0], parv[server]);
+          me.name, parv[0], parv[server]);
       return (HUNTED_NOSUCH);
     }
   }
   else if (!(acptr = FindNServer(parv[server])))
-    return (HUNTED_NOSUCH);    /* Server broke off in the meantime */
+    return (HUNTED_NOSUCH);        /* Server broke off in the meantime */
 
   if (IsMe(acptr))
     return (HUNTED_ISME);
@@ -225,23 +259,11 @@ int hunt_server(int MustBeOper, aClient *cptr, aClient *sptr, char *command,
     return HUNTED_NOSUCH;
   }
 
-#ifdef NO_PROTOCOL9
-  if (MyUser(sptr))
-  {
-    strcpy(y, acptr->yxx);
-    parv[server] = y;
-  }
-#else
-  if (Protocol(acptr->from) > 9)
-  {
-    strcpy(y, acptr->yxx);
-    parv[server] = y;
-  }
-  else
-    parv[server] = acptr->name;
-#endif
+  strcpy(y, acptr->yxx);
+  parv[server] = y;
 
-  sendto_one(acptr, command, parv[0], parv[1], parv[2], parv[3], parv[4],
+  assert(!IsServer(sptr));
+  sendto_one(acptr, command, NumNick(sptr), parv[1], parv[2], parv[3], parv[4],
       parv[5], parv[6], parv[7], parv[8]);
 
   return (HUNTED_PASS);
@@ -261,16 +283,17 @@ int hunt_server(int MustBeOper, aClient *cptr, aClient *sptr, char *command,
  *  The '~'-character should be allowed, but a change should be global,
  *  some confusion would result if only few servers allowed it...
  */
-
-static int do_nick_name(char *nick)
+int do_nick_name(char* nick)
 {
-  Reg1 char *ch;
+  char* ch  = nick;
+  char* end = ch + NICKLEN;
+  assert(0 != ch);
 
-  if (*nick == '-' || isDigit(*nick))  /* first character in [0..9-] */
+  if (*ch == '-' || IsDigit(*ch))        /* first character in [0..9-] */
     return 0;
 
-  for (ch = nick; *ch && (ch - nick) < NICKLEN; ch++)
-    if (!isIrcNk(*ch))
+  for ( ; (ch < end) && *ch; ++ch)
+    if (!IsNickChar(*ch))
       break;
 
   *ch = '\0';
@@ -278,50 +301,6 @@ static int do_nick_name(char *nick)
   return (ch - nick);
 }
 
-/*
- * canonize
- *
- * reduce a string of duplicate list entries to contain only the unique
- * items.  Unavoidably O(n^2).
- */
-char *canonize(char *buffer)
-{
-  static char cbuf[BUFSIZ];
-  register char *s, *t, *cp = cbuf;
-  register int l = 0;
-  char *p = NULL, *p2;
-
-  *cp = '\0';
-
-  for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ","))
-  {
-    if (l)
-    {
-      p2 = NULL;
-      for (t = strtoken(&p2, cbuf, ","); t; t = strtoken(&p2, NULL, ","))
-       if (!strCasediff(s, t))
-         break;
-       else if (p2)
-         p2[-1] = ',';
-    }
-    else
-      t = NULL;
-    if (!t)
-    {
-      if (l)
-       *(cp - 1) = ',';
-      else
-       l = 1;
-      strcpy(cp, s);
-      if (p)
-       cp += (p - s);
-    }
-    else if (p2)
-      p2[-1] = ',';
-  }
-  return cbuf;
-}
-
 /*
  * clean_user_id
  *
@@ -332,24 +311,23 @@ char *canonize(char *buffer)
  * Note that `dest' and `source' can point to the same area or to different
  * non-overlapping areas.
  */
-
 static char *clean_user_id(char *dest, char *source, int tilde)
 {
-  register char ch;
+  char ch;
   char *d = dest;
   char *s = source;
   int rlen = USERLEN;
 
-  ch = *s++;                   /* Store first character to copy: */
+  ch = *s++;                        /* Store first character to copy: */
   if (tilde)
   {
-    *d++ = '~';                        /* If `dest' == `source', then this overwrites `ch' */
+    *d++ = '~';                        /* If `dest' == `source', then this overwrites `ch' */
     --rlen;
   }
-  while (ch && !isCntrl(ch) && rlen--)
+  while (ch && !IsCntrl(ch) && rlen--)
   {
-    register char nch = *s++;  /* Store next character to copy */
-    *d++ = isIrcUi(ch) ? ch : '_';     /* This possibly overwrites it */
+    char nch = *s++;        /* Store next character to copy */
+    *d++ = IsUserChar(ch) ? ch : '_';        /* This possibly overwrites it */
     if (nch == '~')
       ch = '_';
     else
@@ -380,109 +358,107 @@ static char *clean_user_id(char *dest, char *source, int tilde)
  *    this is not fair. It should actually request another
  *    nick from local user or kill him/her...
  */
-
-static int register_user(aClient *cptr, aClient *sptr,
-    char *nick, char *username)
+int register_user(struct Client *cptr, struct Client *sptr,
+                  const char *nick, char *username)
 {
-  Reg1 aConfItem *aconf;
-  char *parv[3], *tmpstr, *tmpstr2;
-  char c = 0 /* not alphanum */ , d = 'a' /* not a digit */ ;
-  short upper = 0;
-  short lower = 0;
-  short pos = 0, leadcaps = 0, other = 0, digits = 0, badid = 0;
-  short digitgroups = 0;
-  anUser *user = sptr->user;
-  Dlink *lp;
-  char ip_base64[8];
-
-  user->last = now;
+  struct ConfItem* aconf;
+  char*            parv[3];
+  char*            tmpstr;
+  char*            tmpstr2;
+  char             c = 0;    /* not alphanum */
+  char             d = 'a';  /* not a digit */
+  short            upper = 0;
+  short            lower = 0;
+  short            pos = 0;
+  short            leadcaps = 0;
+  short            other = 0;
+  short            digits = 0;
+  short            badid = 0;
+  short            digitgroups = 0;
+  struct User*     user = sptr->user;
+  char             ip_base64[8];
+  char             featurebuf[512];
+
+  user->last = CurrentTime;
   parv[0] = sptr->name;
   parv[1] = parv[2] = NULL;
 
   if (MyConnect(sptr))
   {
-    static time_t last_too_many1, last_too_many2;
-    switch (check_client(sptr))
+    static time_t last_too_many1;
+    static time_t last_too_many2;
+
+    assert(cptr == sptr);
+    switch (conf_check_client(sptr))
     {
       case ACR_OK:
-       break;
+        break;
       case ACR_NO_AUTHORIZATION:
-       sendto_op_mask(SNO_UNAUTH, "Unauthorized connection from %s.",
-           sptr->sockhost);
-       ircstp->is_ref++;
-       return exit_client(cptr, sptr, &me,
-           "No Authorization - use another server");
+        sendto_op_mask(SNO_UNAUTH, "Unauthorized connection from %s.",
+                       get_client_name(sptr, HIDE_IP));
+        ++ServerStats->is_ref;
+        return exit_client(cptr, sptr, &me,
+            "No Authorization - use another server");
       case ACR_TOO_MANY_IN_CLASS:
-       if (now - last_too_many1 >= (time_t) 60)
-       {
-         last_too_many1 = now;
-         sendto_op_mask(SNO_TOOMANY, "Too many connections in class for %s.",
-             sptr->sockhost);
-       }
-       IPcheck_connect_fail(sptr);
-       ircstp->is_ref++;
-       return exit_client(cptr, sptr, &me,
-           "Sorry, your connection class is full - try again later or try another server");
+        if (CurrentTime - last_too_many1 >= (time_t) 60)
+        {
+          last_too_many1 = CurrentTime;
+          sendto_op_mask(SNO_TOOMANY, "Too many connections in class for %s.",
+                         get_client_name(sptr, HIDE_IP));
+        }
+        ++ServerStats->is_ref;
+        IPcheck_connect_fail(sptr->ip);
+        return exit_client(cptr, sptr, &me,
+            "Sorry, your connection class is full - try again later or try another server");
       case ACR_TOO_MANY_FROM_IP:
-       if (now - last_too_many2 >= (time_t) 60)
-       {
-         last_too_many2 = now;
-         sendto_op_mask(SNO_TOOMANY,
-             "Too many connections from same IP for %s.",
-             sptr->sockhost);
-       }
-       ircstp->is_ref++;
-       return exit_client(cptr, sptr, &me,
-           "Too many connections from your host");
+        if (CurrentTime - last_too_many2 >= (time_t) 60)
+        {
+          last_too_many2 = CurrentTime;
+          sendto_op_mask(SNO_TOOMANY, "Too many connections from same IP for %s.",
+                         get_client_name(sptr, HIDE_IP));
+        }
+        ++ServerStats->is_ref;
+        return exit_client(cptr, sptr, &me,
+            "Too many connections from your host");
       case ACR_ALREADY_AUTHORIZED:
-       /* Can this ever happen? */
+        /* Can this ever happen? */
       case ACR_BAD_SOCKET:
-       IPcheck_connect_fail(sptr);
-       return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
+        ++ServerStats->is_ref;
+        IPcheck_connect_fail(sptr->ip);
+        return exit_client(cptr, sptr, &me, "Unknown error -- Try again");
     }
-    if (IsUnixSocket(sptr))
-      strncpy(user->host, me.name, HOSTLEN);
-    else
-      strncpy(user->host, sptr->sockhost, HOSTLEN);
+    ircd_strncpy(user->host, sptr->sockhost, HOSTLEN);
     aconf = sptr->confs->value.aconf;
 
     clean_user_id(user->username,
-       (sptr->flags & FLAGS_GOTID) ? sptr->username : username,
-       (sptr->flags & FLAGS_DOID) && !(sptr->flags & FLAGS_GOTID));
+        (sptr->flags & FLAGS_GOTID) ? sptr->username : username,
+        (sptr->flags & FLAGS_DOID) && !(sptr->flags & FLAGS_GOTID));
 
-    if ((user->username[0] == '\000')
-       || ((user->username[0] == '~') && (user->username[1] == '\000')))
+    if ((user->username[0] == '\0')
+        || ((user->username[0] == '~') && (user->username[1] == '\000')))
       return exit_client(cptr, sptr, &me, "USER: Bogus userid.");
 
-    if (!BadPtr(aconf->passwd)
-       && !(isDigit(*aconf->passwd) && !aconf->passwd[1])
+    if (!EmptyString(aconf->passwd)
+        && !(IsDigit(*aconf->passwd) && !aconf->passwd[1])
 #ifdef USEONE
-       && strcmp("ONE", aconf->passwd)
+        && strcmp("ONE", aconf->passwd)
 #endif
-       && strcmp(sptr->passwd, aconf->passwd))
+        && strcmp(sptr->passwd, aconf->passwd))
     {
-      ircstp->is_ref++;
+      ServerStats->is_ref++;
+      IPcheck_connect_fail(sptr->ip);
       sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
-      IPcheck_connect_fail(sptr);
       return exit_client(cptr, sptr, &me, "Bad Password");
     }
     memset(sptr->passwd, 0, sizeof(sptr->passwd));
     /*
      * following block for the benefit of time-dependent K:-lines
      */
-    if (find_kill(sptr))
-    {
-      ircstp->is_ref++;
+    if (find_kill(sptr)) {
+      ServerStats->is_ref++;
+      IPcheck_connect_fail(sptr->ip);
       return exit_client(cptr, sptr, &me, "K-lined");
     }
-#ifdef R_LINES
-    if (find_restrict(sptr))
-    {
-      ircstp->is_ref++;
-      return exit_client(cptr, sptr, &me, "R-lined");
-    }
-#endif
-
     /*
      * Check for mixed case usernames, meaning probably hacked.  Jon2 3-94
      * Summary of rules now implemented in this patch:         Ensor 11-94
@@ -505,83 +481,89 @@ static int register_user(aClient *cptr, aClient *sptr,
       pos++;
       c = *tmpstr;
       tmpstr++;
-      if (isLower(c))
+      if (IsLower(c))
       {
-       lower++;
+        lower++;
       }
-      else if (isUpper(c))
+      else if (IsUpper(c))
       {
-       upper++;
-       if ((leadcaps || pos == 1) && !lower && !digits)
-         leadcaps++;
+        upper++;
+        if ((leadcaps || pos == 1) && !lower && !digits)
+          leadcaps++;
       }
-      else if (isDigit(c))
+      else if (IsDigit(c))
       {
-       digits++;
-       if (pos == 1 || !isDigit(d))
-       {
-         digitgroups++;
-         if (digitgroups > 2)
-           badid = 1;
-       }
+        digits++;
+        if (pos == 1 || !IsDigit(d))
+        {
+          digitgroups++;
+          if (digitgroups > 2)
+            badid = 1;
+        }
       }
       else if (c == '-' || c == '_' || c == '.')
       {
-       other++;
-       if (pos == 1)
-         badid = 1;
-       else if (d == '-' || d == '_' || d == '.' || other > 2)
-         badid = 1;
+        other++;
+        if (pos == 1)
+          badid = 1;
+        else if (d == '-' || d == '_' || d == '.' || other > 2)
+          badid = 1;
       }
       else
-       badid = 1;
+        badid = 1;
       d = c;
     }
     if (!badid)
     {
       if (lower && upper && (!leadcaps || leadcaps > 3 ||
-         (upper > 2 && upper > leadcaps)))
-       badid = 1;
-      else if (digitgroups == 2 && !(isDigit(tmpstr2[0]) || isDigit(c)))
-       badid = 1;
-      else if ((!lower && !upper) || !isAlnum(c))
-       badid = 1;
+          (upper > 2 && upper > leadcaps)))
+        badid = 1;
+      else if (digitgroups == 2 && !(IsDigit(tmpstr2[0]) || IsDigit(c)))
+        badid = 1;
+      else if ((!lower && !upper) || !IsAlnum(c))
+        badid = 1;
     }
     if (badid && (!(sptr->flags & FLAGS_GOTID) ||
-       strcmp(sptr->username, username) != 0))
+        strcmp(sptr->username, username) != 0))
     {
-      ircstp->is_ref++;
+      ServerStats->is_ref++;
       sendto_one(cptr, ":%s %d %s :Your username is invalid.",
-         me.name, ERR_INVALIDUSERNAME, cptr->name);
+                 me.name, ERR_INVALIDUSERNAME, cptr->name);
       sendto_one(cptr,
-         ":%s %d %s :Connect with your real username, in lowercase.",
-         me.name, ERR_INVALIDUSERNAME, cptr->name);
+                 ":%s %d %s :Connect with your real username, in lowercase.",
+                 me.name, ERR_INVALIDUSERNAME, cptr->name);
       sendto_one(cptr, ":%s %d %s :If your mail address were foo@bar.com, "
-         "your username would be foo.",
-         me.name, ERR_INVALIDUSERNAME, cptr->name);
+                 "your username would be foo.",
+                 me.name, ERR_INVALIDUSERNAME, cptr->name);
       return exit_client(cptr, sptr, &me, "USER: Bad username");
     }
-    Count_unknownbecomesclient(sptr, nrof);
+    Count_unknownbecomesclient(sptr, UserStats);
   }
-  else
-  {
-    strncpy(user->username, username, USERLEN);
-    Count_newremoteclient(nrof);
+  else {
+    ircd_strncpy(user->username, username, USERLEN);
+    Count_newremoteclient(UserStats, user->server);
   }
   SetUser(sptr);
+
   if (IsInvisible(sptr))
-    ++nrof.inv_clients;
+    ++UserStats.inv_clients;
   if (IsOper(sptr))
-    ++nrof.opers;
+    ++UserStats.opers;
+
+  if (MyConnect(sptr)) {
+    sptr->handler = CLIENT_HANDLER;
+    release_dns_reply(sptr);
 
-  if (MyConnect(sptr))
-  {
     sendto_one(sptr, rpl_str(RPL_WELCOME), me.name, nick, nick);
-    /* This is a duplicate of the NOTICE but see below... */
+    /*
+     * This is a duplicate of the NOTICE but see below...
+     */
     sendto_one(sptr, rpl_str(RPL_YOURHOST), me.name, nick,
-              me.name, version);
+               me.name, version);
     sendto_one(sptr, rpl_str(RPL_CREATED), me.name, nick, creation);
     sendto_one(sptr, rpl_str(RPL_MYINFO), me.name, parv[0], me.name, version);
+    sprintf_irc(featurebuf,FEATURES,FEATURESVALUES);
+    sendto_one(sptr, rpl_str(RPL_ISUPPORT), me.name, nick, featurebuf);
     m_lusers(sptr, sptr, 1, parv);
     update_load();
 #ifdef NODEFAULTMOTD
@@ -589,20 +571,20 @@ static int register_user(aClient *cptr, aClient *sptr,
 #else
     m_motd(sptr, sptr, 1, parv);
 #endif
-    nextping = now;
+    nextping = CurrentTime;
     if (sptr->snomask & SNO_NOISY)
       set_snomask(sptr, sptr->snomask & SNO_NOISY, SNO_ADD);
 #ifdef ALLOW_SNO_CONNEXIT
 #ifdef SNO_CONNEXIT_IP
     sprintf_irc(sendbuf,
-       ":%s NOTICE * :*** Notice -- Client connecting: %s (%s@%s) [%s] {%d}",
-       me.name, nick, user->username, user->host, inetntoa(sptr->ip),
-       get_client_class(sptr));
+                ":%s NOTICE * :*** Notice -- Client connecting: %s (%s@%s) [%s] {%d}",
+                me.name, nick, user->username, user->host, cptr->sock_ip,
+                get_client_class(sptr));
     sendbufto_op_mask(SNO_CONNEXIT);
 #else /* SNO_CONNEXIT_IP */
     sprintf_irc(sendbuf,
-       ":%s NOTICE * :*** Notice -- Client connecting: %s (%s@%s)",
-       me.name, nick, user->username, user->host);
+                ":%s NOTICE * :*** Notice -- Client connecting: %s (%s@%s)",
+                me.name, nick, user->username, user->host);
     sendbufto_op_mask(SNO_CONNEXIT);
 #endif /* SNO_CONNEXIT_IP */
 #endif /* ALLOW_SNO_CONNEXIT */
@@ -611,19 +593,14 @@ static int register_user(aClient *cptr, aClient *sptr,
   else
     /* if (IsServer(cptr)) */
   {
-    aClient *acptr;
+    struct Client *acptr;
 
     acptr = user->server;
     if (acptr->from != sptr->from)
     {
-      if (Protocol(cptr) < 10)
-       sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])",
-           me.name, sptr->name, me.name, user->server->name, acptr->from->name,
-           acptr->from->sockhost);
-      else
-       sendto_one(cptr, "%s KILL %s%s :%s (%s != %s[%s])",
-           NumServ(&me), NumNick(sptr), me.name, user->server->name,
-           acptr->from->name, acptr->from->sockhost);
+      sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (%s != %s[%s])",
+                 NumServ(&me), NumNick(sptr), me.name, user->server->name,
+                 acptr->from->name, acptr->from->sockhost);
       sptr->flags |= FLAGS_KILLED;
       return exit_client(cptr, sptr, &me, "NICK server wrong direction");
     }
@@ -636,69 +613,25 @@ static int register_user(aClient *cptr, aClient *sptr,
      * FIXME: This can be speeded up - its stupid to check it for
      * every NICK message in a burst again  --Run.
      */
-    for (acptr = user->server; acptr != &me; acptr = acptr->serv->up)
+    for (acptr = user->server; acptr != &me; acptr = acptr->serv->up) {
       if (IsBurst(acptr) || Protocol(acptr) < 10)
-       break;
+        break;
+    }
     if (IPcheck_remote_connect(sptr, user->host, (acptr != &me)) == -1)
-      /* We ran out of bits to count this */
-      return exit_client(cptr, sptr, &me,
-         "More then 255 connections from this IP number");
+      /*
+       * We ran out of bits to count this
+       */
+      return exit_client(cptr, sptr, &me, "More than 255 connections from this address");
   }
-#ifdef NO_PROTOCOL9            /* Use this when all servers are 2.10 (but test it first) --Run */
 
   tmpstr = umode_str(sptr);
   sendto_serv_butone(cptr, *tmpstr ?
-      "%s NICK %s %d %d %s %s +%s %s %s%s :%s" :
-      "%s NICK %s %d %d %s %s %s%s %s%s :%s",
-      NumServ(user->server), nick, sptr->hopcount + 1, sptr->lastnick,
-      user->username, user->host, tmpstr,
-      inttobase64(ip_base64, ntohl(sptr->ip.s_addr), 6),
-      NumNick(sptr), sptr->info);
-
-#else /* Remove the following when all servers are 2.10 */
-
-  /* First send message to all 2.9 servers */
-  sprintf_irc(sendbuf, ":%s NICK %s %d " TIME_T_FMT " %s %s %s :%s",
-      user->server->name, nick, sptr->hopcount + 1, sptr->lastnick,
-      user->username, user->host, user->server->name, sptr->info);
-  for (lp = me.serv->down; lp; lp = lp->next)
-  {
-    if (lp->value.cptr == cptr)
-      continue;
-    if (Protocol(lp->value.cptr) < 10)
-      sendbufto_one(lp->value.cptr);
-  }
-
-  /* If the user has no umode, no need to generate a user MODE */
-  if (*(tmpstr = umode_str(sptr)) && (MyConnect(sptr) || Protocol(cptr) > 9))
-    /* Is it necessary to generate an user MODE message ? */
-  {
-    for (lp = me.serv->down; lp; lp = lp->next)
-    {
-      if (lp->value.cptr == cptr)
-       continue;
-      if (Protocol(lp->value.cptr) < 10)
-       sendto_one(lp->value.cptr, ":%s MODE %s :%s", sptr->name,
-           sptr->name, tmpstr);
-    }
-  }
-
-  /* Now send message to all 2.10 servers */
-  sprintf_irc(sendbuf, *tmpstr ?
-      "%s NICK %s %d %d %s %s +%s %s %s%s :%s" :
-      "%s NICK %s %d %d %s %s %s%s %s%s :%s",
-      NumServ(user->server), nick, sptr->hopcount + 1, sptr->lastnick,
-      user->username, user->host, tmpstr,
-      inttobase64(ip_base64, ntohl(sptr->ip.s_addr), 6),
-      NumNick(sptr), sptr->info);
-  for (lp = me.serv->down; lp; lp = lp->next)
-  {
-    if (lp->value.cptr == cptr || Protocol(lp->value.cptr) < 10)
-      continue;
-    sendbufto_one(lp->value.cptr);
-  }
-
-#endif
+                     "%s " TOK_NICK " %s %d %d %s %s +%s %s %s%s :%s" :
+                     "%s " TOK_NICK " %s %d %d %s %s %s%s %s%s :%s",
+                     NumServ(user->server), nick, sptr->hopcount + 1, sptr->lastnick,
+                     user->username, user->host, tmpstr, 
+                     inttobase64(ip_base64, ntohl(sptr->ip.s_addr), 6),
+                     NumNick(sptr), sptr->info);
 
   /* Send umode to client */
   if (MyUser(sptr))
@@ -706,1772 +639,442 @@ static int register_user(aClient *cptr, aClient *sptr,
     send_umode(cptr, sptr, 0, ALL_UMODES);
     if (sptr->snomask != SNO_DEFAULT && (sptr->flags & FLAGS_SERVNOTICE))
       sendto_one(sptr, rpl_str(RPL_SNOMASK), me.name, sptr->name,
-         sptr->snomask, sptr->snomask);
+                 sptr->snomask, sptr->snomask);
   }
 
   return 0;
 }
 
-/* *INDENT-OFF* */
 
-static int user_modes[] = {
-  FLAGS_OPER,          'o',
-  FLAGS_LOCOP,         'O',
-  FLAGS_INVISIBLE,     'i',
-  FLAGS_WALLOP,                'w',
-  FLAGS_SERVNOTICE,    's',
-  FLAGS_DEAF,          'd',
-  FLAGS_CHSERV,                'k',
-  FLAGS_DEBUG,          'g',
-  0,                   0
+static const struct UserMode {
+  unsigned int flag;
+  char         c;
+} userModeList[] = {
+  { FLAGS_OPER,        'o' },
+  { FLAGS_LOCOP,       'O' },
+  { FLAGS_INVISIBLE,   'i' },
+  { FLAGS_WALLOP,      'w' },
+  { FLAGS_SERVNOTICE,  's' },
+  { FLAGS_DEAF,        'd' },
+  { FLAGS_CHSERV,      'k' },
+  { FLAGS_DEBUG,       'g' }
 };
 
-/* *INDENT-ON* */
+#define USERMODELIST_SIZE sizeof(userModeList) / sizeof(struct UserMode)
 
-#define COOKIE_VERIFIED ((unsigned int)-1)
+#if 0
+static int user_modes[] = {
+  FLAGS_OPER,        'o',
+  FLAGS_LOCOP,       'O',
+  FLAGS_INVISIBLE,   'i',
+  FLAGS_WALLOP,      'w',
+  FLAGS_SERVNOTICE,  's',
+  FLAGS_DEAF,        'd',
+  FLAGS_CHSERV,      'k',
+  FLAGS_DEBUG,       'g',
+  0,                  0
+};
+#endif
 
 /*
- * m_nick
- *
- * parv[0] = sender prefix
- * parv[1] = nickname
- *
- * If from server, source is client:
- *   parv[2] = timestamp
- *
- * Source is server:
- *   parv[2] = hopcount
- *   parv[3] = timestamp
- *   parv[4] = username
- *   parv[5] = hostname
- *   parv[6] = umode (optional)
- *   parv[parc-3] = IP#                 <- Only Protocol >= 10
- *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
- *   parv[parc-1] = info
- *   parv[0] = server
+ * XXX - find a way to get rid of this
  */
-int m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient* acptr;
-  aClient* server = NULL;
-  char     nick[NICKLEN + 2];
-  char*    s;
-  Link*    lp;
-  time_t   lastnick = (time_t) 0;
-  int      differ = 1;
+static char umodeBuf[BUFSIZE];
 
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
-    return 0;
-  }
-  else if ((IsServer(sptr) && parc < 8) || (IsServer(cptr) && parc < 3))
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "NICK");
-    sendto_ops("bad NICK param count for %s from %s",
-       parv[1], cptr->name);
-    return 0;
-  }
-  if (MyConnect(sptr) && (s = strchr(parv[1], '~')))
-    *s = '\0';
-  strncpy(nick, parv[1], NICKLEN + 1);
-  nick[sizeof(nick) - 1] = 0;
-  /*
-   * If do_nick_name() returns a null name OR if the server sent a nick
-   * name and do_nick_name() changed it in some way (due to rules of nick
-   * creation) then reject it. If from a server and we reject it,
-   * and KILL it. -avalon 4/4/92
-   */
-  if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1])))
-  {
-    sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1]);
+int set_nick_name(struct Client* cptr, struct Client* sptr,
+                  const char* nick, int parc, char* parv[])
+{
+  if (IsServer(sptr)) {
+    int   i;
+    const char* p;
 
-    if (IsServer(cptr))
-    {
-      ircstp->is_kill++;
-      sendto_ops("Bad Nick: %s From: %s %s",
-         parv[1], parv[0], cptr->name);
-      if (Protocol(cptr) < 10)
-       sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])",
-           me.name, parv[1], me.name, parv[1], nick, cptr->name);
-      else
-       sendto_one(cptr, "%s KILL %s :%s (%s <- %s[%s])",
-           NumServ(&me), IsServer(sptr) ? parv[parc - 2] : parv[0], me.name,
-           parv[1], nick, cptr->name);
-      if (!IsServer(sptr))     /* bad nick _change_ */
-      {
-       sendto_lowprot_butone(cptr, 9, ":%s KILL %s :%s (%s <- %s!%s@%s)",
-           me.name, parv[0], me.name, cptr->name, parv[0],
-           sptr->user ? sptr->username : "",
-           sptr->user ? sptr->user->server->name : cptr->name);
-       sendto_highprot_butone(cptr, 10, "%s KILL %s :%s (%s <- %s!%s@%s)",
-           NumServ(&me), parv[0], me.name, cptr->name,
-           parv[0], sptr->user ? sptr->username : "",
-           sptr->user ? sptr->user->server->name : cptr->name);
-       sptr->flags |= FLAGS_KILLED;
-       return exit_client(cptr, sptr, &me, "BadNick");
+    /*
+     * A server introducing a new client, change source
+     */
+    struct Client* new_client = make_client(cptr, STAT_UNKNOWN);
+    assert(0 != new_client);
+
+    new_client->hopcount = atoi(parv[2]);
+    new_client->lastnick = atoi(parv[3]);
+    if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+') {
+      for (p = parv[6] + 1; *p; p++) {
+        for (i = 0; i < USERMODELIST_SIZE; ++i) {
+          if (userModeList[i].c == *p) {
+            new_client->flags |= userModeList[i].flag;
+            break;
+          }
+        }
       }
     }
-    return 0;
-  }
-
-  /* 
-   * Check if this is a LOCAL user trying to use a reserved (Juped)
-   * nick, if so tell him that it's a nick in use...
-   */
-
-  if ((!IsServer(cptr)) && isNickJuped(nick))
-  {
-    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
-       /* parv[0] is empty when connecting */
-       BadPtr(parv[0]) ? "*" : parv[0], nick);
-    return 0;                  /* NICK message ignored */
-  }
-
-  /*
-   * Check against nick name collisions.
-   *
-   * Put this 'if' here so that the nesting goes nicely on the screen :)
-   * We check against server name list before determining if the nickname
-   * is present in the nicklist (due to the way the below for loop is
-   * constructed). -avalon
-   */
-  if ((acptr = FindServer(nick))) {
-    if (MyConnect(sptr))
-    {
-      sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
-         BadPtr(parv[0]) ? "*" : parv[0], nick);
-      return 0;                        /* NICK message ignored */
-    }
     /*
-     * We have a nickname trying to use the same name as
-     * a server. Send out a nick collision KILL to remove
-     * the nickname. As long as only a KILL is sent out,
-     * there is no danger of the server being disconnected.
-     * Ultimate way to jupiter a nick ? >;-). -avalon
+     * Set new nick name.
      */
-    sendto_ops("Nick collision on %s(%s <- %s)",
-       sptr->name, acptr->from->name, cptr->name);
-    ircstp->is_kill++;
-    if (Protocol(cptr) < 10)
-      sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)",
-         me.name, sptr->name, me.name, acptr->from->name,
-         cptr->name);
-    else
-      sendto_one(cptr, "%s KILL %s%s :%s (%s <- %s)",
-         NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
-         /*
-          * NOTE: Cannot use get_client_name twice here, it returns static
-          *       string pointer--the other info would be lost.
-          */
-         cptr->name);
-    sptr->flags |= FLAGS_KILLED;
-    return exit_client(cptr, sptr, &me, "Nick/Server collision");
-  }
-
-  if (!(acptr = FindClient(nick)))
-    goto nickkilldone;         /* No collisions, all clear... */
-  /*
-   * If acptr == sptr, then we have a client doing a nick
-   * change between *equivalent* nicknames as far as server
-   * is concerned (user is changing the case of his/her
-   * nickname or somesuch)
-   */
-  if (acptr == sptr)
-  {
-    if (strcmp(acptr->name, nick) != 0)
-      /*
-       * Allows change of case in his/her nick
-       */
-      goto nickkilldone;       /* -- go and process change */
-    else
+    strcpy(new_client->name, nick);
+    new_client->user = make_user(new_client);
+    new_client->user->server = sptr;
+    if (!SetRemoteNumNick(new_client, parv[parc - 2])) {
       /*
-       * This is just ':old NICK old' type thing.
-       * Just forget the whole thing here. There is
-       * no point forwarding it to anywhere,
-       * especially since servers prior to this
-       * version would treat it as nick collision.
+       * if this fails squit the server and free the client
        */
-      return 0;                        /* NICK Message ignored */
-  }
+      free_client(new_client);
+      return exit_client_msg(cptr, sptr, &me, "Invalid numeric index");
+    }
+    new_client->ip.s_addr = htonl(base64toint(parv[parc - 3]));
+    /* IP# of remote client */
 
-  /*
-   * Note: From this point forward it can be assumed that
-   * acptr != sptr (point to different client structures).
-   */
-  /*
-   * If the older one is "non-person", the new entry is just
-   * allowed to overwrite it. Just silently drop non-person,
-   * and proceed with the nick. This should take care of the
-   * "dormant nick" way of generating collisions...
-   */
-  if (IsUnknown(acptr) && MyConnect(acptr))
-  {
-    IPcheck_connect_fail(acptr);
-    exit_client(cptr, acptr, &me, "Overridden by other sign on");
-    goto nickkilldone;
+    add_client_to_list(new_client);
+    hAddClient(new_client);
+
+    sptr->serv->ghost = 0;        /* :server NICK means end of net.burst */
+    ircd_strncpy(new_client->username, parv[4], USERLEN);
+    ircd_strncpy(new_client->user->host, parv[5], HOSTLEN);
+    ircd_strncpy(new_client->info, parv[parc - 1], REALLEN);
+    return register_user(cptr, new_client, new_client->name, parv[4]);
   }
-  /*
-   * Decide, we really have a nick collision and deal with it
-   */
-  if (!IsServer(cptr))
-  {
+  else if (sptr->name[0]) {
     /*
-     * NICK is coming from local client connection. Just
-     * send error reply and ignore the command.
+     * Client changing its nick
+     *
+     * If the client belongs to me, then check to see
+     * if client is on any channels where it is currently
+     * banned.  If so, do not allow the nick change to occur.
      */
-    sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
-       /* parv[0] is empty when connecting */
-       BadPtr(parv[0]) ? "*" : parv[0], nick);
-    return 0;                  /* NICK message ignored */
-  }
-  /*
-   * NICK was coming from a server connection.
-   * This means we have a race condition (two users signing on
-   * at the same time), or two net fragments reconnecting with the same nick.
-   * The latter can happen because two different users connected
-   * or because one and the same user switched server during a net break.
-   * If the TimeStamps are equal, we kill both (or only 'new'
-   * if it was a ":server NICK new ...").
-   * Otherwise we kill the youngest when user@host differ,
-   * or the oldest when they are the same.
-   * We treat user and ~user as different, because if it wasn't
-   * a faked ~user the AUTH wouldn't have added the '~'.
-   * --Run
-   *
-   */
-  if (IsServer(sptr))
-  {
+    if (MyUser(sptr)) {
+      const char* channel_name;
+      if ((channel_name = find_no_nickchange_channel(sptr))) {
+        sendto_one(cptr, err_str(ERR_BANNICKCHANGE), me.name, parv[0],
+                   channel_name);
+        return 0;
+      }
+      /*
+       * Refuse nick change if the last nick change was less
+       * then 30 seconds ago. This is intended to get rid of
+       * clone bots doing NICK FLOOD. -SeKs
+       * If someone didn't change their nick for more then 60 seconds
+       * however, allow to do two nick changes immedately after another
+       * before limiting the nick flood. -Run
+       */
+      if (CurrentTime < cptr->nextnick) {
+        cptr->nextnick += 2;
+        sendto_one(cptr, err_str(ERR_NICKTOOFAST),
+            me.name, parv[0], parv[1], cptr->nextnick - CurrentTime);
+        /* Send error message */
+        sendto_prefix_one(cptr, cptr, ":%s NICK %s", parv[0], parv[0]);
+        /* bounce NICK to user */
+        return 0;                /* ignore nick change! */
+      }
+      else {
+        /* Limit total to 1 change per NICK_DELAY seconds: */
+        cptr->nextnick += NICK_DELAY;
+        /* However allow _maximal_ 1 extra consecutive nick change: */
+        if (cptr->nextnick < CurrentTime)
+          cptr->nextnick = CurrentTime;
+      }
+    }
     /*
-     * A new NICK being introduced by a neighbouring
-     * server (e.g. message type ":server NICK new ..." received)
+     * Also set 'lastnick' to current time, if changed.
      */
-    lastnick = atoi(parv[3]);
-    differ = (strCasediff(acptr->user->username, parv[4]) ||
-       strCasediff(acptr->user->host, parv[5]));
-    sendto_ops("Nick collision on %s (%s " TIME_T_FMT " <- %s " TIME_T_FMT
-       " (%s user@host))", acptr->name, acptr->from->name, acptr->lastnick,
-       cptr->name, lastnick, differ ? "Different" : "Same");
-  }
-  else
-  {
+    if (0 != ircd_strcmp(parv[0], nick))
+      sptr->lastnick = (sptr == cptr) ? TStime() : atoi(parv[2]);
+
     /*
-     * A NICK change has collided (e.g. message type ":old NICK new").
+     * 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.
      */
-    lastnick = atoi(parv[2]);
-    differ = (strCasediff(acptr->user->username, sptr->user->username) ||
-       strCasediff(acptr->user->host, sptr->user->host));
-    sendto_ops("Nick change collision from %s to %s (%s " TIME_T_FMT " <- %s "
-       TIME_T_FMT ")", sptr->name, acptr->name, acptr->from->name,
-       acptr->lastnick, cptr->name, lastnick);
-  }
-  /*
-   * Now remove (kill) the nick on our side if it is the youngest.
-   * If no timestamp was received, we ignore the incoming nick
-   * (and expect a KILL for our legit nick soon ):
-   * When the timestamps are equal we kill both nicks. --Run
-   * acptr->from != cptr should *always* be true (?).
-   */
-  if (acptr->from != cptr)
-  {
-    if ((differ && lastnick >= acptr->lastnick) ||
-       (!differ && lastnick <= acptr->lastnick))
-    {
-      if (!IsServer(sptr))
-      {
-       ircstp->is_kill++;
-       sendto_lowprot_butone(cptr, 9,  /* Kill old from outgoing servers */
-           ":%s KILL %s :%s (%s <- %s (Nick collision))",
-           me.name, sptr->name, me.name, acptr->from->name,
-           cptr->name);
-       sendto_highprot_butone(cptr, 10,        /* Kill old from outgoing servers */
-           "%s KILL %s%s :%s (%s <- %s (Nick collision))",
-           NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
-           cptr->name);
-       if (MyConnect(sptr) && IsServer(cptr) && Protocol(cptr) > 9)
-         sendto_one(cptr, "%s KILL %s%s :%s (Ghost2)",
-             NumServ(&me), NumNick(sptr), me.name);
-       sptr->flags |= FLAGS_KILLED;
-       exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
-      }
-      if (lastnick != acptr->lastnick)
-       return 0;               /* Ignore the NICK */
-    }
-    sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, nick);
-  }
-  ircstp->is_kill++;
-  acptr->flags |= FLAGS_KILLED;
-  if (differ)
-  {
-    sendto_lowprot_butone(cptr, 9,     /* Kill our old from outgoing servers */
-       ":%s KILL %s :%s (%s <- %s (older nick overruled))",
-       me.name, acptr->name, me.name, acptr->from->name,
-       cptr->name);
-    sendto_highprot_butone(cptr, 10,   /* Kill our old from outgoing servers */
-       "%s KILL %s%s :%s (%s <- %s (older nick overruled))",
-       NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
-       cptr->name);
-    if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
-      sendto_one(cptr, "%s%s QUIT :Local kill by %s (Ghost)",
-         NumNick(acptr), me.name);
-    exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
-  }
-  else
-  {
-    sendto_lowprot_butone(cptr, 9,     /* Kill our old from outgoing servers */
-       ":%s KILL %s :%s (%s <- %s (nick collision from same user@host))",
-       me.name, acptr->name, me.name, acptr->from->name,
-       cptr->name);
-    sendto_highprot_butone(cptr, 10,   /* Kill our old from outgoing servers */
-       "%s KILL %s%s :%s (%s <- %s (nick collision from same user@host))",
-       NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
-       cptr->name);
-    if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
-      sendto_one(cptr,
-         "%s%s QUIT :Local kill by %s (Ghost: switched servers too fast)",
-         NumNick(acptr), me.name);
-    exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
-  }
-  if (lastnick == acptr->lastnick)
-    return 0;
-
-nickkilldone:
-  if (IsServer(sptr))
-  {
-    int flag, *s;
-    char *p;
-#ifndef NO_PROTOCOL9
-    const char *nnp9 = NULL;   /* Init. to avoid compiler warning */
-#endif
-
-    /* A server introducing a new client, change source */
-    if (!server)
-      server = sptr;
-#ifndef NO_PROTOCOL9
-    /*
-     * Numeric Nicks does, in contrast to all other protocol enhancements,
-     * translation from protocol 9 -> protocol 10 !
-     * The reason is that I just can't know what protocol it is when I
-     * receive a "MODE #channel +o Run", because I can't 'find' "Run"
-     * before I know the protocol, and I can't know the protocol if I
-     * first have to find the server of "Run".
-     * Therefore, in THIS case, the protocol is determined by the Connected
-     * server: cptr.
-     */
-    if (Protocol(cptr) < 10 && !(nnp9 = CreateNNforProtocol9server(server)))
-      return exit_client_msg(cptr, server, &me,
-         "Too many clients (> %d) from P09 server (%s)", 64, server->name);
-#endif
-    sptr = make_client(cptr, STAT_UNKNOWN);
-    sptr->hopcount = atoi(parv[2]);
-    sptr->lastnick = atoi(parv[3]);
-    if (Protocol(cptr) > 9 && parc > 7 && *parv[6] == '+')
-      for (p = parv[6] + 1; *p; p++)
-       for (s = user_modes; (flag = *s); s += 2)
-         if (((char)*(s + 1)) == *p)
-         {
-           sptr->flags |= flag;
-           break;
-         }
-    /*
-     * Set new nick name.
-     */
-    strcpy(sptr->name, nick);
-    sptr->user = make_user(sptr);
-    sptr->user->server = server;
-#ifndef NO_PROTOCOL9
-    if (Protocol(cptr) < 10)
-    {
-      if (!SetRemoteNumNick(sptr, nnp9))
-      {
-       /*
-        * if this fails squit the server and free the client
-        */
-       free_client(sptr);
-       return exit_client_msg(cptr, server, &me, "Invalid numeric index");
-      }
-      sptr->ip.s_addr = 0;
-    }
-    else
-    {
-#endif
-      if (!SetRemoteNumNick(sptr, parv[parc - 2]))
-      {
-       /*
-        * if this fails squit the server and free the client
-        */
-       free_client(sptr);
-       return exit_client_msg(cptr, server, &me, "Invalid numeric index");
-      }
-      sptr->ip.s_addr = htonl(base64toint(parv[parc - 3]));
-      /* IP# of remote client */
-#ifndef NO_PROTOCOL9
-    }
-#endif
-    add_client_to_list(sptr);
-    hAddClient(sptr);
-
-    server->serv->ghost = 0;   /* :server NICK means end of net.burst */
-    strncpy(sptr->info, parv[parc - 1], sizeof(sptr->info) - 1);
-    strncpy(sptr->user->host, parv[5], sizeof(sptr->user->host) - 1);
-    return register_user(cptr, sptr, sptr->name, parv[4]);
-  }
-  else if (sptr->name[0])
-  {
-    /*
-     * Client changing its nick
-     *
-     * If the client belongs to me, then check to see
-     * if client is on any channels where it is currently
-     * banned.  If so, do not allow the nick change to occur.
-     */
-    if (MyUser(sptr))
-    {
-      for (lp = cptr->user->channel; lp; lp = lp->next)
-       if (can_send(cptr, lp->value.chptr) == MODE_BAN)
-       {
-         sendto_one(cptr, err_str(ERR_BANNICKCHANGE), me.name, parv[0],
-             lp->value.chptr->chname);
-         return 0;
-       }
-      /*
-       * Refuse nick change if the last nick change was less
-       * then 30 seconds ago. This is intended to get rid of
-       * clone bots doing NICK FLOOD. -SeKs
-       * If someone didn't change their nick for more then 60 seconds
-       * however, allow to do two nick changes immedately after another
-       * before limiting the nick flood. -Run
-       */
-      if (now < cptr->nextnick)
-      {
-       cptr->nextnick += 2;
-       sendto_one(cptr, err_str(ERR_NICKTOOFAST),
-           me.name, parv[0], parv[1], cptr->nextnick - now);
-       /* Send error message */
-       sendto_prefix_one(cptr, cptr, ":%s NICK %s", parv[0], parv[0]);
-       /* bounce NICK to user */
-       return 0;               /* ignore nick change! */
-      }
-      else
-      {
-       /* Limit total to 1 change per NICK_DELAY seconds: */
-       cptr->nextnick += NICK_DELAY;
-       /* However allow _maximal_ 1 extra consecutive nick change: */
-       if (cptr->nextnick < now)
-         cptr->nextnick = now;
-      }
-    }
-    /*
-     * Also set 'lastnick' to current time, if changed.
-     */
-    if (strCasediff(parv[0], nick))
-      sptr->lastnick = (sptr == cptr) ? TStime() : atoi(parv[2]);
-
-    /*
-     * 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 (IsUser(sptr))
-    {
+    if (IsUser(sptr)) {
       sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
       add_history(sptr, 1);
-#ifdef NO_PROTOCOL9
       sendto_serv_butone(cptr,
-         "%s%s NICK %s " TIME_T_FMT, NumNick(sptr), nick, sptr->lastnick);
-#else
-      sendto_lowprot_butone(cptr, 9,
-         ":%s NICK %s " TIME_T_FMT, parv[0], nick, sptr->lastnick);
-      sendto_highprot_butone(cptr, 10,
-         "%s%s NICK %s " TIME_T_FMT, NumNick(sptr), nick, sptr->lastnick);
-#endif
+          "%s%s " TOK_NICK " %s " TIME_T_FMT, NumNick(sptr), nick, sptr->lastnick);
     }
     else
       sendto_one(sptr, ":%s NICK :%s", parv[0], nick);
+
     if (sptr->name[0])
       hRemClient(sptr);
     strcpy(sptr->name, nick);
     hAddClient(sptr);
   }
-  else
-  {
+  else {
     /* Local client setting NICK the first time */
 
     strcpy(sptr->name, nick);
-    if (!sptr->user)
-    {
+    if (!sptr->user) {
       sptr->user = make_user(sptr);
       sptr->user->server = &me;
     }
     SetLocalNumNick(sptr);
     hAddClient(sptr);
-
-    /*
-     * If the client hasn't gotten a cookie-ping yet,
-     * choose a cookie and send it. -record!jegelhof@cloud9.net
-     */
-    if (!sptr->cookie)
-    {
-      do
-       sptr->cookie = (ircrandom() & 0x7fffffff);
-      while (!sptr->cookie);
-      sendto_one(cptr, "PING :%u", sptr->cookie);
-    }
-    else if (*sptr->user->host && sptr->cookie == COOKIE_VERIFIED)
-    {
-      /*
-       * USER and PONG already received, now we have NICK.
-       * register_user may reject the client and call exit_client
-       * for it - must test this and exit m_nick too !
-       */
-      sptr->lastnick = TStime();       /* Always local client */
-      if (register_user(cptr, sptr, nick, sptr->user->username) == CPTR_KILLED)
-       return CPTR_KILLED;
-    }
-  }
-  return 0;
-}
-
-/*
- * add_target
- *
- * sptr must be a local client!
- *
- * Cannonifies target for client `sptr'.
- */
-void add_target(aClient *sptr, void *target)
-{
-  register unsigned char *p;
-  register unsigned int tmp = ((size_t)target & 0xffff00) >> 8;
-  unsigned char hash = (tmp * tmp) >> 12;
-  if (sptr->targets[0] == hash)        /* Last person that we messaged ourself? */
-    return;
-  for (p = sptr->targets; p < &sptr->targets[MAXTARGETS - 1];)
-    if (*++p == hash)
-      return;                  /* Already in table */
-
-  /* New target */
-  memmove(&sptr->targets[RESERVEDTARGETS + 1],
-      &sptr->targets[RESERVEDTARGETS], MAXTARGETS - RESERVEDTARGETS - 1);
-  sptr->targets[RESERVEDTARGETS] = hash;
-  return;
-}
-
-/*
- * check_target_limit
- *
- * sptr must be a local client !
- *
- * Returns 'true' (1) when too many targets are addressed.
- * Returns 'false' (0) when it's ok to send to this target.
- */
-int check_target_limit(aClient *sptr, void *target, const char *name,
-    int created)
-{
-  register unsigned char *p;
-  register unsigned int tmp = ((size_t)target & 0xffff00) >> 8;
-  unsigned char hash = (tmp * tmp) >> 12;
-  if (sptr->targets[0] == hash)        /* Same target as last time ? */
-    return 0;
-  for (p = sptr->targets; p < &sptr->targets[MAXTARGETS - 1];)
-    if (*++p == hash)
-    {
-      memmove(&sptr->targets[1], &sptr->targets[0], p - sptr->targets);
-      sptr->targets[0] = hash;
-      return 0;
-    }
-
-  /* New target */
-  if (!created)
-  {
-    if (now < sptr->nexttarget)
-    {
-      if (sptr->nexttarget - now < TARGET_DELAY + 8)   /* No server flooding */
-      {
-       sptr->nexttarget += 2;
-       sendto_one(sptr, err_str(ERR_TARGETTOOFAST),
-           me.name, sptr->name, name, sptr->nexttarget - now);
-      }
-      return 1;
-    }
-    else
-    {
-#ifdef GODMODE
-      sendto_one(sptr, ":%s NOTICE %s :New target: %s; ft " TIME_T_FMT,
-         me.name, sptr->name, name, (now - sptr->nexttarget) / TARGET_DELAY);
-#endif
-      sptr->nexttarget += TARGET_DELAY;
-      if (sptr->nexttarget < now - (TARGET_DELAY * (MAXTARGETS - 1)))
-       sptr->nexttarget = now - (TARGET_DELAY * (MAXTARGETS - 1));
-    }
-  }
-  memmove(&sptr->targets[1], &sptr->targets[0], MAXTARGETS - 1);
-  sptr->targets[0] = hash;
-  return 0;
-}
-
-/*
- * m_message (used in m_private() and m_notice())
- *
- * The general function to deliver MSG's between users/channels
- *
- * parv[0] = sender prefix
- * parv[1] = receiver list
- * parv[parc-1] = message text
- *
- * massive cleanup
- * rev argv 6/91
- */
-static int m_message(aClient *cptr, aClient *sptr,
-    int parc, char *parv[], int notice)
-{
-  Reg1 aClient *acptr;
-  Reg2 char *s;
-  aChannel *chptr;
-  char *nick, *server, *p, *cmd, *host;
-
-  sptr->flags &= ~FLAGS_TS8;
-
-  cmd = notice ? MSG_NOTICE : MSG_PRIVATE;
-
-  if (parc < 2 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NORECIPIENT), me.name, parv[0], cmd);
-    return -1;
-  }
-
-  if (parc < 3 || *parv[parc - 1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
-    return -1;
-  }
-
-  if (MyUser(sptr))
-    parv[1] = canonize(parv[1]);
-  for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
-      nick = strtoken(&p, NULL, ","))
-  {
-    /*
-     * channel msg?
-     */
-    if (IsChannelName(nick))
-    {
-      if ((chptr = FindChannel(nick)))
-      {
-       if (can_send(sptr, chptr) == 0  /* This first: Almost never a server/service */
-           || IsChannelService(sptr) || IsServer(sptr))
-       {
-         if (MyUser(sptr) && (chptr->mode.mode & MODE_NOPRIVMSGS) &&
-             check_target_limit(sptr, chptr, chptr->chname, 0))
-           continue;
-         sendto_channel_butone(cptr, sptr, chptr,
-             ":%s %s %s :%s", parv[0], cmd, chptr->chname, parv[parc - 1]);
-       }
-       else if (!notice)
-         sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
-             me.name, parv[0], chptr->chname);
-       continue;
-      }
-    }
-    else if (*nick != '$' && !strchr(nick, '@'))
-    {
-      /*
-       * nickname addressed?
-       */
-      if (MyUser(sptr) || Protocol(cptr) < 10)
-       acptr = FindUser(nick);
-      else if ((acptr = findNUser(nick)) && !IsUser(acptr))
-       acptr = NULL;
-      if (acptr)
-      {
-       if (MyUser(sptr) && check_target_limit(sptr, acptr, acptr->name, 0))
-         continue;
-       if (!is_silenced(sptr, acptr))
-       {
-         if (!notice && MyConnect(sptr) && acptr->user && acptr->user->away)
-           sendto_one(sptr, rpl_str(RPL_AWAY),
-               me.name, parv[0], acptr->name, acptr->user->away);
-         if (MyUser(acptr) || Protocol(acptr->from) < 10)
-         {
-           if (MyUser(acptr))
-             add_target(acptr, sptr);
-           sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
-               parv[0], cmd, acptr->name, parv[parc - 1]);
-         }
-         else
-           sendto_prefix_one(acptr, sptr, ":%s %s %s%s :%s",
-               parv[0], cmd, NumNick(acptr), parv[parc - 1]);
-       }
-      }
-      else if (MyUser(sptr) || Protocol(cptr) < 10)
-       sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
-      else
-       sendto_one(sptr,
-           ":%s %d %s * :Target left UnderNet. Failed to deliver: [%.50s]",
-           me.name, ERR_NOSUCHNICK, sptr->name, parv[parc - 1]);
-      continue;
-    }
-    /*
-     * The following two cases allow masks in NOTICEs
-     * (for OPERs only)
-     *
-     * Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
-     */
-    if ((*nick == '$' || *nick == '#') && IsAnOper(sptr))
-    {
-      if (MyConnect(sptr))
-      {
-       if (!(s = strrchr(nick, '.')))
-       {
-         sendto_one(sptr, err_str(ERR_NOTOPLEVEL), me.name, parv[0], nick);
-         continue;
-       }
-       while (*++s)
-         if (*s == '.' || *s == '*' || *s == '?')
-           break;
-       if (*s == '*' || *s == '?')
-       {
-         sendto_one(sptr, err_str(ERR_WILDTOPLEVEL), me.name, parv[0], nick);
-         continue;
-       }
-      }
-      sendto_match_butone(IsServer(cptr) ? cptr : NULL,
-         sptr, nick + 1, (*nick == '#') ? MATCH_HOST : MATCH_SERVER,
-         ":%s %s %s :%s", parv[0], cmd, nick, parv[parc - 1]);
-      continue;
-    }
-    else if ((server = strchr(nick, '@')) && (acptr = FindServer(server + 1)))
-    {
-      /*
-       * NICK[%host]@server addressed? See if <server> is me first
-       */
-      if (!IsMe(acptr))
-      {
-       sendto_one(acptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[parc - 1]);
-       continue;
-      }
-
-      /* Look for an user whose NICK is equal to <nick> and then
-       * check if it's hostname matches <host> and if it's a local
-       * user. */
-      *server = '\0';
-      if ((host = strchr(nick, '%')))
-       *host++ = '\0';
-
-      if ((!(acptr = FindUser(nick))) ||
-         (!(MyUser(acptr))) ||
-         ((!(BadPtr(host))) && match(host, acptr->user->host)))
-       acptr = NULL;
-
-      *server = '@';
-      if (host)
-       *--host = '%';
-
-      if (acptr)
-      {
-       if (!(is_silenced(sptr, acptr)))
-         sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
-             parv[0], cmd, nick, parv[parc - 1]);
-       continue;
-      }
-    }
-    if (IsChannelName(nick))
-      sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], nick);
-    else
-      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
-  }
-  return 0;
-}
-
-/*
- * m_private
- *
- * parv[0] = sender prefix
- * parv[1] = receiver list
- * parv[parc-1] = message text
- */
-int m_private(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  return m_message(cptr, sptr, parc, parv, 0);
-}
-
-/*
- * m_notice
- *
- * parv[0] = sender prefix
- * parv[1] = receiver list
- * parv[parc-1] = notice text
- */
-int m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  if (MyUser(sptr) && parv[1] && parv[1][0] == '@' &&
-      IsChannelName(&parv[1][1]))
-  {
-    parv[1]++;                 /* Get rid of '@' */
-    return m_wallchops(cptr, sptr, parc, parv);
-  }
-  return m_message(cptr, sptr, parc, parv, 1);
-}
-
-
-/*
- * whisper - called from m_cnotice and m_cprivmsg.
- *
- * parv[0] = sender prefix
- * parv[1] = nick
- * parv[2] = #channel
- * parv[3] = Private message text
- *
- * Added 971023 by Run.
- * Reason: Allows channel operators to sent an arbitrary number of private
- *   messages to users on their channel, avoiding the max.targets limit.
- *   Building this into m_private would use too much cpu because we'd have
- *   to a cross channel lookup for every private message!
- * Note that we can't allow non-chan ops to use this command, it would be
- *   abused by mass advertisers.
- */
-int whisper(aClient *sptr, int parc, char *parv[], int notice)
-{
-  int s_is_member = 0, s_is_voiced = 0, t_is_member = 0;
-  aClient *tcptr;
-  aChannel *chptr;
-  register Link *lp;
-
-  if (!MyUser(sptr))
-    return 0;
-  if (parc < 4 || BadPtr(parv[3]))
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
-       me.name, parv[0], notice ? "CNOTICE" : "CPRIVMSG");
-    return 0;
-  }
-  if (!(chptr = FindChannel(parv[2])))
-  {
-    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[2]);
-    return 0;
-  }
-  if (!(tcptr = FindUser(parv[1])))
-  {
-    sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
-    return 0;
-  }
-  for (lp = chptr->members; lp; lp = lp->next)
-  {
-    register aClient *mcptr = lp->value.cptr;
-    if (mcptr == sptr)
-    {
-      s_is_member = 1;
-      if ((lp->flags & (CHFL_CHANOP | CHFL_VOICE)))
-       s_is_voiced = 1;
-      else
-       break;
-      if (t_is_member)
-       break;
-    }
-    if (mcptr == tcptr)
-    {
-      t_is_member = 1;
-      if (s_is_voiced)
-       break;
-    }
-  }
-  if (!s_is_voiced)
-  {
-    sendto_one(sptr, err_str(s_is_member ? ERR_VOICENEEDED : ERR_NOTONCHANNEL),
-       me.name, parv[0], chptr->chname);
-    return 0;
-  }
-  if (!t_is_member)
-  {
-    sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
-       me.name, parv[0], tcptr->name, chptr->chname);
-    return 0;
-  }
-  if (is_silenced(sptr, tcptr))
-    return 0;
-
-  if (tcptr->user && tcptr->user->away)
-    sendto_one(sptr, rpl_str(RPL_AWAY),
-       me.name, parv[0], tcptr->name, tcptr->user->away);
-  if (MyUser(tcptr) || Protocol(tcptr->from) < 10)
-    sendto_prefix_one(tcptr, sptr, ":%s %s %s :%s",
-       parv[0], notice ? "NOTICE" : "PRIVMSG", tcptr->name, parv[3]);
-  else
-    sendto_prefix_one(tcptr, sptr, ":%s %s %s%s :%s",
-       parv[0], notice ? "NOTICE" : "PRIVMSG", NumNick(tcptr), parv[3]);
-
-  return 0;
-}
-
-int m_cnotice(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
-{
-  return whisper(sptr, parc, parv, 1);
-}
-
-int m_cprivmsg(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
-{
-  return whisper(sptr, parc, parv, 0);
-}
-
-/*
- * m_wallchops
- *
- * parv[0] = sender prefix
- * parv[1] = target channel
- * parv[parc - 1] = wallchops text
- */
-int m_wallchops(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aChannel *chptr;
-
-  sptr->flags &= ~FLAGS_TS8;
-
-  if (parc < 2 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NORECIPIENT), me.name, parv[0], "WALLCHOPS");
-    return -1;
-  }
-
-  if (parc < 3 || *parv[parc - 1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
-    return -1;
-  }
-
-  if (MyUser(sptr))
-    parv[1] = canonize(parv[1]);
-
-  if (IsChannelName(parv[1]))
-  {
-    if ((chptr = FindChannel(parv[1])))
-    {
-      if (can_send(sptr, chptr) == 0)
-      {
-       if (MyUser(sptr) && (chptr->mode.mode & MODE_NOPRIVMSGS) &&
-           check_target_limit(sptr, chptr, chptr->chname, 0))
-         return 0;
-       /* Send to local clients: */
-       sendto_lchanops_butone(cptr, sptr, chptr,
-           ":%s NOTICE @%s :%s", parv[0], parv[1], parv[parc - 1]);
-#ifdef NO_PROTOCOL9
-       /* And to other servers: */
-       sendto_chanopsserv_butone(cptr, sptr, chptr,
-           ":%s WC %s :%s", parv[0], parv[1], parv[parc - 1]);
-#else
-       /*
-        * WARNING: `sendto_chanopsserv_butone' is heavily hacked when
-        * `NO_PROTOCOL9' is not defined ! Therefore this is the ONLY
-        * place you may use `sendto_chanopsserv_butone', until all
-        * servers are 2.10.
-        */
-       sendto_chanopsserv_butone(cptr, sptr, chptr,
-           ":%s WC %s :%s", parv[0], parv[1], parv[parc - 1]);
-#endif
-      }
-      else
-       sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
-           me.name, parv[0], parv[1]);
-    }
-  }
-  else
-    sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], parv[1]);
-
-  return 0;
-}
-
-/*
- * m_user
- *
- * parv[0] = sender prefix
- * parv[1] = username (login name, account)
- * parv[2] = umode mask
- * parv[3] = server notice mask
- * parv[4] = users real name info
- */
-int m_user(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-#define UFLAGS (FLAGS_INVISIBLE|FLAGS_WALLOP|FLAGS_SERVNOTICE)
-  char *username, *host, *server, *realname;
-  anUser *user;
-
-  if (IsServer(cptr))
-    return 0;
-
-  if (IsServerPort(cptr))
-    return exit_client(cptr, cptr, &me, "Use a different port");
-
-  if (parc > 2 && (username = strchr(parv[1], '@')))
-    *username = '\0';
-  if (parc < 5 || *parv[1] == '\0' || *parv[2] == '\0' ||
-      *parv[3] == '\0' || *parv[4] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "USER");
-    return 0;
-  }
-
-  /* Copy parameters into better documenting variables */
-
-  username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1];
-  host = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2];
-  server = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3];
-  realname = (parc < 5 || BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
-
-  user = make_user(sptr);
-
-  if (!IsUnknown(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
-    return 0;
-  }
-
-  if (!strchr(host, '.'))      /* Not an IP# as hostname ? */
-    sptr->flags |= (UFLAGS & atoi(host));
-  if ((sptr->flags & FLAGS_SERVNOTICE))
-    set_snomask(sptr, (isDigit(*server) && !strchr(server, '.')) ?
-       (atoi(server) & SNO_USER) : SNO_DEFAULT, SNO_SET);
-  user->server = &me;
-  strncpy(sptr->info, realname, sizeof(sptr->info) - 1);
-  if (sptr->name[0] && sptr->cookie == COOKIE_VERIFIED)
-    /* NICK and PONG already received, now we have USER... */
-    return register_user(cptr, sptr, sptr->name, username);
-  else
-  {
-    strncpy(sptr->user->username, username, USERLEN);
-    strncpy(user->host, host, sizeof(user->host) - 1);
-  }
-  return 0;
-}
-
-/*
- * m_quit
- *
- * parv[0] = sender prefix
- * parv[parc-1] = comment
- */
-int m_quit(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  register char *comment = (parc > 1
-      && parv[parc - 1]) ? parv[parc - 1] : cptr->name;
-
-  if (MyUser(sptr))
-  {
-    if (!strncmp("Local Kill", comment, 10) || !strncmp(comment, "Killed", 6))
-      comment = parv[0];
-    if (sptr->user)
-    {
-      Link *lp;
-      for (lp = sptr->user->channel; lp; lp = lp->next)
-       if (can_send(sptr, lp->value.chptr) != 0)
-         return exit_client(cptr, sptr, sptr, "Signed off");
-    }
-  }
-  if (strlen(comment) > (size_t)TOPICLEN)
-    comment[TOPICLEN] = '\0';
-  return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, comment);
-}
-
-/*
- * m_kill
- *
- * parv[0] = sender prefix
- * parv[1] = kill victim
- * parv[parc-1] = kill path
- */
-int m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr;
-  char *inpath = cptr->name;
-  char *user, *path, *killer;
-  int chasing = 0;
-
-  if (parc < 3 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL");
-    return 0;
-  }
-
-  user = parv[1];
-  path = parv[parc - 1];       /* Either defined or NULL (parc >= 3) */
-
-#ifdef OPER_KILL
-  if (!IsPrivileged(cptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-#else
-  if (!IsServer(cptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-#endif
-  if (IsAnOper(cptr))
-  {
-    if (BadPtr(path))
-    {
-      sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "KILL");
-      return 0;
-    }
-    if (strlen(path) > (size_t)TOPICLEN)
-      path[TOPICLEN] = '\0';
-  }
-
-  if (MyUser(sptr) || Protocol(cptr) < 10)
-  {
-    if (!(acptr = FindClient(user)))
-    {
-      /*
-       * If the user has recently changed nick, we automaticly
-       * rewrite the KILL for this new nickname--this keeps
-       * servers in synch when nick change and kill collide
-       */
-      if (!(acptr = get_history(user, (long)15)))
-      {
-       sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], user);
-       return 0;
-      }
-      sendto_one(sptr, ":%s NOTICE %s :Changed KILL %s into %s",
-         me.name, parv[0], user, acptr->name);
-      chasing = 1;
-    }
-  }
-  else if (!(acptr = findNUser(user)))
-  {
-    if (Protocol(cptr) < 10 && IsUser(sptr))
-      sendto_one(sptr,
-         ":%s NOTICE %s :KILL target disconnected before I got him :(",
-         me.name, parv[0]);
-    else if (IsUser(sptr))
-      sendto_one(sptr,
-         "%s NOTICE %s%s :KILL target disconnected before I got him :(",
-         NumServ(&me), NumNick(sptr));
-    return 0;
-  }
-  if (!MyConnect(acptr) && IsLocOp(cptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-  if (IsServer(acptr) || IsMe(acptr))
-  {
-    sendto_one(sptr, err_str(ERR_CANTKILLSERVER), me.name, parv[0]);
-    return 0;
-  }
-
-  /* if the user is +k, prevent a kill from local user */
-  if (IsChannelService(acptr) && MyUser(sptr))
-  {
-    sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
-       parv[0], "KILL", acptr->name);
-    return 0;
-  }
-
-#ifdef LOCAL_KILL_ONLY
-  if (MyConnect(sptr) && !MyConnect(acptr))
-  {
-    sendto_one(sptr, ":%s NOTICE %s :Nick %s isnt on your server",
-       me.name, parv[0], acptr->name);
-    return 0;
-  }
-#endif
-  if (!IsServer(cptr))
-  {
-    /*
-     * The kill originates from this server, initialize path.
-     * (In which case the 'path' may contain user suplied
-     * explanation ...or some nasty comment, sigh... >;-)
-     *
-     * ...!operhost!oper
-     * ...!operhost!oper (comment)
-     */
-    inpath = cptr->user->host;
-    if (!BadPtr(path))
-    {
-      sprintf_irc(buf,
-         "%s%s (%s)", cptr->name, IsOper(sptr) ? "" : "(L)", path);
-      path = buf;
-    }
-    else
-      path = cptr->name;
-  }
-  else if (BadPtr(path))
-    path = "*no-path*";                /* Bogus server sending??? */
-  /*
-   * Notify all *local* opers about the KILL (this includes the one
-   * originating the kill, if from this server--the special numeric
-   * reply message is not generated anymore).
-   *
-   * Note: "acptr->name" is used instead of "user" because we may
-   *       have changed the target because of the nickname change.
-   */
-  if (IsLocOp(sptr) && !MyConnect(acptr))
-  {
-    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
-    return 0;
-  }
-  sendto_op_mask(IsServer(sptr) ? SNO_SERVKILL : SNO_OPERKILL,
-      "Received KILL message for %s. From %s Path: %s!%s",
-      acptr->name, parv[0], inpath, path);
-#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
-  if (MyUser(acptr))
-  {                            /* get more infos when your local
-                                  clients are killed -- _dl */
-    if (IsServer(sptr))
-      syslog(LOG_DEBUG,
-         "A local client %s!%s@%s KILLED from %s [%s] Path: %s!%s)",
-         acptr->name, acptr->user->username, acptr->user->host,
-         parv[0], sptr->name, inpath, path);
-    else
-      syslog(LOG_DEBUG,
-         "A local client %s!%s@%s KILLED by %s [%s!%s@%s] (%s!%s)",
-         acptr->name, acptr->user->username, acptr->user->host,
-         parv[0], sptr->name, sptr->user->username, sptr->user->host,
-         inpath, path);
-  }
-  else if (IsOper(sptr))
-    syslog(LOG_DEBUG, "KILL From %s For %s Path %s!%s",
-       parv[0], acptr->name, inpath, path);
-#endif
-  /*
-   * 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(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
-  {
-    sendto_lowprot_butone(cptr, 9, ":%s KILL %s :%s!%s",
-       parv[0], acptr->name, inpath, path);
-    sendto_highprot_butone(cptr, 10, ":%s KILL %s%s :%s!%s",
-       parv[0], NumNick(acptr), inpath, path);
-#ifndef NO_PROTOCOL9
-    if (chasing && IsServer(cptr))     /* Can be removed when all are Protocol 10 */
-      sendto_one(cptr, ":%s KILL %s :%s!%s",
-         me.name, acptr->name, inpath, path);
-#endif
-    /* We *can* have crossed a NICK with this numeric... --Run */
-    /* Note the following situation:
-     *  KILL SAA -->       X
-     *  <-- S NICK ... SAA | <-- SAA QUIT <-- S NICK ... SAA <-- SQUIT S
-     * Where the KILL reaches point X before the QUIT does.
-     * This would then *still* cause an orphan because the KILL doesn't reach S
-     * (because of the SQUIT), the QUIT is ignored (because of the KILL)
-     * and the second NICK ... SAA causes an orphan on the server at the
-     * right (which then isn't removed when the SQUIT arrives).
-     * Therefore we still need to detect numeric nick collisions too.
-     */
-    if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
-      sendto_one(cptr, "%s KILL %s%s :%s!%s (Ghost5)",
-         NumServ(&me), NumNick(acptr), inpath, path);
-    acptr->flags |= FLAGS_KILLED;
-  }
-
-  /*
-   * Tell the victim she/he has been zapped, but *only* if
-   * the victim is on current server--no sense in sending the
-   * notification chasing the above kill, it won't get far
-   * anyway (as this user don't exist there any more either)
-   */
-  if (MyConnect(acptr))
-    sendto_prefix_one(acptr, sptr, ":%s KILL %s :%s!%s",
-       parv[0], acptr->name, inpath, path);
-  /*
-   * 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)
-   */
-  if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
-    sprintf_irc(buf2, "Local kill by %s (%s)", sptr->name,
-       BadPtr(parv[parc - 1]) ? sptr->name : parv[parc - 1]);
-  else
-  {
-    if ((killer = strchr(path, ' ')))
-    {
-      while (*killer && *killer != '!')
-       killer--;
-      if (!*killer)
-       killer = path;
-      else
-       killer++;
-    }
-    else
-      killer = path;
-    sprintf_irc(buf2, "Killed (%s)", killer);
-  }
-  return exit_client(cptr, acptr, sptr, buf2);
-}
-
-/*
- * m_away                               - Added 14 Dec 1988 by jto.
- *
- * parv[0] = sender prefix
- * parv[1] = away message
- */
-int m_away(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg1 char *away, *awy2 = parv[1];
-
-  away = sptr->user->away;
-
-  if (parc < 2 || !*awy2)
-  {
-    /* Marking as not away */
-    if (away)
-    {
-      RunFree(away);
-      sptr->user->away = NULL;
-    }
-    sendto_serv_butone(cptr, ":%s AWAY", parv[0]);
-    if (MyConnect(sptr))
-      sendto_one(sptr, rpl_str(RPL_UNAWAY), me.name, parv[0]);
-    return 0;
-  }
-
-  /* Marking as away */
-
-  if (strlen(awy2) > (size_t)TOPICLEN)
-    awy2[TOPICLEN] = '\0';
-  sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2);
-
-  if (away)
-    away = (char *)RunRealloc(away, strlen(awy2) + 1);
-  else
-    away = (char *)RunMalloc(strlen(awy2) + 1);
-
-  sptr->user->away = away;
-  strcpy(away, awy2);
-  if (MyConnect(sptr))
-    sendto_one(sptr, rpl_str(RPL_NOWAWAY), me.name, parv[0]);
-  return 0;
-}
-
-/*
- * m_ping
- *
- * parv[0] = sender prefix
- * parv[1] = origin
- * parv[2] = destination
- */
-int m_ping(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr;
-  char *origin, *destination;
-
-  if (parc < 2 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
-    return 0;
-  }
-  origin = parv[1];
-  destination = parv[2];       /* Will get NULL or pointer (parc >= 2!!) */
-
-  acptr = FindClient(origin);
-  if (acptr && acptr != sptr)
-    origin = cptr->name;
-
-  if (!BadPtr(destination) && strCasediff(destination, me.name) != 0)
-  {
-    if ((acptr = FindServer(destination)))
-      sendto_one(acptr, ":%s PING %s :%s", parv[0], origin, destination);
-    else
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
-         me.name, parv[0], destination);
-      return 0;
-    }
-  }
-  else
-    sendto_one(sptr, ":%s PONG %s :%s", me.name, me.name, origin);
-  return 0;
-}
-
-/*
- * m_pong
- *
- * parv[0] = sender prefix
- * parv[1] = origin
- * parv[2] = destination
- */
-int m_pong(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  aClient *acptr;
-  char *origin, *destination;
-
-  if (MyUser(sptr))
-    return 0;
-
-  /* Check to see if this is a PONG :cookie reply from an
-   * unregistered user.  If so, process it. -record       */
-
-  if ((!IsRegistered(sptr)) && (sptr->cookie != 0) &&
-      (sptr->cookie != COOKIE_VERIFIED) && (parc > 1))
-  {
-    if (atol(parv[parc - 1]) == (long)sptr->cookie)
-    {
-      sptr->cookie = COOKIE_VERIFIED;
-      if (sptr->user && *sptr->user->host && sptr->name[0])    /* NICK and
-                                                                  USER OK */
-       return register_user(cptr, sptr, sptr->name, sptr->user->username);
-    }
-    else
-      sendto_one(sptr, ":%s %d %s :To connect, type /QUOTE PONG %u",
-         me.name, ERR_BADPING, sptr->name, sptr->cookie);
-
-    return 0;
-  }
-
-  if (parc < 2 || *parv[1] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NOORIGIN), me.name, parv[0]);
-    return 0;
-  }
-
-  origin = parv[1];
-  destination = parv[2];
-  cptr->flags &= ~FLAGS_PINGSENT;
-  sptr->flags &= ~FLAGS_PINGSENT;
-
-  if (!BadPtr(destination) && strCasediff(destination, me.name) != 0)
-  {
-    if ((acptr = FindClient(destination)))
-      sendto_one(acptr, ":%s PONG %s %s", parv[0], origin, destination);
-    else
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
-         me.name, parv[0], destination);
-      return 0;
+
+    /*
+     * If the client hasn't gotten a cookie-ping yet,
+     * choose a cookie and send it. -record!jegelhof@cloud9.net
+     */
+    if (!sptr->cookie) {
+      do {
+        sptr->cookie = (ircrandom() & 0x7fffffff);
+      } while (!sptr->cookie);
+      sendto_one(cptr, "PING :%u", sptr->cookie);
+    }
+    else if (*sptr->user->host && sptr->cookie == COOKIE_VERIFIED) {
+      /*
+       * USER and PONG already received, now we have NICK.
+       * register_user may reject the client and call exit_client
+       * for it - must test this and exit m_nick too !
+       */
+      sptr->lastnick = TStime();        /* Always local client */
+      if (register_user(cptr, sptr, nick, sptr->user->username) == CPTR_KILLED)
+        return CPTR_KILLED;
     }
   }
-#ifdef DEBUGMODE
-  else
-    Debug((DEBUG_NOTICE, "PONG: %s %s",
-       origin, destination ? destination : "*"));
-#endif
   return 0;
 }
 
-static char umode_buf[2 * sizeof(user_modes) / sizeof(int)];
 
 /*
- * added Sat Jul 25 07:30:42 EST 1992
+ * add_target
+ *
+ * sptr must be a local client!
+ *
+ * Cannonifies target for client `sptr'.
  */
-static void send_umode_out(aClient *cptr, aClient *sptr, int old)
+void add_target(struct Client *sptr, void *target)
 {
-  Reg1 int i;
-  Reg2 aClient *acptr;
-
-  send_umode(NULL, sptr, old, SEND_UMODES);
-
-  for (i = highest_fd; i >= 0; i--)
-    if ((acptr = loc_clients[i]) && IsServer(acptr) &&
-       (acptr != cptr) && (acptr != sptr) && *umode_buf)
-      sendto_one(acptr, ":%s MODE %s :%s", sptr->name, sptr->name, umode_buf);
+  unsigned char *p;
+  unsigned int tmp = ((size_t)target & 0xffff00) >> 8;
+  unsigned char hash = (tmp * tmp) >> 12;
+  if (sptr->targets[0] == hash)        /* Last person that we messaged ourself? */
+    return;
+  for (p = sptr->targets; p < &sptr->targets[MAXTARGETS - 1];)
+    if (*++p == hash)
+      return;                        /* Already in table */
 
-  if (cptr && MyUser(cptr))
-    send_umode(cptr, sptr, old, ALL_UMODES);
+  /* New target */
+  memmove(&sptr->targets[RESERVEDTARGETS + 1],
+      &sptr->targets[RESERVEDTARGETS], MAXTARGETS - RESERVEDTARGETS - 1);
+  sptr->targets[RESERVEDTARGETS] = hash;
+  return;
 }
 
 /*
- *  m_oper
- *    parv[0] = sender prefix
- *    parv[1] = oper name
- *    parv[2] = oper password
+ * check_target_limit
+ *
+ * sptr must be a local client !
+ *
+ * Returns 'true' (1) when too many targets are addressed.
+ * Returns 'false' (0) when it's ok to send to this target.
  */
-int m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[])
+int check_target_limit(struct Client *sptr, void *target, const char *name,
+    int created)
 {
-  aConfItem *aconf;
-  char *name, *password, *encr;
-#ifdef CRYPT_OPER_PASSWORD
-  char salt[3];
-#endif /* CRYPT_OPER_PASSWORD */
-
-  name = parc > 1 ? parv[1] : NULL;
-  password = parc > 2 ? parv[2] : NULL;
-
-  if (!IsServer(cptr) && (BadPtr(name) || BadPtr(password)))
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "OPER");
-    return 0;
-  }
-
-  /* if message arrived from server, trust it, and set to oper */
-
-  if ((IsServer(cptr) || IsMe(cptr)) && !IsOper(sptr))
-  {
-    ++nrof.opers;
-    sptr->flags |= FLAGS_OPER;
-    sendto_serv_butone(cptr, ":%s MODE %s :+o", parv[0], parv[0]);
-    if (IsMe(cptr))
-      sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
-    return 0;
-  }
-  else if (IsAnOper(sptr))
-  {
-    if (MyConnect(sptr))
-      sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
-    return 0;
-  }
-  if (!(aconf = find_conf_exact(name, sptr->username, sptr->sockhost,
-      CONF_OPS)) && !(aconf = find_conf_exact(name, sptr->username,
-      inetntoa(cptr->ip), CONF_OPS)))
-  {
-    sendto_one(sptr, err_str(ERR_NOOPERHOST), me.name, parv[0]);
-    sendto_realops("Failed OPER attempt by %s (%s@%s)",
-       parv[0], sptr->user->username, sptr->sockhost);
+  unsigned char *p;
+  unsigned int tmp = ((size_t)target & 0xffff00) >> 8;
+  unsigned char hash = (tmp * tmp) >> 12;
+  if (sptr->targets[0] == hash)        /* Same target as last time ? */
     return 0;
-  }
-#ifdef CRYPT_OPER_PASSWORD
-  /* use first two chars of the password they send in as salt */
-
-  /* passwd may be NULL. Head it off at the pass... */
-  salt[0] = '\0';
-  if (password && aconf->passwd)
-  {
-    salt[0] = aconf->passwd[0];
-    salt[1] = aconf->passwd[1];
-    salt[2] = '\0';
-    encr = crypt(password, salt);
-  }
-  else
-    encr = "";
-#else
-  encr = password;
-#endif /* CRYPT_OPER_PASSWORD */
+  for (p = sptr->targets; p < &sptr->targets[MAXTARGETS - 1];)
+    if (*++p == hash)
+    {
+      memmove(&sptr->targets[1], &sptr->targets[0], p - sptr->targets);
+      sptr->targets[0] = hash;
+      return 0;
+    }
 
-  if ((aconf->status & CONF_OPS) &&
-      !strcmp(encr, aconf->passwd) && attach_conf(sptr, aconf) == ACR_OK)
+  /* New target */
+  if (!created)
   {
-    int old = (sptr->flags & ALL_UMODES);
-
-#ifdef OPER_REMOTE
-    if (aconf->status == CONF_LOCOP)
-    {
-#else
-    if (!IsLocal(sptr) || aconf->status == CONF_LOCOP)
+    if (CurrentTime < sptr->nexttarget)
     {
-#endif
-      ClearOper(sptr);
-      SetLocOp(sptr);
+      if (sptr->nexttarget - CurrentTime < TARGET_DELAY + 8)        /* No server flooding */
+      {
+        sptr->nexttarget += 2;
+        sendto_one(sptr, err_str(ERR_TARGETTOOFAST),
+            me.name, sptr->name, name, sptr->nexttarget - CurrentTime);
+      }
+      return 1;
     }
     else
     {
-      /* prevent someone from being both oper and local oper */
-      ClearLocOp(sptr);
-      SetOper(sptr);
-      ++nrof.opers;
-    }
-    sendto_ops("%s (%s@%s) is now operator (%c)", parv[0],
-       sptr->user->username, sptr->sockhost, IsOper(sptr) ? 'O' : 'o');
-    sptr->flags |= (FLAGS_WALLOP | FLAGS_SERVNOTICE | FLAGS_DEBUG);
-    set_snomask(sptr, SNO_OPERDEFAULT, SNO_ADD);
-    send_umode_out(cptr, sptr, old);
-    sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
-#if !defined(CRYPT_OPER_PASSWORD) && (defined(FNAME_OPERLOG) ||\
-    (defined(USE_SYSLOG) && defined(SYSLOG_OPER)))
-    encr = "";
-#endif
-#if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
-    syslog(LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s)",
-       name, encr, parv[0], sptr->user->username, sptr->sockhost);
-#endif
-#ifdef FNAME_OPERLOG
-    if (IsUser(sptr))
-      write_log(FNAME_OPERLOG,
-         "%s OPER (%s) (%s) by (%s!%s@%s)\n", myctime(now), name,
-         encr, parv[0], sptr->user->username, sptr->sockhost);
+#ifdef GODMODE
+      sendto_one(sptr, ":%s NOTICE %s :New target: %s; ft " TIME_T_FMT,
+          me.name, sptr->name, name, (CurrentTime - sptr->nexttarget) / TARGET_DELAY);
 #endif
+      sptr->nexttarget += TARGET_DELAY;
+      if (sptr->nexttarget < CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1)))
+        sptr->nexttarget = CurrentTime - (TARGET_DELAY * (MAXTARGETS - 1));
+    }
   }
-  else
-  {
-    detach_conf(sptr, aconf);
-    sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
-    sendto_realops("Failed OPER attempt by %s (%s@%s)",
-       parv[0], sptr->user->username, sptr->sockhost);
-  }
+  memmove(&sptr->targets[1], &sptr->targets[0], MAXTARGETS - 1);
+  sptr->targets[0] = hash;
   return 0;
 }
 
 /*
- * m_pass
+ * whisper - called from m_cnotice and m_cprivmsg.
  *
  * parv[0] = sender prefix
- * parv[1] = password
+ * parv[1] = nick
+ * parv[2] = #channel
+ * parv[3] = Private message text
+ *
+ * Added 971023 by Run.
+ * Reason: Allows channel operators to sent an arbitrary number of private
+ *   messages to users on their channel, avoiding the max.targets limit.
+ *   Building this into m_private would use too much cpu because we'd have
+ *   to a cross channel lookup for every private message!
+ * Note that we can't allow non-chan ops to use this command, it would be
+ *   abused by mass advertisers.
+ *
  */
-int m_pass(aClient *cptr, aClient *sptr, int parc, char *parv[])
+int whisper(struct Client* source, const char* nick, const char* channel,
+            const char* text, int is_notice)
 {
-  char *password = parc > 1 ? parv[1] : NULL;
+  struct Client*     dest;
+  struct Channel*    chptr;
+  struct Membership* membership;
 
-  if (BadPtr(password))
-  {
-    sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "PASS");
+  assert(0 != source);
+  assert(0 != nick);
+  assert(0 != channel);
+  assert(MyUser(source));
+
+  if (!(dest = FindUser(nick))) {
+    sendto_one(source, err_str(ERR_NOSUCHNICK), me.name, source->name, nick);
     return 0;
   }
-  if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
-  {
-    sendto_one(cptr, err_str(ERR_ALREADYREGISTRED), me.name, parv[0]);
+  if (!(chptr = FindChannel(channel))) {
+    sendto_one(source, err_str(ERR_NOSUCHCHANNEL), me.name, source->name, channel);
     return 0;
   }
-  strncpy(cptr->passwd, password, sizeof(cptr->passwd) - 1);
-  return 0;
-}
-
-/*
- * m_userhost
- *
- * Added by Darren Reed 13/8/91 to aid clients and reduce the need for
- * complicated requests like WHOIS.
- *
- * Returns user/host information only (no spurious AWAY labels or channels).
- *
- * Rewritten to speed it up by Carlo Wood 3/8/97.
- */
-int m_userhost(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
-{
-  Reg1 char *s;
-  Reg2 int i, j = 5;
-  char *p = NULL, *sbuf;
-  aClient *acptr;
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "USERHOST");
+  /*
+   * compare both users channel lists, instead of the channels user list
+   * since the link is the same, this should be a little faster for channels
+   * with a lot of users
+   */
+  for (membership = source->user->channel; membership; membership = membership->next_channel) {
+    if (chptr == membership->channel)
+      break;
+  }
+  if (0 == membership) {
+    sendto_one(source, err_str(ERR_NOTONCHANNEL), me.name, source->name, chptr->chname);
     return 0;
   }
-
-  sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERHOST), me.name, parv[0]);
-  for (i = j, s = strtoken(&p, parv[1], " "); i && s;
-      s = strtoken(&p, (char *)NULL, " "), i--)
-    if ((acptr = FindUser(s)))
-    {
-      if (i < j)
-       *sbuf++ = ' ';
-      sbuf = sprintf_irc(sbuf, "%s%s=%c%s@%s", acptr->name,
-         IsAnOper(acptr) ? "*" : "", (acptr->user->away) ? '-' : '+',
-         acptr->user->username, acptr->user->host);
-    }
-    else
-    {
-      if (i < j)
-       sendbufto_one(sptr);
-      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], s);
-      sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERHOST), me.name, parv[0]);
-      j = i - 1;
-    }
-  if (j)
-    sendbufto_one(sptr);
+  if (!IsVoicedOrOpped(membership)) {
+    sendto_one(source, err_str(ERR_VOICENEEDED), me.name, source->name, chptr->chname);
+    return 0;
+  }
+  /*
+   * lookup channel in destination
+   */
+  assert(0 != dest->user);
+  for (membership = dest->user->channel; membership; membership = membership->next_channel) {
+    if (chptr == membership->channel)
+      break;
+  }
+  if (0 == membership || IsZombie(membership)) {
+    sendto_one(source, err_str(ERR_USERNOTINCHANNEL), me.name, 
+               source->name, dest->name, chptr->chname);
+    return 0;
+  }
+  if (is_silenced(source, dest))
+    return 0;
+          
+  if (dest->user->away)
+    sendto_one(source, rpl_str(RPL_AWAY), me.name, source->name,
+               dest->name, dest->user->away);
+  if (MyUser(dest))
+    sendto_prefix_one(dest, source, ":%s %s %s :%s",
+                      source->name, is_notice ? MSG_NOTICE : MSG_PRIVATE, 
+                      dest->name, text);
+  else
+    sendto_one(dest, "%s%s %s %s%s :%s",
+               NumNick(source), is_notice ? TOK_NOTICE : TOK_PRIVATE, 
+               NumNick(dest), text);
   return 0;
 }
 
+
 /*
- * m_userip added by Carlo Wood 3/8/97.
- *
- * The same as USERHOST, but with the IP-number instead of the hostname.
+ * added Sat Jul 25 07:30:42 EST 1992
  */
-int m_userip(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
+void send_umode_out(struct Client *cptr, struct Client *sptr, int old)
 {
-  Reg1 char *s;
-  Reg3 int i, j = 5;
-  char *p = NULL, *sbuf;
-  aClient *acptr;
+  int i;
+  struct Client *acptr;
 
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "USERIP");
-    return 0;
-  }
+  send_umode(NULL, sptr, old, SEND_UMODES);
 
-  sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERIP), me.name, parv[0]);
-  for (i = j, s = strtoken(&p, parv[1], " "); i && s;
-      s = strtoken(&p, (char *)NULL, " "), i--)
-    if ((acptr = FindUser(s)))
-    {
-      if (i < j)
-       *sbuf++ = ' ';
-      sbuf = sprintf_irc(sbuf, "%s%s=%c%s@%s", acptr->name,
-         IsAnOper(acptr) ? "*" : "", (acptr->user->away) ? '-' : '+',
-         acptr->user->username, inetntoa(acptr->ip));
-    }
-    else
-    {
-      if (i < j)
-       sendbufto_one(sptr);
-      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], s);
-      sbuf = sprintf_irc(sendbuf, rpl_str(RPL_USERIP), me.name, parv[0]);
-      j = i - 1;
-    }
-  if (i < j)
-    sendbufto_one(sptr);
-  return 0;
+  for (i = HighestFd; i >= 0; i--) {
+    if ((acptr = LocalClientArray[i]) && IsServer(acptr) &&
+        (acptr != cptr) && (acptr != sptr) && *umodeBuf)
+      sendto_one(acptr, "%s%s " TOK_MODE " %s :%s", NumNick(sptr), sptr->name, umodeBuf);
+  }
+  if (cptr && MyUser(cptr))
+    send_umode(cptr, sptr, old, ALL_UMODES);
 }
 
+
 /*
- * 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
+ * send_user_info - send user info userip/userhost
+ * NOTE: formatter must put info into buffer and return a pointer to the end of
+ * the data it put in the buffer.
  */
-
-int m_ison(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
+void send_user_info(struct Client* sptr, char* names, int rpl, InfoFormatter fmt)
 {
-  Reg1 aClient *acptr;
-  Reg2 char *s, **pav = parv;
-  Reg3 size_t len;
-  char *p = NULL;
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "ISON");
-    return 0;
-  }
-
-  sprintf_irc(buf, rpl_str(RPL_ISON), me.name, *parv);
-  len = strlen(buf);
-  buf[sizeof(buf) - 1] = 0;
-
-  for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " "))
-    if ((acptr = FindUser(s)))
-    {
-      strncat(buf, acptr->name, sizeof(buf) - 1 - len);
-      len += strlen(acptr->name);
-      if (len >= sizeof(buf) - 1)
-       break;
-      strcat(buf, " ");
-      len++;
+  char*          sbuf;
+  char*          name;
+  char*          p = 0;
+  int            arg_count = 0;
+  int            users_found = 0;
+  struct Client* acptr;
+  char           buf[BUFSIZE * 2];
+
+  assert(0 != sptr);
+  assert(0 != names);
+  assert(0 != fmt);
+
+  sbuf = sprintf_irc(buf, rpl_str(rpl), me.name, sptr->name);
+
+  for (name = ircd_strtok(&p, names, " "); name; name = ircd_strtok(&p, 0, " ")) {
+    if ((acptr = FindUser(name))) {
+      if (users_found++)
+        *sbuf++ = ' ';
+      sbuf = (*fmt)(acptr, sbuf);
     }
-  sendto_one(sptr, "%s", buf);
-  return 0;
+    else
+      send_error_to_client(sptr, ERR_NOSUCHNICK, name);
+    if (5 == ++arg_count)
+      break;
+  }
+  if (users_found)
+    send_buffer(sptr, buf);
 }
 
+
 /*
- * m_umode() added 15/10/91 By Darren Reed.
+ * set_user_mode() added 15/10/91 By Darren Reed.
  *
  * parv[0] - sender
  * parv[1] - username to change mode for
  * parv[2] - modes to change
  */
-int m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
+int set_user_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
 {
-  Reg1 int flag;
-  Reg2 int *s;
-  Reg3 char **p, *m;
-  aClient *acptr;
-  int what, setflags;
-  snomask_t tmpmask = 0;
+  char** p;
+  char*  m;
+  struct Client *acptr;
+  int what;
+  int i;
+  int setflags;
+  unsigned int tmpmask = 0;
   int snomask_given = 0;
+  char buf[BUFSIZE];
 
   what = MODE_ADD;
 
   if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "MODE");
-    return 0;
-  }
+    return need_more_params(sptr, "MODE");
 
   if (!(acptr = FindUser(parv[1])))
   {
@@ -2484,7 +1087,7 @@ int m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
   {
     if (IsServer(cptr))
       sendto_ops_butone(NULL, &me, ":%s WALLOPS :MODE for User %s From %s!%s",
-         me.name, parv[1], cptr->name, sptr->name);
+          me.name, parv[1], cptr->name, sptr->name);
     else
       sendto_one(sptr, err_str(ERR_USERSDONTMATCH), me.name, parv[0]);
     return 0;
@@ -2494,119 +1097,162 @@ int m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
   {
     m = buf;
     *m++ = '+';
-    for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4); s += 2)
-      if (sptr->flags & flag)
-       *m++ = (char)(*(s + 1));
+    for (i = 0; i < USERMODELIST_SIZE; ++i) {
+      if ( (userModeList[i].flag & sptr->flags))
+        *m++ = userModeList[i].c;
+    }
     *m = '\0';
     sendto_one(sptr, rpl_str(RPL_UMODEIS), me.name, parv[0], buf);
     if ((sptr->flags & FLAGS_SERVNOTICE) && MyConnect(sptr)
-       && sptr->snomask !=
-       (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT))
+        && sptr->snomask !=
+        (unsigned int)(IsOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT))
       sendto_one(sptr, rpl_str(RPL_SNOMASK), me.name, parv[0], sptr->snomask,
-         sptr->snomask);
+          sptr->snomask);
     return 0;
   }
 
-  /* find flags already set for user */
+  /*
+   * find flags already set for user
+   * why not just copy them?
+   */
+  setflags = sptr->flags;
+#if 0
   setflags = 0;
-  for (s = user_modes; (flag = *s); s += 2)
-    if (sptr->flags & flag)
-      setflags |= flag;
+  for (i = 0; i < USERMODELIST_SIZE; ++i) {
+    if (sptr->flags & userModeList[i].flag)
+      setflags |= userModeList[i].flag;
+  }
+#endif
   if (MyConnect(sptr))
     tmpmask = sptr->snomask;
 
   /*
    * parse mode change string(s)
    */
-  for (p = &parv[2]; *p; p++)  /* p is changed in loop too */
-    for (m = *p; *m; m++)
-      switch (*m)
-      {
-       case '+':
-         what = MODE_ADD;
-         break;
-       case '-':
-         what = MODE_DEL;
-         break;
-       case 's':
-         if (*(p + 1) && is_snomask(*(p + 1)))
-         {
-           snomask_given = 1;
-           tmpmask = umode_make_snomask(tmpmask, *++p, what);
-           tmpmask &= (IsAnOper(sptr) ? SNO_ALL : SNO_USER);
-         }
-         else
-           tmpmask = (what == MODE_ADD) ?
-               (IsAnOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT) : 0;
-         if (tmpmask)
-           sptr->flags |= FLAGS_SERVNOTICE;
-         else
-           sptr->flags &= ~FLAGS_SERVNOTICE;
-         break;
-         /*
-          * We may not get these, but they shouldnt be in default:
-          */
-       case ' ':
-       case '\n':
-       case '\r':
-       case '\t':
-         break;
-       default:
-         for (s = user_modes; (flag = *s); s += 2)
-           if (*m == (char)(*(s + 1)))
-           {
-             if (what == MODE_ADD)
-               sptr->flags |= flag;
-             else if ((flag & (FLAGS_OPER | FLAGS_LOCOP)))
-             {
-               sptr->flags &= ~(FLAGS_OPER | FLAGS_LOCOP);
-               if (MyConnect(sptr))
-                 tmpmask = sptr->snomask & ~SNO_OPER;
-             }
-             /* allow either -o or -O to reset all operator status's... */
-             else
-               sptr->flags &= ~flag;
-             break;
-           }
-         if (flag == 0 && MyConnect(sptr))
-           sendto_one(sptr, err_str(ERR_UMODEUNKNOWNFLAG), me.name, parv[0]);
-         break;
+  for (p = &parv[2]; *p; p++) {       /* p is changed in loop too */
+    for (m = *p; *m; m++) {
+      switch (*m) {
+      case '+':
+        what = MODE_ADD;
+        break;
+      case '-':
+        what = MODE_DEL;
+        break;
+      case 's':
+        if (*(p + 1) && is_snomask(*(p + 1))) {
+          snomask_given = 1;
+          tmpmask = umode_make_snomask(tmpmask, *++p, what);
+          tmpmask &= (IsAnOper(sptr) ? SNO_ALL : SNO_USER);
+        }
+        else
+          tmpmask = (what == MODE_ADD) ?
+              (IsAnOper(sptr) ? SNO_OPERDEFAULT : SNO_DEFAULT) : 0;
+        if (tmpmask)
+          sptr->flags |= FLAGS_SERVNOTICE;
+        else
+          sptr->flags &= ~FLAGS_SERVNOTICE;
+        break;
+      case 'w':
+        if (what == MODE_ADD)
+          SetWallops(sptr);
+        else
+          ClearWallops(sptr);
+        break;
+      case 'o':
+        if (what == MODE_ADD)
+          SetOper(sptr);
+        else {
+          sptr->flags &= ~(FLAGS_OPER | FLAGS_LOCOP);
+          if (MyConnect(sptr)) {
+            tmpmask = sptr->snomask & ~SNO_OPER;
+            sptr->handler = CLIENT_HANDLER;
+          }
+        }
+        break;
+      case 'O':
+        if (what == MODE_ADD)
+          SetLocOp(sptr);
+        else { 
+          sptr->flags &= ~(FLAGS_OPER | FLAGS_LOCOP);
+          if (MyConnect(sptr)) {
+            tmpmask = sptr->snomask & ~SNO_OPER;
+            sptr->handler = CLIENT_HANDLER;
+          }
+        }
+        break;
+      case 'i':
+        if (what == MODE_ADD)
+          SetInvisible(sptr);
+        else
+          ClearInvisible(sptr);
+        break;
+      case 'd':
+        if (what == MODE_ADD)
+          SetDeaf(sptr);
+        else
+          ClearDeaf(sptr);
+        break;
+      case 'k':
+        if (what == MODE_ADD)
+          SetChannelService(sptr);
+        else
+          ClearChannelService(sptr);
+        break;
+      case 'g':
+        if (what == MODE_ADD)
+          SetDebug(sptr);
+        else
+          ClearDebug(sptr);
+        break;
+      default:
+        break;
       }
+    }
+  }
   /*
+   * Evaluate rules for new user mode
    * Stop users making themselves operators too easily:
    */
   if (!(setflags & FLAGS_OPER) && IsOper(sptr) && !IsServer(cptr))
     ClearOper(sptr);
   if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr) && !IsServer(cptr))
-    sptr->flags &= ~FLAGS_LOCOP;
+    ClearLocOp(sptr);
+#ifdef WALLOPS_OPER_ONLY
+  /*
+   * only send wallops to opers
+   */
+  if (!IsAnOper(sptr) && !(setflags & FLAGS_WALLOP) && !IsServer(cptr))
+    ClearWallops(sptr);
+#endif
   if ((setflags & (FLAGS_OPER | FLAGS_LOCOP)) && !IsAnOper(sptr) &&
       MyConnect(sptr))
     det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPS);
-  /* new umode; servers can set it, local users cannot;
-   * prevents users from /kick'ing or /mode -o'ing */
+  /*
+   * new umode; servers can set it, local users cannot;
+   * prevents users from /kick'ing or /mode -o'ing
+   */
   if (!(setflags & FLAGS_CHSERV) && !IsServer(cptr))
-    sptr->flags &= ~FLAGS_CHSERV;
+    ClearChannelService(sptr);
   /*
    * Compare new flags with old flags and send string which
    * will cause servers to update correctly.
    */
   if ((setflags & FLAGS_OPER) && !IsOper(sptr))
-    --nrof.opers;
+    --UserStats.opers;
   if (!(setflags & FLAGS_OPER) && IsOper(sptr))
-    ++nrof.opers;
+    ++UserStats.opers;
   if ((setflags & FLAGS_INVISIBLE) && !IsInvisible(sptr))
-    --nrof.inv_clients;
+    --UserStats.inv_clients;
   if (!(setflags & FLAGS_INVISIBLE) && IsInvisible(sptr))
-    ++nrof.inv_clients;
+    ++UserStats.inv_clients;
   send_umode_out(cptr, sptr, setflags);
 
-  if (MyConnect(sptr))
-  {
+  if (MyConnect(sptr)) {
     if (tmpmask != sptr->snomask)
       set_snomask(sptr, tmpmask, SNO_SET);
     if (sptr->snomask && snomask_given)
       sendto_one(sptr, rpl_str(RPL_SNOMASK), me.name, sptr->name,
-         sptr->snomask, sptr->snomask);
+                 sptr->snomask, sptr->snomask);
   }
 
   return 0;
@@ -2616,68 +1262,71 @@ int m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
  * Build umode string for BURST command
  * --Run
  */
-char *umode_str(aClient *cptr)
+char *umode_str(struct Client *cptr)
 {
-  char *m = umode_buf;         /* Maximum string size: "owidg\0" */
-  int *s, flag, c_flags;
+  char* m = umodeBuf;                /* Maximum string size: "owidg\0" */
+  int   i;
+  int   c_flags;
 
-  c_flags = cptr->flags & SEND_UMODES; /* cleaning up the original code */
+  c_flags = cptr->flags & SEND_UMODES;        /* cleaning up the original code */
 
-  for (s = user_modes; (flag = *s); s += 2)
-    if ((c_flags & flag))
-      *m++ = *(s + 1);
+  for (i = 0; i < USERMODELIST_SIZE; ++i) {
+    if ( (c_flags & userModeList[i].flag))
+      *m++ = userModeList[i].c;
+  }
   *m = '\0';
 
-  return umode_buf;            /* Note: static buffer, gets
-                                  overwritten by send_umode() */
+  return umodeBuf;                /* Note: static buffer, gets
+                                   overwritten by send_umode() */
 }
 
 /*
  * Send the MODE string for user (user) to connection cptr
  * -avalon
  */
-void send_umode(aClient *cptr, aClient *sptr, int old, int sendmask)
+void send_umode(struct Client *cptr, struct Client *sptr, int old, int sendmask)
 {
-  Reg1 int *s, flag;
-  Reg2 char *m;
+  int i;
+  int flag;
+  char *m;
   int what = MODE_NULL;
 
   /*
-   * Build a string in umode_buf to represent the change in the user's
+   * Build a string in umodeBuf to represent the change in the user's
    * mode between the new (sptr->flag) and 'old'.
    */
-  m = umode_buf;
+  m = umodeBuf;
   *m = '\0';
-  for (s = user_modes; (flag = *s); s += 2)
-  {
+  for (i = 0; i < USERMODELIST_SIZE; ++i) {
+    flag = userModeList[i].flag;
     if (MyUser(sptr) && !(flag & sendmask))
       continue;
-    if ((flag & old) && !(sptr->flags & flag))
+    if ( (flag & old) && !(sptr->flags & flag))
     {
       if (what == MODE_DEL)
-       *m++ = *(s + 1);
+        *m++ = userModeList[i].c;
       else
       {
-       what = MODE_DEL;
-       *m++ = '-';
-       *m++ = *(s + 1);
+        what = MODE_DEL;
+        *m++ = '-';
+        *m++ = userModeList[i].c;
       }
     }
     else if (!(flag & old) && (sptr->flags & flag))
     {
       if (what == MODE_ADD)
-       *m++ = *(s + 1);
+        *m++ = userModeList[i].c;
       else
       {
-       what = MODE_ADD;
-       *m++ = '+';
-       *m++ = *(s + 1);
+        what = MODE_ADD;
+        *m++ = '+';
+        *m++ = userModeList[i].c;
       }
     }
   }
   *m = '\0';
-  if (*umode_buf && cptr)
-    sendto_one(cptr, ":%s MODE %s :%s", sptr->name, sptr->name, umode_buf);
+  if (*umodeBuf && cptr)
+    sendto_one(cptr, ":%s MODE %s :%s", sptr->name, sptr->name, umodeBuf);
 }
 
 /*
@@ -2690,10 +1339,10 @@ int is_snomask(char *word)
   if (word)
   {
     for (; *word; word++)
-      if (isDigit(*word))
-       return 1;
-      else if (isAlpha(*word))
-       return 0;
+      if (IsDigit(*word))
+        return 1;
+      else if (IsAlpha(*word))
+        return 0;
   }
   return 0;
 }
@@ -2702,10 +1351,10 @@ int is_snomask(char *word)
  * If it begins with a +, count this as an additive mask instead of just
  * a replacement.  If what == MODE_DEL, "+" has no special effect.
  */
-snomask_t umode_make_snomask(snomask_t oldmask, char *arg, int what)
+unsigned int umode_make_snomask(unsigned int oldmask, char *arg, int what)
 {
-  snomask_t sno_what;
-  snomask_t newmask;
+  unsigned int sno_what;
+  unsigned int newmask;
   if (*arg == '+')
   {
     arg++;
@@ -2725,7 +1374,7 @@ snomask_t umode_make_snomask(snomask_t oldmask, char *arg, int what)
   else
     sno_what = (what == MODE_ADD) ? SNO_SET : SNO_DEL;
   /* pity we don't have strtoul everywhere */
-  newmask = (snomask_t)atoi(arg);
+  newmask = (unsigned int)atoi(arg);
   if (sno_what == SNO_DEL)
     newmask = oldmask & ~newmask;
   else if (sno_what == SNO_ADD)
@@ -2733,17 +1382,34 @@ snomask_t umode_make_snomask(snomask_t oldmask, char *arg, int what)
   return newmask;
 }
 
+static void delfrom_list(struct Client *cptr, struct SLink **list)
+{
+  struct SLink* tmp;
+  struct SLink* prv = NULL;
+
+  for (tmp = *list; tmp; tmp = tmp->next) {
+    if (tmp->value.cptr == cptr) {
+      if (prv)
+        prv->next = tmp->next;
+      else
+        *list = tmp->next;
+      free_link(tmp);
+      break;
+    }
+    prv = tmp;
+  }
+}
+
 /*
  * This function sets a Client's server notices mask, according to
  * the parameter 'what'.  This could be even faster, but the code
  * gets mighty hard to read :)
  */
-void delfrom_list(aClient *, Link **);
-void set_snomask(aClient *cptr, snomask_t newmask, int what)
+void set_snomask(struct Client *cptr, unsigned int newmask, int what)
 {
-  snomask_t oldmask, diffmask; /* unsigned please */
+  unsigned int oldmask, diffmask;        /* unsigned please */
   int i;
-  Link *tmp;
+  struct SLink *tmp;
 
   oldmask = cptr->snomask;
 
@@ -2751,46 +1417,29 @@ void set_snomask(aClient *cptr, snomask_t newmask, int what)
     newmask |= oldmask;
   else if (what == SNO_DEL)
     newmask = oldmask & ~newmask;
-  else if (what != SNO_SET)    /* absolute set, no math needed */
+  else if (what != SNO_SET)        /* absolute set, no math needed */
     sendto_ops("setsnomask called with %d ?!", what);
 
   newmask &= (IsAnOper(cptr) ? SNO_ALL : SNO_USER);
 
   diffmask = oldmask ^ newmask;
 
-  for (i = 0; diffmask >> i; i++)
+  for (i = 0; diffmask >> i; i++) {
     if (((diffmask >> i) & 1))
     {
       if (((newmask >> i) & 1))
       {
-       tmp = make_link();
-       tmp->next = opsarray[i];
-       tmp->value.cptr = cptr;
-       opsarray[i] = tmp;
+        tmp = make_link();
+        tmp->next = opsarray[i];
+        tmp->value.cptr = cptr;
+        opsarray[i] = tmp;
       }
       else
-       /* not real portable :( */
-       delfrom_list(cptr, &opsarray[i]);
+        /* not real portable :( */
+        delfrom_list(cptr, &opsarray[i]);
     }
-  cptr->snomask = newmask;
-}
-
-void delfrom_list(aClient *cptr, Link **list)
-{
-  Link *tmp, *prv = NULL;
-  for (tmp = *list; tmp; tmp = tmp->next)
-  {
-    if (tmp->value.cptr == cptr)
-    {
-      if (prv)
-       prv->next = tmp->next;
-      else
-       *list = tmp->next;
-      free_link(tmp);
-      break;
-    }
-    prv = tmp;
   }
+  cptr->snomask = newmask;
 }
 
 /*
@@ -2801,10 +1450,10 @@ void delfrom_list(aClient *cptr, Link **list)
  * but more over, if this is detected on a server not local to sptr
  * the SILENCE mask is sent upstream.
  */
-int is_silenced(aClient *sptr, aClient *acptr)
+int is_silenced(struct Client *sptr, struct Client *acptr)
 {
-  Reg1 Link *lp;
-  Reg2 anUser *user;
+  struct SLink *lp;
+  struct User *user;
   static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
   static char senderip[16 + NICKLEN + USERLEN + 5];
 
@@ -2812,20 +1461,20 @@ int is_silenced(aClient *sptr, aClient *acptr)
     return 0;
   sprintf_irc(sender, "%s!%s@%s", sptr->name, user->username, user->host);
   sprintf_irc(senderip, "%s!%s@%s", sptr->name, user->username,
-      inetntoa(sptr->ip));
+              ircd_ntoa((const char*) &sptr->ip));
   for (; lp; lp = lp->next)
   {
     if ((!(lp->flags & CHFL_SILENCE_IPMASK) && !match(lp->value.cp, sender)) ||
-       ((lp->flags & CHFL_SILENCE_IPMASK) && !match(lp->value.cp, senderip)))
+        ((lp->flags & CHFL_SILENCE_IPMASK) && !match(lp->value.cp, senderip)))
     {
       if (!MyConnect(sptr))
       {
-       if (Protocol(sptr->from) < 10)
-         sendto_one(sptr->from, ":%s SILENCE %s %s", acptr->name,
-             sptr->name, lp->value.cp);
-       else
-         sendto_one(sptr->from, ":%s SILENCE %s%s %s", acptr->name,
-             NumNick(sptr), lp->value.cp);
+        if (Protocol(sptr->from) < 10)
+          sendto_one(sptr->from, ":%s SILENCE %s %s", acptr->name,
+              sptr->name, lp->value.cp);
+        else
+          sendto_one(sptr->from, ":%s SILENCE %s%s %s", acptr->name,
+              NumNick(sptr), lp->value.cp);
       }
       return 1;
     }
@@ -2839,42 +1488,42 @@ int is_silenced(aClient *sptr, aClient *acptr)
  * Removes all silence masks from the list of sptr that fall within `mask'
  * Returns -1 if none where found, 0 otherwise.
  */
-int del_silence(aClient *sptr, char *mask)
+int del_silence(struct Client *sptr, char *mask)
 {
-  Reg1 Link **lp;
-  Reg2 Link *tmp;
+  struct SLink **lp;
+  struct SLink *tmp;
   int ret = -1;
 
-  for (lp = &sptr->user->silence; *lp;)
+  for (lp = &sptr->user->silence; *lp;) {
     if (!mmatch(mask, (*lp)->value.cp))
     {
       tmp = *lp;
       *lp = tmp->next;
-      RunFree(tmp->value.cp);
+      MyFree(tmp->value.cp);
       free_link(tmp);
       ret = 0;
     }
     else
       lp = &(*lp)->next;
-
+  }
   return ret;
 }
 
-static int add_silence(aClient *sptr, char *mask)
+int add_silence(struct Client* sptr, const char* mask)
 {
-  Reg1 Link *lp, **lpp;
-  Reg3 int cnt = 0, len = strlen(mask);
+  struct SLink *lp, **lpp;
+  int cnt = 0, len = strlen(mask);
   char *ip_start;
 
   for (lpp = &sptr->user->silence, lp = *lpp; lp;)
   {
-    if (!strCasediff(mask, lp->value.cp))
+    if (0 == ircd_strcmp(mask, lp->value.cp))
       return -1;
     if (!mmatch(mask, lp->value.cp))
     {
-      Link *tmp = lp;
+      struct SLink *tmp = lp;
       *lpp = lp = lp->next;
-      RunFree(tmp->value.cp);
+      MyFree(tmp->value.cp);
       free_link(tmp);
       continue;
     }
@@ -2883,19 +1532,20 @@ static int add_silence(aClient *sptr, char *mask)
       len += strlen(lp->value.cp);
       if ((len > MAXSILELENGTH) || (++cnt >= MAXSILES))
       {
-       sendto_one(sptr, err_str(ERR_SILELISTFULL), me.name, sptr->name, mask);
-       return -1;
+        sendto_one(sptr, err_str(ERR_SILELISTFULL), me.name, sptr->name, mask);
+        return -1;
       }
       else if (!mmatch(lp->value.cp, mask))
-       return -1;
+        return -1;
     }
     lpp = &lp->next;
     lp = *lpp;
   }
   lp = make_link();
-  memset(lp, 0, sizeof(Link));
+  memset(lp, 0, sizeof(struct SLink));
   lp->next = sptr->user->silence;
-  lp->value.cp = (char *)RunMalloc(strlen(mask) + 1);
+  lp->value.cp = (char*) MyMalloc(strlen(mask) + 1);
+  assert(0 != lp->value.cp);
   strcpy(lp->value.cp, mask);
   if ((ip_start = strrchr(mask, '@')) && check_if_ipmask(ip_start + 1))
     lp->flags = CHFL_SILENCE_IPMASK;
@@ -2903,91 +1553,3 @@ static int add_silence(aClient *sptr, char *mask)
   return 0;
 }
 
-/*
- * m_silence() - Added 19 May 1994 by Run.
- *
- *   parv[0] = sender prefix
- * From local client:
- *   parv[1] = mask (NULL sends the list)
- * From remote client:
- *   parv[1] = Numeric nick that must be silenced
- *   parv[2] = mask
- */
-int m_silence(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Link *lp;
-  aClient *acptr;
-  char c, *cp;
-
-  if (MyUser(sptr))
-  {
-    acptr = sptr;
-    if (parc < 2 || *parv[1] == '\0' || (acptr = FindUser(parv[1])))
-    {
-      if (!(acptr->user))
-       return 0;
-      for (lp = acptr->user->silence; lp; lp = lp->next)
-       sendto_one(sptr, rpl_str(RPL_SILELIST), me.name,
-           sptr->name, acptr->name, lp->value.cp);
-      sendto_one(sptr, rpl_str(RPL_ENDOFSILELIST), me.name, sptr->name,
-         acptr->name);
-      return 0;
-    }
-    cp = parv[1];
-    c = *cp;
-    if (c == '-' || c == '+')
-      cp++;
-    else if (!(strchr(cp, '@') || strchr(cp, '.') ||
-       strchr(cp, '!') || strchr(cp, '*')))
-    {
-      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
-      return -1;
-    }
-    else
-      c = '+';
-    cp = pretty_mask(cp);
-    if ((c == '-' && !del_silence(sptr, cp)) ||
-       (c != '-' && !add_silence(sptr, cp)))
-    {
-      sendto_prefix_one(sptr, sptr, ":%s SILENCE %c%s", parv[0], c, cp);
-      if (c == '-')
-       sendto_serv_butone(NULL, ":%s SILENCE * -%s", sptr->name, cp);
-    }
-  }
-  else if (parc < 3 || *parv[2] == '\0')
-  {
-    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "SILENCE");
-    return -1;
-  }
-  else
-  {
-    if (Protocol(cptr) < 10)
-      acptr = FindClient(parv[1]);     /* In case of NOTE notice, parv[1] */
-    else if (parv[1][1])       /* can be a server */
-      acptr = findNUser(parv[1]);
-    else
-      acptr = FindNServer(parv[1]);
-
-    if (*parv[2] == '-')
-    {
-      if (!del_silence(sptr, parv[2] + 1))
-       sendto_serv_butone(cptr, ":%s SILENCE * %s", parv[0], parv[2]);
-    }
-    else
-    {
-      add_silence(sptr, parv[2]);
-      if (acptr && IsServer(acptr->from))
-      {
-       if (Protocol(acptr->from) < 10)
-         sendto_one(acptr, ":%s SILENCE %s %s", parv[0], acptr->name, parv[2]);
-       else if (IsServer(acptr))
-         sendto_one(acptr, ":%s SILENCE %s %s",
-             parv[0], NumServ(acptr), parv[2]);
-       else
-         sendto_one(acptr, ":%s SILENCE %s%s %s",
-             parv[0], NumNick(acptr), parv[2]);
-      }
-    }
-  }
-  return 0;
-}
index cd4913271f3f0420a021c150698804434e7e6f45..9920407777df4973c2ad95ac5c083c2614653ed8 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdio.h>
-#include "h.h"
-#include "struct.h"
-#include "s_bsd.h"
-#include "s_serv.h"
 #include "send.h"
-#include "s_misc.h"
-#include "common.h"
-#include "match.h"
-#include "s_bsd.h"
-#include "list.h"
-#include "ircd.h"
 #include "channel.h"
-#include "bsd.h"
 #include "class.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
+#include "msg.h"
+#include "numnicks.h"
+#include "s_bsd.h"
+#include "s_debug.h"
+#include "s_misc.h"
 #include "s_user.h"
 #include "sprintf_irc.h"
+#include "struct.h"
+#include "sys.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
 
-RCSTAG_CC("$Id$");
 
 char sendbuf[2048];
 static int sentalong[MAXCONNECTIONS];
 static int sentalong_marker;
-struct SLink *opsarray[32];    /* don't use highest bit unless you change
-                                  atoi to strtoul in sendto_op_mask() */
+struct SLink *opsarray[32];     /* don't use highest bit unless you change
+                                   atoi to strtoul in sendto_op_mask() */
 #ifdef GODMODE
 char sendbuf2[2048];
 int sdbflag;
@@ -66,7 +69,7 @@ int sdbflag;
  * like Persons and yet unknown connections...
  */
 
-static void dead_link(aClient *to, char *notice)
+static void dead_link(struct Client *to, char *notice)
 {
   to->flags |= FLAGS_DEADSOCKET;
   /*
@@ -77,14 +80,20 @@ static void dead_link(aClient *to, char *notice)
   DBufClear(&to->sendQ);
 
   /* Keep a copy of the last comment, for later use... */
-  strncpy(LastDeadComment(to), notice, sizeof(LastDeadComment(to)));
-  LastDeadComment(to)[sizeof(LastDeadComment(to)) - 1] = 0;
+  ircd_strncpy(LastDeadComment(to), notice, sizeof(LastDeadComment(to) - 1));
+  LastDeadComment(to)[sizeof(LastDeadComment(to)) - 1] = '\0';
 
   if (!IsUser(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING))
     sendto_ops("%s for %s", LastDeadComment(to), to->name);
   Debug((DEBUG_ERROR, LastDeadComment(to)));
 }
 
+static int can_send(struct Client* to)
+{
+  assert(0 != to);
+  return (IsDead(to) || IsMe(to) || -1 == to->fd) ? 0 : 1;
+}
+
 /*
  * flush_connections
  *
@@ -95,19 +104,35 @@ static void dead_link(aClient *to, char *notice)
  * client and try to send it. if we cant send it, it goes into the sendQ
  * -avalon
  */
-void flush_connections(int fd)
+void flush_connections(struct Client* cptr)
 {
-  Reg1 int i;
-  Reg2 aClient *cptr;
+  if (cptr) {
+    send_queued(cptr);
+  }
+  else {
+    int i;
+    for (i = HighestFd; i >= 0; i--) {
+      if ((cptr = LocalClientArray[i]))
+        send_queued(cptr);
+    }
+  }
+}
 
-  if (fd == me.fd)
-  {
-    for (i = highest_fd; i >= 0; i--)
-      if ((cptr = loc_clients[i]) && DBufLength(&cptr->sendQ) > 0)
-       send_queued(cptr);
+/*
+ * flush_sendq_except - run through local client array and flush
+ * the sendq for each client, if the address of the client sendq
+ * is the same as the one specified, it is skipped. This is used
+ * by dbuf_put to try to get some more memory before bailing and
+ * causing the client to be disconnected.
+ */
+void flush_sendq_except(const struct DBuf* one)
+{
+  int i;
+  struct Client* cptr;
+  for (i = HighestFd; i >= 0; i--) {
+    if ( (cptr = LocalClientArray[i]) && one != &cptr->sendQ)
+      send_queued(cptr);
   }
-  else if (fd >= 0 && (cptr = loc_clients[fd]) && DBufLength(&cptr->sendQ) > 0)
-    send_queued(cptr);
 }
 
 /*
@@ -117,63 +142,36 @@ void flush_connections(int fd)
  * when there is a chance that some output would be possible. This
  * attempts to empty the send queue as far as possible...
  */
-void send_queued(aClient *to)
+void send_queued(struct Client *to)
 {
-#ifndef pyr
-  if (to->flags & FLAGS_BLOCKED)
-    return;                    /* Don't bother */
-#endif
-  /*
-   * Once socket is marked dead, we cannot start writing to it,
-   * even if the error is removed...
-   */
-  if (IsDead(to))
-  {
-    /*
-     * Actually, we should *NEVER* get here--something is
-     * not working correct if send_queued is called for a
-     * dead socket... --msa
-     *
-     * But we DO get here since flush_connections() is called
-     * from the main loop when a server still had remaining data
-     * in its buffer (not ending on a new-line).
-     * I rather leave the test here then move it to the main loop
-     * though: It wouldn't save cpu and it might introduce a bug :/.
-     * --Run
-     */
-    return;
-  }
-  while (DBufLength(&to->sendQ) > 0)
-  {
-    const char *msg;
-    size_t len, rlen;
-    int tmp;
+  assert(0 != to);
+  assert(0 != to->local);
 
-    msg = dbuf_map(&to->sendQ, &len);
-    /* Returns always len > 0 */
-    if ((tmp = deliver_it(to, msg, len)) < 0)
-    {
-      dead_link(to, "Write error, closing link");
-      return;
+  if (IsBlocked(to) || !can_send(to))
+    return;                     /* Don't bother */
+
+  while (DBufLength(&to->sendQ) > 0) {
+    size_t len;
+    const char* msg = dbuf_map(&to->sendQ, &len);
+
+    if ((len = deliver_it(to, msg, len))) {
+      dbuf_delete(&to->sendQ, len);
+      to->lastsq = DBufLength(&to->sendQ) / 1024;
+      if (IsBlocked(to))
+        break;
     }
-    rlen = tmp;
-    dbuf_delete(&to->sendQ, rlen);
-    to->lastsq = DBufLength(&to->sendQ) / 1024;
-    if (rlen < len)
-    {
-      to->flags |= FLAGS_BLOCKED;      /* Wait till select() says
-                                          we can write again */
+    else {
+      if (IsDead(to))
+        dead_link(to, "Write error, closing link");
       break;
     }
   }
-
-  return;
 }
 
 /*
  *  send message to single client
  */
-void sendto_one(aClient *to, char *pattern, ...)
+void sendto_one(struct Client *to, const char* pattern, ...)
 {
   va_list vl;
   va_start(vl, pattern);
@@ -181,101 +179,87 @@ void sendto_one(aClient *to, char *pattern, ...)
   va_end(vl);
 }
 
-void vsendto_one(aClient *to, char *pattern, va_list vl)
+
+void vsendto_one(struct Client *to, const char* pattern, va_list vl)
 {
   vsprintf_irc(sendbuf, pattern, vl);
   sendbufto_one(to);
 }
 
-void sendbufto_one(aClient *to)
+#ifdef GODMODE
+static void send_to_god(struct Client* to, const char* buf)
 {
-  int len;
+  if (!sdbflag && !IsUser(to)) {
+    char sbuf2[BUFSIZE + 1];
+    size_t len = strlen(buf) - 2;   /* Remove "\r\n" */
 
-  Debug((DEBUG_SEND, "Sending [%s] to %s", sendbuf, to->name));
+    sdbflag = 1;
+    len = IRCD_MIN(len, BUFSIZE);
+    ircd_strncpy(sbuf2, buf, len);
+    sbuf2[len] = '\0';
 
-  if (to->from)
-    to = to->from;
-  if (IsDead(to))
-    return;                    /* This socket has already
-                                  been marked as dead */
-  if (to->fd < 0)
-  {
-    /* This is normal when 'to' was being closed (via exit_client
-     *  and close_connection) --Run
-     * Print the debug message anyway...
-     */
-    Debug((DEBUG_ERROR, "Local socket %s with negative fd %d... AARGH!",
-       to->name, to->fd));
-    return;
+    if (len > 402) {
+      char c = sbuf2[200];
+      sbuf2[200] = '\0';
+      sendto_ops("SND:%-8.8s(%.4d): \"%s...%s\"",
+                 to->name, len, sbuf2, &sbuf2[len - 200]);
+    }
+    else
+      sendto_ops("SND:%-8.8s(%.4d): \"%s\"", to->name, len, sbuf2);
+    sdbflag = 0;
   }
+}
+#endif /* GODMODE */
 
-  len = strlen(sendbuf);
-  if (sendbuf[len - 1] != '\n')
-  {
-    if (len > 510)
-      len = 510;
-    sendbuf[len++] = '\r';
-    sendbuf[len++] = '\n';
-    sendbuf[len] = '\0';
-  }
+void send_buffer(struct Client* to, char* buf)
+{
+  size_t len;
+  assert(0 != to);
+  assert(0 != buf);
 
-  if (IsMe(to))
-  {
-    char tmp_sendbuf[sizeof(sendbuf)];
+  if (to->from)
+    to = to->from;
 
-    strcpy(tmp_sendbuf, sendbuf);
-    sendto_ops("Trying to send [%s] to myself!", tmp_sendbuf);
+  if (!can_send(to))
+    /*
+     * This socket has already been marked as dead
+     */
     return;
-  }
 
-  if (DBufLength(&to->sendQ) > get_sendq(to))
-  {
+  if (DBufLength(&to->sendQ) > get_sendq(to)) {
     if (IsServer(to))
-      sendto_ops("Max SendQ limit exceeded for %s: "
-         SIZE_T_FMT " > " SIZE_T_FMT, to->name,
-         DBufLength(&to->sendQ), get_sendq(to));
+      sendto_ops("Max SendQ limit exceeded for %s: " SIZE_T_FMT " > " SIZE_T_FMT,
+                 to->name, DBufLength(&to->sendQ), get_sendq(to));
     dead_link(to, "Max sendQ exceeded");
     return;
   }
 
-  else if (!dbuf_put(&to->sendQ, sendbuf, len))
-  {
-    dead_link(to, "Buffer allocation error");
-    return;
+  Debug((DEBUG_SEND, "Sending [%s] to %s", buf, to->name));
+
+  len = strlen(buf);
+  if (buf[len - 1] != '\n') {
+    if (len > 510)
+      len = 510;
+    buf[len++] = '\r';
+    buf[len++] = '\n';
+    buf[len] = '\0';
   }
-#ifdef GODMODE
 
-  if (!sdbflag && !IsUser(to))
-  {
-    size_t len = strlen(sendbuf) - 2;  /* Remove "\r\n" */
-    sdbflag = 1;
-    strncpy(sendbuf2, sendbuf, len);
-    sendbuf2[len] = '\0';
-    if (len > 402)
-    {
-      char c = sendbuf2[200];
-      sendbuf2[200] = 0;
-      sendto_ops("SND:%-8.8s(%.4d): \"%s...%s\"",
-         to->name, len, sendbuf2, &sendbuf2[len - 200]);
-      sendbuf2[200] = c;
-    }
-    else
-      sendto_ops("SND:%-8.8s(%.4d): \"%s\"", to->name, len, sendbuf2);
-    strcpy(sendbuf, sendbuf2);
-    strcat(sendbuf, "\r\n");
-    sdbflag = 0;
+  if (0 == dbuf_put(&to->sendQ, buf, len)) {
+    dead_link(to, "Buffer allocation error");
+    return;
   }
 
+#ifdef GODMODE
+  send_to_god(to, buf);
 #endif /* GODMODE */
   /*
    * Update statistics. The following is slightly incorrect
    * because it counts messages even if queued, but bytes
    * only really sent. Queued bytes get updated in SendQueued.
    */
-  to->sendM += 1;
-  me.sendM += 1;
-  if (to->acpt != &me)
-    to->acpt->sendM += 1;
+  ++to->sendM;
+  ++me.sendM;
   /*
    * This little bit is to stop the sendQ from growing too large when
    * there is no need for it to. Thus we call send_queued() every time
@@ -288,15 +272,20 @@ void sendbufto_one(aClient *to)
     send_queued(to);
 }
 
-static void vsendto_prefix_one(register aClient *to, register aClient *from,
-    char *pattern, va_list vl)
+void sendbufto_one(struct Client* to)
+{
+  send_buffer(to, sendbuf);
+}
+
+static void vsendto_prefix_one(struct Client *to, struct Client *from,
+    const char* pattern, va_list vl)
 {
   if (to && from && MyUser(to) && IsUser(from))
   {
     static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
     char *par;
     int flag = 0;
-    Reg3 anUser *user = from->user;
+    struct User *user = from->user;
 
     par = va_arg(vl, char *);
     strcpy(sender, from->name);
@@ -304,14 +293,14 @@ static void vsendto_prefix_one(register aClient *to, register aClient *from,
     {
       if (*user->username)
       {
-       strcat(sender, "!");
-       strcat(sender, user->username);
+        strcat(sender, "!");
+        strcat(sender, user->username);
       }
       if (*user->host && !MyConnect(from))
       {
-       strcat(sender, "@");
-       strcat(sender, user->host);
-       flag = 1;
+        strcat(sender, "@");
+        strcat(sender, user->host);
+        flag = 1;
       }
     }
     /*
@@ -321,10 +310,7 @@ static void vsendto_prefix_one(register aClient *to, register aClient *from,
     if (!flag && MyConnect(from) && *user->host)
     {
       strcat(sender, "@");
-      if (IsUnixSocket(from))
-       strcat(sender, user->host);
-      else
-       strcat(sender, from->sockhost);
+      strcat(sender, from->sockhost);
     }
     *sendbuf = ':';
     strcpy(&sendbuf[1], sender);
@@ -336,94 +322,161 @@ static void vsendto_prefix_one(register aClient *to, register aClient *from,
   sendbufto_one(to);
 }
 
-void sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr,
-    char *pattern, ...)
+void sendto_channel_butone(struct Client *one, struct Client *from, struct Channel *chptr,
+    const char* pattern, ...)
 {
   va_list vl;
-  Reg1 Link *lp;
-  Reg2 aClient *acptr;
-  Reg3 int i;
+  struct Membership* member;
+  struct Client *acptr;
+  int i;
 
   va_start(vl, pattern);
 
   ++sentalong_marker;
-  for (lp = chptr->members; lp; lp = lp->next)
+  for (member = chptr->members; member; member = member->next_member)
   {
-    acptr = lp->value.cptr;
-    if (acptr->from == one ||  /* ...was the one I should skip */
-       (lp->flags & CHFL_ZOMBIE) || IsDeaf(acptr))
+    acptr = member->user;
+    /* ...was the one I should skip */
+    if (acptr->from == one || IsZombie(member) || IsDeaf(acptr))
       continue;
-    if (MyConnect(acptr))      /* (It is always a client) */
+    if (MyConnect(acptr))       /* (It is always a client) */
       vsendto_prefix_one(acptr, from, pattern, vl);
-    else if (sentalong[(i = acptr->from->fd)] != sentalong_marker)
+    else if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
     {
       sentalong[i] = sentalong_marker;
-      /* Don't send channel messages to links that are still eating
-         the net.burst: -- Run 2/1/1997 */
+      /*
+       * Don't send channel messages to links that are still eating
+       * the net.burst: -- Run 2/1/1997
+       */
       if (!IsBurstOrBurstAck(acptr->from))
-       vsendto_prefix_one(acptr, from, pattern, vl);
+        vsendto_prefix_one(acptr, from, pattern, vl);
     }
   }
   va_end(vl);
-  return;
 }
 
-void sendto_lchanops_butone(aClient *one, aClient *from, aChannel *chptr,
-    char *pattern, ...)
+
+void sendmsgto_channel_butone(struct Client *one, struct Client *from,
+                              struct Channel *chptr, const char *sender,
+                              const char *cmd, const char *chname, const char *msg)
+{
+ /*
+  * Sends a PRIVMSG/NOTICE to all members on a channel but 'one', translating
+  * TOKENS to full messages when sent to local clients. --Gte (12/12/99)
+  */
+  struct Membership* member;
+  struct Client *acptr;
+  char userbuf[2048];
+  char servbuf[2048];
+  int i;
+  int flag=-1;
+
+  /* 
+   * Precalculate the buffers we sent to the clients instead of doing an
+   * expensive sprintf() per member that we send to.  We still have to
+   * use strcpy() which is evil.
+   */
+  if (IsServer(from)) {
+    sprintf(userbuf,":%s %s %s :%s",
+        from->name, 
+        ((cmd[0] == 'P') ? MSG_PRIVATE : MSG_NOTICE),
+        chname, msg);
+    sprintf(servbuf,"%s " TOK_PRIVATE " %s :%s",
+        NumServ(from), chname, msg);
+  } else {
+    sprintf(userbuf,":%s!%s@%s %s %s :%s",
+      from->name, from->username, from->user->host,
+      ((cmd[0] == 'P') ? MSG_PRIVATE : MSG_NOTICE),
+      chname, msg);
+    sprintf(servbuf,"%s%s %s %s :%s",
+      NumNick(from), 
+       ((cmd[0] == 'P') ? TOK_PRIVATE : TOK_NOTICE),
+     chname, msg);
+  }
+
+  ++sentalong_marker;
+  for (member = chptr->members; member; member = member->next_member)
+  {
+    acptr = member->user;
+    /* ...was the one I should skip */
+    if (acptr->from == one || IsZombie(member) || IsDeaf(acptr))
+      continue;
+    if (MyConnect(acptr)) {      /* (It is always a client) */
+        if (flag!=0)
+          strcpy(sendbuf,userbuf);
+        flag=0;
+        sendbufto_one(acptr);
+    }
+    else if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
+    {
+      sentalong[i] = sentalong_marker;
+      if (!IsBurstOrBurstAck(acptr->from)) {
+        if (flag != 1)
+          strcpy(sendbuf,servbuf);
+        flag = 1;
+        sendbufto_one(acptr);
+  }
+    } /* of if MyConnect() */
+  } /* of for(members) */
+}
+
+void sendto_lchanops_butone(struct Client *one, struct Client *from, struct Channel *chptr,
+    const char* pattern, ...)
 {
   va_list vl;
-  Reg1 Link *lp;
-  Reg2 aClient *acptr;
+  struct Membership* member;
+  struct Client *acptr;
 
   va_start(vl, pattern);
 
-  for (lp = chptr->members; lp; lp = lp->next)
+  for (member = chptr->members; member; member = member->next_member)
   {
-    acptr = lp->value.cptr;
-    if (acptr == one ||                /* ...was the one I should skip */
-       !(lp->flags & CHFL_CHANOP) ||   /* Skip non chanops */
-       (lp->flags & CHFL_ZOMBIE) || IsDeaf(acptr))
+    acptr = member->user;
+    /* ...was the one I should skip */
+    if (acptr == one || !IsChanOp(member) || IsZombie(member) || IsDeaf(acptr))
       continue;
-    if (MyConnect(acptr))      /* (It is always a client) */
+    if (MyConnect(acptr))       /* (It is always a client) */
       vsendto_prefix_one(acptr, from, pattern, vl);
   }
   va_end(vl);
   return;
 }
 
-void sendto_chanopsserv_butone(aClient *one, aClient *from, aChannel *chptr,
-    char *pattern, ...)
+void sendto_chanopsserv_butone(struct Client *one, struct Client *from, struct Channel *chptr,
+    const char* pattern, ...)
 {
   va_list vl;
-  Reg1 Link *lp;
-  Reg2 aClient *acptr;
-  Reg3 int i;
+  struct Membership* member;
+  struct Client *acptr;
+  int i;
 #ifndef NO_PROTOCOL9
-  char target[128];
-  char *source, *tp, *msg;
+  char  target[128];
+  char* source;
+  char* tp;
+  char* msg;
 #endif
 
   va_start(vl, pattern);
 
   ++sentalong_marker;
-  for (lp = chptr->members; lp; lp = lp->next)
+  for (member = chptr->members; member; member = member->next_member)
   {
-    acptr = lp->value.cptr;
-    if (acptr->from == acptr ||        /* Skip local clients */
+    acptr = member->user;
+    if (acptr->from == acptr || /* Skip local clients */
 #ifndef NO_PROTOCOL9
-       Protocol(acptr->from) < 10 ||   /* Skip P09 links */
+        Protocol(acptr->from) < 10 ||   /* Skip P09 links */
 #endif
-       acptr->from == one ||   /* ...was the one I should skip */
-       !(lp->flags & CHFL_CHANOP) ||   /* Skip non chanops */
-       (lp->flags & CHFL_ZOMBIE) || IsDeaf(acptr))
+        acptr->from == one ||   /* ...was the one I should skip */
+        !IsChanOp(member) ||   /* Skip non chanops */
+        IsZombie(member) || IsDeaf(acptr))
       continue;
-    if (sentalong[(i = acptr->from->fd)] != sentalong_marker)
+    if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
     {
       sentalong[i] = sentalong_marker;
       /* Don't send channel messages to links that are
          still eating the net.burst: -- Run 2/1/1997 */
       if (!IsBurstOrBurstAck(acptr->from))
-       vsendto_prefix_one(acptr, from, pattern, vl);
+        vsendto_prefix_one(acptr, from, pattern, vl);
     }
   }
 
@@ -431,52 +484,52 @@ void sendto_chanopsserv_butone(aClient *one, aClient *from, aChannel *chptr,
   /* Send message to all 2.9 servers */
   /* This is a hack, because it assumes that we know how `vl' is build up */
   source = va_arg(vl, char *);
-  tp = va_arg(vl, char *);     /* Channel */
+  tp = va_arg(vl, char *);      /* Channel */
   msg = va_arg(vl, char *);
-  for (lp = chptr->members; lp; lp = lp->next)
+  for (member = chptr->members; member; member = member->next_member)
   {
-    acptr = lp->value.cptr;
-    if (acptr->from == acptr ||        /* Skip local clients */
-       Protocol(acptr->from) > 9 ||    /* Skip P10 servers */
-       acptr->from == one ||   /* ...was the one I should skip */
-       !(lp->flags & CHFL_CHANOP) ||   /* Skip non chanops */
-       (lp->flags & CHFL_ZOMBIE) || IsDeaf(acptr))
+    acptr = member->user;
+    if (acptr->from == acptr || /* Skip local clients */
+        Protocol(acptr->from) > 9 ||    /* Skip P10 servers */
+        acptr->from == one ||   /* ...was the one I should skip */
+        !IsChanOp(member) ||   /* Skip non chanops */
+        IsZombie(member) || IsDeaf(acptr))
       continue;
-    if (sentalong[(i = acptr->from->fd)] != sentalong_marker)
+    if (-1 < (i = acptr->from->fd) && sentalong[i] != sentalong_marker)
     {
       sentalong[i] = sentalong_marker;
       /* Don't send channel messages to links that are
          still eating the net.burst: -- Run 2/1/1997 */
       if (!IsBurstOrBurstAck(acptr->from))
       {
-       Link *lp2;
-       aClient *acptr2;
-       tp = target;
-       *tp = 0;
-       /* Find all chanops in this direction: */
-       for (lp2 = chptr->members; lp2; lp2 = lp2->next)
-       {
-         acptr2 = lp2->value.cptr;
-         if (acptr2->from == acptr->from && acptr2->from != one &&
-             (lp2->flags & CHFL_CHANOP) && !(lp2->flags & CHFL_ZOMBIE) &&
-             !IsDeaf(acptr2))
-         {
-           int len = strlen(acptr2->name);
-           if (tp + len + 2 > target + sizeof(target))
-           {
-             sendto_prefix_one(acptr, from,
-                 ":%s NOTICE %s :%s", source, target, msg);
-             tp = target;
-             *tp = 0;
-           }
-           if (*target)
-             strcpy(tp++, ",");
-           strcpy(tp, acptr2->name);
-           tp += len;
-         }
-       }
-       sendto_prefix_one(acptr, from,
-           ":%s NOTICE %s :%s", source, target, msg);
+        struct Membership* other_member;
+        struct Client* acptr2;
+        tp = target;
+        *tp = 0;
+        /* Find all chanops in this direction: */
+        for (other_member = chptr->members; other_member; other_member = other_member->next_member)
+        {
+          acptr2 = other_member->user;
+          if (acptr2->from == acptr->from && acptr2->from != one &&
+              IsChanOp(other_member) && !IsZombie(other_member) &&
+              !IsDeaf(acptr2))
+          {
+            int len = strlen(acptr2->name);
+            if (tp + len + 2 > target + sizeof(target))
+            {
+              sendto_prefix_one(acptr, from,
+                  ":%s NOTICE %s :%s", source, target, msg);
+              tp = target;
+              *tp = 0;
+            }
+            if (*target)
+              strcpy(tp++, ",");
+            strcpy(tp, acptr2->name);
+            tp += len;
+          }
+        }
+        sendto_prefix_one(acptr, from,
+            ":%s NOTICE %s :%s", source, target, msg);
       }
     }
   }
@@ -491,10 +544,10 @@ void sendto_chanopsserv_butone(aClient *one, aClient *from, aChannel *chptr,
  *
  * Send a message to all connected servers except the client 'one'.
  */
-void sendto_serv_butone(aClient *one, char *pattern, ...)
+void sendto_serv_butone(struct Client *one, const char* pattern, ...)
 {
   va_list vl;
-  Reg1 Dlink *lp;
+  struct DLink *lp;
 
   va_start(vl, pattern);
   vsprintf_irc(sendbuf, pattern, vl);
@@ -515,9 +568,9 @@ void sendto_serv_butone(aClient *one, char *pattern, ...)
  * Send prepared sendbuf to all connected servers except the client 'one'
  *  -Ghostwolf 18-May-97
  */
-void sendbufto_serv_butone(aClient *one)
+void sendbufto_serv_butone(struct Client *one)
 {
-  Reg1 Dlink *lp;
+  struct DLink *lp;
 
   for (lp = me.serv->down; lp; lp = lp->next)
   {
@@ -527,35 +580,44 @@ void sendbufto_serv_butone(aClient *one)
   }
 }
 
+
 /*
  * sendto_common_channels()
  *
  * Sends a message to all people (inclusing `acptr') on local server
  * who are in same channel with client `acptr'.
  */
-void sendto_common_channels(aClient *acptr, char *pattern, ...)
+void sendto_common_channels(struct Client *acptr, const char* pattern, ...)
 {
   va_list vl;
-  Reg1 Link *chan;
-  Reg2 Link *member;
+  struct Membership* chan;
+  struct Membership* member;
+
+  assert(0 != acptr);
+  assert(0 != acptr->from);
+  assert(0 != pattern);
 
   va_start(vl, pattern);
 
   ++sentalong_marker;
-  if (acptr->fd >= 0)
-    sentalong[acptr->fd] = sentalong_marker;
-  /* loop through acptr's channels, and the members on their channels */
-  if (acptr->user)
-    for (chan = acptr->user->channel; chan; chan = chan->next)
-      for (member = chan->value.chptr->members; member; member = member->next)
-      {
-       Reg3 aClient *cptr = member->value.cptr;
-       if (MyConnect(cptr) && sentalong[cptr->fd] != sentalong_marker)
-       {
-         sentalong[cptr->fd] = sentalong_marker;
-         vsendto_prefix_one(cptr, acptr, pattern, vl);
-       }
+  if (-1 < acptr->from->fd)
+    sentalong[acptr->from->fd] = sentalong_marker;
+  /*
+   * loop through acptr's channels, and the members on their channels
+   */
+  if (acptr->user) {
+    for (chan = acptr->user->channel; chan; chan = chan->next_channel) {
+      for (member = chan->channel->members; member; member = member->next_member) {
+        struct Client *cptr = member->user;
+        int    i;
+        if (MyConnect(cptr) && 
+            -1 < (i = cptr->fd) && sentalong[i] != sentalong_marker) {
+          sentalong[i] = sentalong_marker;
+          vsendto_prefix_one(cptr, acptr, pattern, vl);
+        }
       }
+    }
+  }
   if (MyConnect(acptr))
     vsendto_prefix_one(acptr, acptr, pattern, vl);
   va_end(vl);
@@ -568,15 +630,18 @@ void sendto_common_channels(aClient *acptr, char *pattern, ...)
  * Send a message to all members of a channel that
  * are connected to this server.
  */
-void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...)
+void sendto_channel_butserv(struct Channel *chptr, struct Client *from, const char* pattern, ...)
 {
   va_list vl;
-  Reg1 Link *lp;
-  Reg2 aClient *acptr;
+  struct Membership* member;
+  struct Client *acptr;
+  
+  va_start(vl, pattern);
 
-  for (va_start(vl, pattern), lp = chptr->members; lp; lp = lp->next)
-    if (MyConnect(acptr = lp->value.cptr) && !(lp->flags & CHFL_ZOMBIE))
+  for (member = chptr->members; member; member = member->next_member) {
+    if (MyConnect(acptr = member->user) && !IsZombie(member))
       vsendto_prefix_one(acptr, from, pattern, vl);
+  }
   va_end(vl);
   return;
 }
@@ -588,7 +653,7 @@ void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...)
  *  addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
  */
 
-static int match_it(aClient *one, char *mask, int what)
+static int match_it(struct Client *one, const char *mask, int what)
 {
   switch (what)
   {
@@ -606,30 +671,30 @@ static int match_it(aClient *one, char *mask, int what)
  * Send to all clients which match the mask in a way defined on 'what';
  * either by user hostname or user servername.
  */
-void sendto_match_butone(aClient *one, aClient *from,
-    char *mask, int what, char *pattern, ...)
+void sendto_match_butone(struct Client *one, struct Client *from,
+    const char *mask, int what, const char* pattern, ...)
 {
   va_list vl;
-  Reg1 int i;
-  Reg2 aClient *cptr, *acptr;
+  int i;
+  struct Client *cptr, *acptr;
 
   va_start(vl, pattern);
-  for (i = 0; i <= highest_fd; i++)
+  for (i = 0; i <= HighestFd; i++)
   {
-    if (!(cptr = loc_clients[i]))
-      continue;                        /* that clients are not mine */
-    if (cptr == one)           /* must skip the origin !! */
+    if (!(cptr = LocalClientArray[i]))
+      continue;                 /* that clients are not mine */
+    if (cptr == one)            /* must skip the origin !! */
       continue;
     if (IsServer(cptr))
     {
-      for (acptr = client; acptr; acptr = acptr->next)
-       if (IsUser(acptr) && match_it(acptr, mask, what) && acptr->from == cptr)
-         break;
+      for (acptr = GlobalClientList; acptr; acptr = acptr->next)
+        if (IsUser(acptr) && match_it(acptr, mask, what) && acptr->from == cptr)
+          break;
       /* a person on that server matches the mask, so we
        *  send *one* msg to that server ...
        */
       if (acptr == NULL)
-       continue;
+        continue;
       /* ... but only if there *IS* a matching person */
     }
     /* my client, does he match ? */
@@ -647,25 +712,27 @@ void sendto_match_butone(aClient *one, aClient *from,
  *
  * Send to *local* ops but one.
  */
-void sendto_lops_butone(aClient *one, char *pattern, ...)
+void sendto_lops_butone(struct Client* one, const char* pattern, ...)
 {
-  va_list vl;
-  Reg1 aClient *cptr;
-  aClient **cptrp;
-  int i;
-  char nbuf[1024];
+  va_list         vl;
+  struct Client*  cptr;
+  struct Client** clients = me.serv->client_list;
+  int             i;
+  char            nbuf[1024];
+
+  assert(0 != clients);
 
   sprintf_irc(nbuf, ":%s NOTICE %%s :*** Notice -- ", me.name);
   va_start(vl, pattern);
   vsprintf_irc(nbuf + strlen(nbuf), pattern, vl);
   va_end(vl);
-  for (cptrp = me.serv->client_list, i = 0; i <= me.serv->nn_mask; ++cptrp, ++i)
-    if ((cptr = *cptrp) && cptr != one && SendServNotice(cptr))
-    {
+
+  for (i = 0; i <= me.serv->nn_mask; ++i) {
+    if ((cptr = clients[i]) && cptr != one && SendServNotice(cptr)) {
       sprintf_irc(sendbuf, nbuf, cptr->name);
       sendbufto_one(cptr);
     }
-  return;
+  }
 }
 
 /*
@@ -675,12 +742,12 @@ void sendto_lops_butone(aClient *one, char *pattern, ...)
  * Don't try to send to more than one list! That is not supported.
  * Xorath 5/1/97
  */
-void vsendto_op_mask(register snomask_t mask, const char *pattern, va_list vl)
+void vsendto_op_mask(unsigned int mask, const char *pattern, va_list vl)
 {
   static char fmt[1024];
   char *fmt_target;
-  register int i = 0;          /* so that 1 points to opsarray[0] */
-  Link *opslist;
+  int i = 0;            /* so that 1 points to opsarray[0] */
+  struct SLink *opslist;
 
   while ((mask >>= 1))
     i++;
@@ -705,10 +772,10 @@ void vsendto_op_mask(register snomask_t mask, const char *pattern, va_list vl)
  * Send a prepared sendbuf to the list indicated by the bitmask field.
  * Ghostwolf 16-May-97
  */
-void sendbufto_op_mask(snomask_t mask)
+void sendbufto_op_mask(unsigned int mask)
 {
-  register int i = 0;          /* so that 1 points to opsarray[0] */
-  Link *opslist;
+  int i = 0;            /* so that 1 points to opsarray[0] */
+  struct SLink *opslist;
   while ((mask >>= 1))
     i++;
   if (!(opslist = opsarray[i]))
@@ -729,27 +796,25 @@ void sendbufto_op_mask(snomask_t mask)
  */
 void vsendto_ops(const char *pattern, va_list vl)
 {
-  Reg1 aClient *cptr;
-  Reg2 int i;
+  struct Client *cptr;
+  int i;
   char fmt[1024];
   char *fmt_target;
 
   fmt_target = sprintf_irc(fmt, ":%s NOTICE ", me.name);
 
-  for (i = 0; i <= highest_fd; i++)
-    if ((cptr = loc_clients[i]) && !IsServer(cptr) && !IsMe(cptr) &&
-       SendServNotice(cptr))
+  for (i = 0; i <= HighestFd; i++)
+    if ((cptr = LocalClientArray[i]) && !IsServer(cptr) &&
+        SendServNotice(cptr))
     {
       strcpy(fmt_target, cptr->name);
       strcat(fmt_target, " :*** Notice -- ");
       strcat(fmt_target, pattern);
       vsendto_one(cptr, fmt, vl);
     }
-
-  return;
 }
 
-void sendto_op_mask(snomask_t mask, const char *pattern, ...)
+void sendto_op_mask(unsigned int mask, const char *pattern, ...)
 {
   va_list vl;
   va_start(vl, pattern);
@@ -772,24 +837,23 @@ void sendto_ops(const char *pattern, ...)
  * one - client not to send message to
  * from- client which message is from *NEVER* NULL!!
  */
-void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...)
+void sendto_ops_butone(struct Client *one, struct Client *from, const char *pattern, ...)
 {
   va_list vl;
-  Reg1 int i;
-  Reg2 aClient *cptr;
+  int i;
+  struct Client *cptr;
 
   va_start(vl, pattern);
   ++sentalong_marker;
-  for (cptr = client; cptr; cptr = cptr->next)
+  for (cptr = GlobalClientList; cptr; cptr = cptr->next)
   {
-    /*if (!IsAnOper(cptr)) */
     if (!SendWallops(cptr))
       continue;
-    i = cptr->from->fd;                /* find connection oper is on */
-    if (sentalong[i] == sentalong_marker)      /* sent message along it already ? */
+    i = cptr->from->fd;         /* find connection oper is on */
+    if (i < 0 || sentalong[i] == sentalong_marker)       /* sent message along it already ? */
       continue;
     if (cptr->from == one)
-      continue;                        /* ...was the one I should skip */
+      continue;                 /* ...was the one I should skip */
     sentalong[i] = sentalong_marker;
     vsendto_prefix_one(cptr->from, from, pattern, vl);
   }
@@ -805,21 +869,21 @@ void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...)
  *
  * one - server not to send message to.
  */
-void sendto_g_serv_butone(aClient *one, char *pattern, ...)
+void sendto_g_serv_butone(struct Client *one, const char *pattern, ...)
 {
   va_list vl;
-  aClient *cptr;
+  struct Client *cptr;
   int i;
 
   va_start(vl, pattern);
   ++sentalong_marker;
   vsprintf_irc(sendbuf, pattern, vl);
-  for (cptr = client; cptr; cptr = cptr->next)
+  for (cptr = GlobalClientList; cptr; cptr = cptr->next)
   {
     if (!SendDebug(cptr))
       continue;
-    i = cptr->from->fd;                /* find connection user is on */
-    if (sentalong[i] == sentalong_marker)      /* sent message along it already ? */
+    i = cptr->from->fd;         /* find connection user is on */
+    if (i < 0 || sentalong[i] == sentalong_marker)       /* sent message along it already ? */
       continue;
     if (MyConnect(cptr))
       continue;
@@ -842,7 +906,7 @@ void sendto_g_serv_butone(aClient *one, char *pattern, ...)
  * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
  * -avalon
  */
-void sendto_prefix_one(Reg1 aClient *to, Reg2 aClient *from, char *pattern, ...)
+void sendto_prefix_one(struct Client *to, struct Client *from, const char *pattern, ...)
 {
   va_list vl;
   va_start(vl, pattern);
@@ -869,10 +933,10 @@ void sendto_realops(const char *pattern, ...)
 /*
  * Send message to all servers of protocol 'p' and lower.
  */
-void sendto_lowprot_butone(aClient *cptr, int p, char *pattern, ...)
+void sendto_lowprot_butone(struct Client *cptr, int p, const char *pattern, ...)
 {
   va_list vl;
-  Dlink *lp;
+  struct DLink *lp;
   va_start(vl, pattern);
   for (lp = me.serv->down; lp; lp = lp->next)
     if (lp->value.cptr != cptr && Protocol(lp->value.cptr) <= p)
@@ -883,10 +947,10 @@ void sendto_lowprot_butone(aClient *cptr, int p, char *pattern, ...)
 /*
  * Send message to all servers of protocol 'p' and higher.
  */
-void sendto_highprot_butone(aClient *cptr, int p, char *pattern, ...)
+void sendto_highprot_butone(struct Client *cptr, int p, const char *pattern, ...)
 {
   va_list vl;
-  Dlink *lp;
+  struct DLink *lp;
   va_start(vl, pattern);
   for (lp = me.serv->down; lp; lp = lp->next)
     if (lp->value.cptr != cptr && Protocol(lp->value.cptr) >= p)
index ab85492ca18c10d0322299a7334327b241ff0a17..59e5218d534fda98622153de302c35720cf6df70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * IRC - Internet Relay Chat, ircd/s_ping.c
+ * IRC - Internet Relay Chat, ircd/sprintf_irc.c
  *
  * (C) Copyright 1997
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
+#include "sprintf_irc.h"
 #include "sys.h"
 #include <stdio.h>
-#include "h.h"
-#include "sprintf_irc.h"
 
-RCSTAG_CC("$Id$");
 
 /* *INDENT-OFF* */
 
@@ -270,134 +269,133 @@ static char scratch_buffer[32];
  *
  * --Run
  */
-char *vsprintf_irc(register char *str,
-    register const char *format, register va_list vl)
+char *vsprintf_irc(char *str, const char *format, va_list vl)
 {
-  register char c;
+  char c;
 
   while ((c = *format++))
   {
     if (c == '%')
     {
-      c = *format++;           /* May never be '\0' ! */
+      c = *format++;            /* May never be '\0' ! */
       if (c == 'c')
       {
-       *str++ = (char)va_arg(vl, int);
-       continue;
+        *str++ = (char)va_arg(vl, int);
+        continue;
       }
       if (c == 's')
       {
-       register const char *p1 = va_arg(vl, const char *);
-       if ((*str = *p1))
-         while ((*++str = *++p1));
-       continue;
+        const char *p1 = va_arg(vl, const char *);
+        if ((*str = *p1))
+          while ((*++str = *++p1));
+        continue;
       }
-      if (c == 'l' && *format == 'u')  /* Prints time_t value in interval
-                                          [ 100000000 , 4294967295 ]
-                                          Actually prints like "%09lu" */
+      if (c == 'l' && *format == 'u')   /* Prints time_t value in interval
+                                           [ 100000000 , 4294967295 ]
+                                           Actually prints like "%09lu" */
       {
-       register unsigned long v1, v2;
-       register const char *ap;
-       ++format;
-       v1 = va_arg(vl, unsigned long);
-       if (v1 > 999999999L)
-       {
-         v2 = v1 / 1000000000;
-         v1 -= v2 * 1000000000;
-         *str++ = '0' + v2;
-       }
-       v2 = v1 / 1000000;
-       v1 -= v2 * 1000000;
-       ap = atoi_tab + (v2 << 2);
-       *str++ = *ap++;
-       *str++ = *ap++;
-       *str++ = *ap;
-       v2 = v1 / 1000;
-       v1 -= v2 * 1000;
-       ap = atoi_tab + (v2 << 2);
-       *str++ = *ap++;
-       *str++ = *ap++;
-       *str++ = *ap;
-       ap = atoi_tab + (v1 << 2);
-       *str++ = *ap++;
-       *str++ = *ap++;
-       *str++ = *ap;
-       continue;
+        unsigned long v1, v2;
+        const char *ap;
+        ++format;
+        v1 = va_arg(vl, unsigned long);
+        if (v1 > 999999999L)
+        {
+          v2 = v1 / 1000000000;
+          v1 -= v2 * 1000000000;
+          *str++ = '0' + v2;
+        }
+        v2 = v1 / 1000000;
+        v1 -= v2 * 1000000;
+        ap = atoi_tab + (v2 << 2);
+        *str++ = *ap++;
+        *str++ = *ap++;
+        *str++ = *ap;
+        v2 = v1 / 1000;
+        v1 -= v2 * 1000;
+        ap = atoi_tab + (v2 << 2);
+        *str++ = *ap++;
+        *str++ = *ap++;
+        *str++ = *ap;
+        ap = atoi_tab + (v1 << 2);
+        *str++ = *ap++;
+        *str++ = *ap++;
+        *str++ = *ap;
+        continue;
       }
-#if 0                          /* Not used */
-      if (c == 'N')            /* Prints "%03u" a numeric value in the
-                                  range [ 0, 999 ], padded with zero's */
+#if 0                           /* Not used */
+      if (c == 'N')             /* Prints "%03u" a numeric value in the
+                                   range [ 0, 999 ], padded with zero's */
       {
-       register unsigned int v1;
-       register const char *ap;
-       v1 = va_arg(vl, unsigned int);
-       ap = atoi_tab + (v1 << 2);
-       *str++ = *ap++;
-       *str++ = *ap++;
-       *str++ = *ap;
-       continue;
+        unsigned int v1;
+        const char *ap;
+        v1 = va_arg(vl, unsigned int);
+        ap = atoi_tab + (v1 << 2);
+        *str++ = *ap++;
+        *str++ = *ap++;
+        *str++ = *ap;
+        continue;
       }
 #endif
       if (c == 'd')
       {
-       register unsigned int v1, v2;
-       register const char *ap;
-       register char *s = &scratch_buffer[sizeof(scratch_buffer) - 2];
-       v1 = va_arg(vl, int);
-       if ((int)v1 <= 0)
-       {
-         if (v1 == 0)
-         {
-           *str++ = '0';
-           continue;
-         }
-         *str++ = '-';
-         v1 = -v1;
-       }
-       do
-       {
-         v2 = v1 / 1000;
-         ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2);
-         *s-- = *ap--;
-         *s-- = *ap--;
-         *s-- = *ap;
-       }
-       while ((v1 = v2) > 0);
-       while ('0' == *++s);
-       *str = *s;
-       while ((*++str = *++s));
-       continue;
+        unsigned int v1, v2;
+        const char *ap;
+        char *s = &scratch_buffer[sizeof(scratch_buffer) - 2];
+        v1 = va_arg(vl, int);
+        if ((int)v1 <= 0)
+        {
+          if (v1 == 0)
+          {
+            *str++ = '0';
+            continue;
+          }
+          *str++ = '-';
+          v1 = -v1;
+        }
+        do
+        {
+          v2 = v1 / 1000;
+          ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2);
+          *s-- = *ap--;
+          *s-- = *ap--;
+          *s-- = *ap;
+        }
+        while ((v1 = v2) > 0);
+        while ('0' == *++s);
+        *str = *s;
+        while ((*++str = *++s));
+        continue;
       }
       if (c == 'u')
       {
-       register unsigned int v1, v2;
-       register const char *ap;
-       register char *s = &scratch_buffer[sizeof(scratch_buffer) - 2];
-       v1 = va_arg(vl, unsigned int);
-       if (v1 == 0)
-       {
-         *str++ = '0';
-         continue;
-       }
-       do
-       {
-         v2 = v1 / 1000;
-         ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2);
-         *s-- = *ap--;
-         *s-- = *ap--;
-         *s-- = *ap;
-       }
-       while ((v1 = v2) > 0);
-       while ('0' == *++s);
-       *str = *s;
-       while ((*++str = *++s));
-       continue;
+        unsigned int v1, v2;
+        const char *ap;
+        char *s = &scratch_buffer[sizeof(scratch_buffer) - 2];
+        v1 = va_arg(vl, unsigned int);
+        if (v1 == 0)
+        {
+          *str++ = '0';
+          continue;
+        }
+        do
+        {
+          v2 = v1 / 1000;
+          ap = atoi_tab + 2 + ((v1 - 1000 * v2) << 2);
+          *s-- = *ap--;
+          *s-- = *ap--;
+          *s-- = *ap;
+        }
+        while ((v1 = v2) > 0);
+        while ('0' == *++s);
+        *str = *s;
+        while ((*++str = *++s));
+        continue;
       }
       if (c != '%')
       {
-       format -= 2;
-       str += vsprintf(str, format, vl);
-       break;
+        format -= 2;
+        str += vsprintf(str, format, vl);
+        break;
       }
     }
     *str++ = c;
@@ -406,10 +404,10 @@ char *vsprintf_irc(register char *str,
   return str;
 }
 
-char *sprintf_irc(register char *str, const char *format, ...)
+char *sprintf_irc(char *str, const char *format, ...)
 {
-  register va_list vl;
-  register char *ret;
+  va_list vl;
+  char *ret;
   va_start(vl, format);
   ret = vsprintf_irc(str, format, vl);
   va_end(vl);
index ebc17950ecf43c790432b756f49201ac662564d5..6f9821173a88e6f523d2f83840baa8c39019066c 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#ifdef _SEQUENT_
-#include <sys/timers.h>
-#include <stddef.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <stdarg.h>
-#include <signal.h>
-#include "h.h"
-#include "send.h"
+#include "support.h"
+#include "fileio.h"
 #include "ircd.h"
+#include "ircd_chattr.h"
 #include "s_bsd.h"
-#include "support.h"
+#include "s_debug.h"
+#include "send.h"
 #include "sprintf_irc.h"
-#include "common.h"
-#include "fileio.h"
-
-RCSTAG_CC("$Id$");
-
-#ifndef HAVE_STRTOKEN
-/*
- * strtoken.c
- *
- * Walk through a string of tokens, using a set of separators.
- * -argv 9/90
- */
-char *strtoken(char **save, char *str, char *fs)
-{
-  char *pos = *save;           /* keep last position across calls */
-  Reg1 char *tmp;
-
-  if (str)
-    pos = str;                 /* new string scan */
-
-  while (pos && *pos && strchr(fs, *pos) != NULL)
-    pos++;                     /* skip leading separators */
-
-  if (!pos || !*pos)
-    return (pos = *save = NULL);       /* string contains only sep's */
-
-  tmp = pos;                   /* now, keep position of the token */
-
-  while (*pos && strchr(fs, *pos) == NULL)
-    pos++;                     /* skip content of the token */
-
-  if (*pos)
-    *pos++ = '\0';             /* remove first sep after the token */
-  else
-    pos = NULL;                        /* end of string */
-
-  *save = pos;
-  return (tmp);
-}
-#endif /* !HAVE_STRTOKEN */
-
-#ifndef HAVE_STRERROR
-/*
- * strerror
- *
- * Returns an appropriate system error string to a given errno.
- * -argv 11/90
- */
-
-char *strerror(int err_no)
-{
-  static char buff[40];
-  char *errp;
-
-  errp = (err_no > sys_nerr ? (char *)NULL : sys_errlist[err_no]);
-
-  if (errp == (char *)NULL)
-  {
-    errp = buff;
-    sprintf_irc(errp, "Unknown Error %d", err_no);
-  }
-  return errp;
-}
-
-#endif /* !HAVE_STRERROR */
-
-/*
- * inetntoa --    Changed the parameter to NOT take a pointer.
- *                -Run 4/8/97
- * inetntoa --    Changed name to remove collision possibility and
- *                so behaviour is garanteed to take a pointer arg.
- *                -avalon 23/11/92
- * inet_ntoa --   Returned the dotted notation of a given
- *                internet number (some ULTRIX don't have this)
- *                -argv 11/90.
- * inet_ntoa --   Its broken on some Ultrix/Dynix too. -avalon
- */
-char *inetntoa(struct in_addr in)
-{
-  static char buf[16];
-  Reg1 unsigned char *s = (unsigned char *)&in.s_addr;
-  Reg2 unsigned char a, b, c, d;
-
-  a = *s++;
-  b = *s++;
-  c = *s++;
-  d = *s++;
-  sprintf_irc(buf, "%u.%u.%u.%u", a, b, c, d);
-
-  return buf;
-}
-
-#ifndef HAVE_INET_NETOF
-/*
- *    inet_netof --   return the net portion of an internet number
- *                    argv 11/90
- */
-int inet_netof(struct in_addr in)
-{
-  int addr = in.s_net;
-
-  if (addr & 0x80 == 0)
-    return ((int)in.s_net);
-
-  if (addr & 0x40 == 0)
-    return ((int)in.s_net * 256 + in.s_host);
-
-  return ((int)in.s_net * 256 + in.s_host * 256 + in.s_lh);
-}
-
-#endif /* !HAVE_INET_NETOF */
+#include "sys.h"
 
-#ifndef HAVE_GETTIMEOFDAY
-/* This is copied from ircu3.0.0 (with permission), not vica versa. */
-int gettimeofday(struct timeval *tv, void * /*UNUSED*/)
-{
-  register int ret;
-  static struct timespec tp;
-
-  if ((ret = getclock(TIMEOFDAY, &tp)))
-    return ret;
-  tv->tv_sec = (long)tp.tv_sec;
-  tv->tv_usec = (tp.tv_nsec + 500) / 1000;
-  return 0;
-}
-#endif /* !HAVE_GETTIMEOFDAY */
+#include <signal.h>   /* kill */
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
 
 #ifdef DEBUGMODE
 
@@ -178,11 +53,7 @@ void dumpcore(const char *pattern, ...)
   if (!lastd)
     lastd = now;
   else if (now - lastd < 60 && dumps > 2)
-#ifdef __cplusplus
-    s_die(0);
-#else
-    s_die();
-#endif
+    server_die("too many core dumps");
   if (now - lastd > 60)
   {
     lastd = now;
@@ -196,33 +67,29 @@ void dumpcore(const char *pattern, ...)
     kill(p, 3);
     kill(p, 9);
   }
-  write_pidfile();
   sprintf_irc(corename, "core.%d", p);
   rename("core", corename);
   Debug((DEBUG_FATAL, "Dumped core : core.%d", p));
   sendto_ops("Dumped core : core.%d", p);
   vdebug(DEBUG_FATAL, pattern, vl);
   vsendto_ops(pattern, vl);
-#ifdef __cplusplus
-  s_die(0);
-#else
-  s_die();
-#endif
-
   va_end(vl);
+
+  server_die("debug core dump");
+
 }
 #endif
 
 int check_if_ipmask(const char *mask)
 {
   int has_digit = 0;
-  register const char *p;
+  const char *p;
 
   for (p = mask; *p; ++p)
     if (*p != '*' && *p != '?' && *p != '.')
     {
-      if (!isDigit(*p))
-       return 0;
+      if (!IsDigit(*p))
+        return 0;
       has_digit = -1;
     }
 
diff --git a/ircd/table_gen.c b/ircd/table_gen.c
new file mode 100644 (file)
index 0000000..44eaa7b
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * IRC - Internet Relay Chat, include/common.c
+ * Copyright (C) 1998 Andrea Cocito
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*=============================================================================
+ * TABLE GENERATOR
+ * The following part of code is NOT included in the actual server's
+ * or library source, it's just used to build the above tables
+ *
+ * This should rebuild the actual tables and automatically place them
+ * into this source file, note that this part of code is for developers
+ * only, it's supposed to work on both signed and unsigned chars but I
+ * actually tested it only on signed-char architectures, the code and
+ * macros actually used by the server instead DO work and have been tested
+ * on platforms where0 char is both signed or unsigned, this is true as long
+ * as the <limits.h> macros are set properly and without any need to rebuild
+ * the tables (wich as said an admin should NEVER do, tables need to be rebuilt
+ * only when one wants to really change the results or when one has to
+ * compile on architectures where a char is NOT eight bits [?!], yes
+ * it all is supposed to work in that case too... but I can't test it
+ * because I've not found a machine in the world where this happes).
+ *
+ * NEVER -f[un]signed-char on gcc since that does NOT fix the named macros
+ * and you end up in a non-ANSI environment where CHAR_MIN and CHAR_MAX
+ * are _not_ the real limits of a default 'char' type. This is true for
+ * both admins and coders.
+ *
+ */
+
+#include "ircd_chattr.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+static void zeroTables(void);
+static void markString(int macro, const char *s);
+static void unMarkString(int macro, const char *s);
+static void markRange(int macro, char from, char to);
+static void moveMacro(int from, int to);
+static void setLowHi(const char firstlow, const char lastlow,
+    const char firsthi);
+
+char NTL_tolower_tab[1 + CHAR_MAX - CHAR_MIN]; /* 256 bytes */
+char NTL_toupper_tab[1 + CHAR_MAX - CHAR_MIN]; /* 256 bytes */
+int NTL_char_attrib[1 + CHAR_MAX - CHAR_MIN];  /* 256 ints = 0.5 to 2 kilobytes */
+
+/*
+ * makeTables() 
+ * Where we make the tables, edit ONLY this to change the tables.
+ */
+
+static void makeTables(void)
+{
+
+  /* Start from a known status */
+  zeroTables();
+
+  /* Make the very elementary sets */
+  markRange(NTL_LOWER, 'a', 'z');
+  markString(NTL_LOWER, "{|}~");
+
+  markRange(NTL_UPPER, 'A', 'Z');
+  markString(NTL_UPPER, "[\\]^");
+
+  markRange(NTL_DIGIT, '0', '9');
+
+  markRange(NTL_CNTRL, '\000', '\037');
+
+  markString(NTL_PUNCT, "!\"#$%&'()*+,-./:;<=>?@_`");
+
+  markString(NTL_SPACE, "\011\012\013\014\015\040");
+
+  /* Make the derived sets, 
+   * WARNING: The order of these calls is important, some depend on 
+   * the results of the previous ones ! */
+
+  moveMacro(NTL_LOWER | NTL_UPPER, NTL_ALPHA);
+  moveMacro(NTL_ALPHA | NTL_DIGIT, NTL_ALNUM);
+  moveMacro(NTL_ALNUM | NTL_PUNCT, NTL_GRAPH);
+
+  moveMacro(NTL_GRAPH, NTL_PRINT);
+  markString(NTL_PRINT, " ");
+
+  markRange(NTL_IRCCH, 0, UCHAR_MAX);
+  unMarkString(NTL_IRCCH, "\007\040\054\240");
+
+  markRange(NTL_IRCCL, '\300', '\326');
+  markRange(NTL_IRCCL, '\330', '\336');
+
+  moveMacro(NTL_ALNUM, NTL_IRCHN);
+  markString(NTL_IRCHN, "-_.");        /* Some DNS might allow '_' per RFC 1033 ! */
+
+  moveMacro(NTL_DIGIT, NTL_IRCIP);
+  markString(NTL_IRCIP, ".");
+
+  moveMacro(NTL_DIGIT | NTL_ALPHA, NTL_IRCNK);
+  markString(NTL_IRCNK, "-_`");
+
+  moveMacro(NTL_ALNUM, NTL_IRCUI);
+  markRange(NTL_IRCUI, '\xe0', '\xf6');
+  markRange(NTL_IRCUI, '\xf8', '\xfe');
+  markRange(NTL_IRCUI, '\xc0', '\xd6');
+  markRange(NTL_IRCUI, '\xd8', '\xde');
+  markString(NTL_IRCUI, ".-_^'`~");
+  markString(NTL_EOL, "\n\r");
+  markString(NTL_CHPFX, "#&+");
+  markString(NTL_KTIME, " ,-0123456789");
+
+  /* And finally let's take care of the toLower/toUpper stuff */
+
+  setLowHi('a', 'z', 'A');
+  setLowHi('\xe0', '\xf6', '\xc0');
+  setLowHi('\xf8', '\xfe', '\xd8');
+  setLowHi('{', '~', '[');
+}
+
+/* 
+ * main()
+ * This is the main program to be executed for -DMAKETABLES
+ */
+
+static void dumphw(int *p, int beg);
+static void dumphb(char *p, int beg);
+
+int main(void)
+{
+  int i;
+
+  /* Make the tables */
+  makeTables();
+
+  /* Dump them as ANSI C source to be included below */
+  printf("/*\n * Automatically Generated Tables - DO NOT EDIT\n */\n");
+  printf("#include <limits.h>\n");
+
+  /* NTL_tolower_tab */
+  printf("const char ToLowerTab_8859_1[] = {\n");
+  printf("#if (CHAR_MIN<0)\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_tolower_tab, i);
+  printf("                ,\n");
+  printf("#endif /* (CHAR_MIN<0) */\n");
+  i = 0;
+  dumphb(NTL_tolower_tab, i);
+  printf("#if (!(CHAR_MIN<0))\n");
+  printf("                ,\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_tolower_tab, i);
+  printf("#endif /* (!(CHAR_MIN<0)) */\n");
+  printf("  };\n\n");
+
+  /* NTL_toupper_tab */
+  printf("const char ToUpperTab_8859_1[] = {\n");
+  printf("#if (CHAR_MIN<0)\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_toupper_tab, i);
+  printf("                ,\n");
+  printf("#endif /* (CHAR_MIN<0) */\n");
+  i = 0;
+  dumphb(NTL_toupper_tab, i);
+  printf("#if (!(CHAR_MIN<0))\n");
+  printf("                ,\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphb(NTL_toupper_tab, i);
+  printf("#endif /* (!(CHAR_MIN<0)) */\n");
+  printf("  };\n\n");
+
+  /* NTL_char_attrib */
+  printf("const unsigned int IRCD_CharAttrTab[] = {\n");
+  printf("#if (CHAR_MIN<0)\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphw(NTL_char_attrib, i);
+  printf("                ,\n");
+  printf("#endif /* (CHAR_MIN<0) */\n");
+  i = 0;
+  dumphw(NTL_char_attrib, i);
+  printf("#if (!(CHAR_MIN<0))\n");
+  printf("                ,\n");
+  i = (int)((char)SCHAR_MIN);
+  dumphw(NTL_char_attrib, i);
+  printf("#endif /* (!(CHAR_MIN<0)) */\n");
+  printf("  };\n\n");
+
+  return 0;
+
+}
+
+/* A few utility functions for makeTables() */
+
+static void zeroTables(void)
+{
+  int i;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+  {
+    NTL_tolower_tab[i - CHAR_MIN] = (char)i;   /* Unchanged */
+    NTL_toupper_tab[i - CHAR_MIN] = (char)i;   /* Unchanged */
+    NTL_char_attrib[i - CHAR_MIN] = 0x0000;    /* Nothing */
+  }
+}
+
+static void markString(int macro, const char *s)
+{
+  while (*s)
+    NTL_char_attrib[*(s++) - CHAR_MIN] |= macro;
+}
+
+static void unMarkString(int macro, const char *s)
+{
+  while (*s)
+    NTL_char_attrib[*(s++) - CHAR_MIN] &= ~macro;
+}
+
+static void markRange(int macro, char from, char to)
+{
+  int i;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+    if (((unsigned char)i >= (unsigned char)from)
+       && ((unsigned char)i <= (unsigned char)to))
+      NTL_char_attrib[(char)i - CHAR_MIN] |= macro;
+}
+
+static void moveMacro(int from, int to)
+{
+  int i;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+    if (NTL_char_attrib[i - CHAR_MIN] & from)
+      NTL_char_attrib[i - CHAR_MIN] |= to;
+}
+
+static void setLowHi(const char firstlow, const char lastlow,
+    const char firsthi)
+{
+  int i, j;
+  for (i = CHAR_MIN; i <= CHAR_MAX; i++)
+    if (((unsigned char)i >= (unsigned char)firstlow)
+       && ((unsigned char)i <= (unsigned char)lastlow))
+    {
+      j = ((int)((char)(i + (int)(firsthi - firstlow))));
+      NTL_tolower_tab[((char)j) - CHAR_MIN] = (char)i;
+      NTL_toupper_tab[((char)i) - CHAR_MIN] = (char)j;
+    }
+}
+
+/* These are used in main() to actually dump the tables, each function
+   dumps half table as hex/char constants... */
+
+#define ROWSIZE 8
+
+static void dumphb(char *tbl, int beg)
+{
+  int i, j, k;
+  char *p = &tbl[beg - CHAR_MIN];
+  char c;
+  for (i = 0; i <= SCHAR_MAX; i += ROWSIZE)
+  {
+    k = i + ROWSIZE - 1;
+    if (k > SCHAR_MAX)
+      k = SCHAR_MAX;
+
+    c = (char)(beg + i);
+    printf("/*");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf(" '%c'", c);
+    else
+      printf(" x%02x", ((int)((unsigned char)c)));
+
+    c = (char)(beg + k);
+    printf("-");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf("'%c'", c);
+    else
+      printf("x%02x", ((int)((unsigned char)c)));
+    printf(" */");
+
+    for (j = i; j <= k; j++)
+    {
+      c = p[j];
+      if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+         && (c != '\''))
+       printf("    '%c'", c);
+      else
+       printf(" '\\x%02x'", ((int)((unsigned char)c)));
+      if (j < SCHAR_MAX)
+       printf(",");
+    }
+    printf("\n");
+  }
+}
+
+static void dumphw(int *tbl, int beg)
+{
+  int i, j, k;
+  int *p = &tbl[beg - CHAR_MIN];
+  char c;
+  for (i = 0; i <= SCHAR_MAX; i += ROWSIZE)
+  {
+    k = i + ROWSIZE - 1;
+    if (k > SCHAR_MAX)
+      k = SCHAR_MAX;
+
+    c = (char)(beg + i);
+    printf("/*");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf(" '%c'", c);
+    else
+      printf(" x%02x", ((int)((unsigned char)c)));
+
+    c = (char)(beg + k);
+    printf("-");
+    if ((c > 0) && (c < SCHAR_MAX) && (isprint(c)) && (c != '\\')
+       && (c != '\''))
+      printf("'%c'", c);
+    else
+      printf("x%02x", ((int)((unsigned char)c)));
+    printf(" */");
+
+    for (j = i; j <= k; j++)
+    {
+      printf(" 0x%04x", p[j] & 0xffffffff);
+      if (j < SCHAR_MAX)
+       printf(",");
+    }
+    printf("\n");
+  }
+}
+
diff --git a/ircd/test/Makefile b/ircd/test/Makefile
new file mode 100644 (file)
index 0000000..460e3a6
--- /dev/null
@@ -0,0 +1,20 @@
+
+CPPFLAGS = -I../../include -I../../config
+CFLAGS   = -g -Wall
+
+TESTPROGS = \
+       ircd_chattr_t \
+       ircd_string_t
+
+all: ${TESTPROGS}
+ircd_chattr_t: ircd_chattr_t.o ../ircd_string.o
+       ${CC} -o $@ $^
+
+ircd_string_t: ircd_string_t.o ../ircd_string.o
+       ${CC} -o $@ $^
+
+.PHONY: clean
+
+clean:
+       rm -f core *.o ${TESTPROGS}
diff --git a/ircd/test/ircd_chattr.0.dat b/ircd/test/ircd_chattr.0.dat
new file mode 100644 (file)
index 0000000..7b0cf24
--- /dev/null
@@ -0,0 +1,16 @@
+IsAlnum:         0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^abcdefghijklmnopqrstuvwxyz{|}~
+IsAlpha:         ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^abcdefghijklmnopqrstuvwxyz{|}~
+IsDigit:         0123456789
+IsLower:         abcdefghijklmnopqrstuvwxyz{|}~
+IsSpace:         \t\n\v\f\r 
+IsUpper:         ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^
+IsCntrl:         \0\1\2\3\4\5\6\a\b\t\n\v\f\r\e\f\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f
+IsChannelChar:   \0\1\2\3\4\5\6\b\t\n\v\f\r\e\f\10\11\12\13\14\15\16\17\18\19\1a\1b\1c\1d\1e\1f!"#$%&'()*+-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\7f\80\81\82\83\84\85\86\87\88\89\8a\8b\8c\8d\8e\8f\90\91\92\93\94\95\96\97\98\99\9a\9b\9c\9d\9e\9f\a1\a2\a3\a4\a5\a6\a7\a8\a9\aa\ab\ac\ad\ae\af\b0\b1\b2\b3\b4\b5\b6\b7\b8\b9\ba\bb\bc\bd\be\bf\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9\ca\cb\cc\cd\ce\cf\d0\d1\d2\d3\d4\d5\d6\d7\d8\d9\da\db\dc\dd\de\df\e0\e1\e2\e3\e4\e5\e6\e7\e8\e9\ea\eb\ec\ed\ee\ef\f0\f1\f2\f3\f4\f5\f6\f7\f8\f9\fa\fb\fc\fd\fe\ff
+IsChannelLower:  \c0\c1\c2\c3\c4\c5\c6\c7\c8\c9\ca\cb\cc\cd\ce\cf\d0\d1\d2\d3\d4\d5\d6\d8\d9\da\db\dc\dd\de
+IsChannelPrefix: #&+
+IsNickChar:      -0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
+IsUserChar:      '-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9\ca\cb\cc\cd\ce\cf\d0\d1\d2\d3\d4\d5\d6\d8\d9\da\db\dc\dd\de\e0\e1\e2\e3\e4\e5\e6\e7\e8\e9\ea\eb\ec\ed\ee\ef\f0\f1\f2\f3\f4\f5\f6\f8\f9\fa\fb\fc\fd\fe
+IsHostChar:      -.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~
+IsIPChar:        .0123456789
+IsEol:           \n\r
+IsKTimeChar:      ,-0123456789
diff --git a/ircd/test/ircd_chattr_t.c b/ircd/test/ircd_chattr_t.c
new file mode 100644 (file)
index 0000000..806a3e6
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * ircd_chattr_t.c - Test file for character attributes
+ */
+#include "ircd_chattr.h"
+#include <assert.h>
+#include <stdio.h>
+
+typedef int (*EvalFn)(char);
+
+int eval_alnum(char c)
+{
+  return (0 != IsAlnum(c));
+}
+
+int eval_alpha(char c)
+{
+  return (0 != IsAlpha(c));
+}
+
+int eval_digit(char c)
+{
+  return (0 != IsDigit(c));
+}
+
+int eval_lower(char c)
+{
+  return (0 != IsLower(c));
+}
+
+int eval_space(char c)
+{
+  return (0 != IsSpace(c));
+}
+
+int eval_upper(char c)
+{
+  return (0 != IsUpper(c));
+}
+
+int eval_cntrl(char c)
+{
+  return (0 != IsCntrl(c));
+}
+
+int eval_channel_char(char c)
+{
+  return (0 != IsChannelChar(c));
+}
+
+int eval_channel_lower(char c)
+{
+  return (0 != IsChannelLower(c));
+}
+
+int eval_channel_prefix(char c)
+{
+  return (0 != IsChannelPrefix(c));
+}
+
+int eval_nick_char(char c)
+{
+  return (0 != IsNickChar(c));
+}
+
+int eval_user_char(char c)
+{
+  return (0 != IsUserChar(c));
+}
+
+int eval_host_char(char c)
+{
+  return (0 != IsHostChar(c));
+}
+
+int eval_ip_char(char c)
+{
+  return (0 != IsIPChar(c));
+}
+
+int eval_eol(char c)
+{
+  return (0 != IsEol(c));
+}
+
+int eval_ktime_char(char c)
+{
+  return (0 != IsKTimeChar(c));
+}
+
+struct CharTest {
+  const char* name;
+  EvalFn      evaluator;
+} testList[] = {
+  { "IsAlnum:         ", eval_alnum },
+  { "IsAlpha:         ", eval_alpha },
+  { "IsDigit:         ", eval_digit },
+  { "IsLower:         ", eval_lower },
+  { "IsSpace:         ", eval_space },
+  { "IsUpper:         ", eval_upper },
+  { "IsCntrl:         ", eval_cntrl },
+  { "IsChannelChar:   ", eval_channel_char },
+  { "IsChannelLower:  ", eval_channel_lower },
+  { "IsChannelPrefix: ", eval_channel_prefix },
+  { "IsNickChar:      ", eval_nick_char },
+  { "IsUserChar:      ", eval_user_char },
+  { "IsHostChar:      ", eval_host_char },
+  { "IsIPChar:        ", eval_ip_char },
+  { "IsEol:           ", eval_eol },
+  { "IsKTimeChar:     ", eval_ktime_char }
+};
+
+#define TESTLIST_SIZE sizeof(testList) / sizeof(struct CharTest)
+
+void print_char(unsigned char c)
+{
+  if (c < 0x20) {
+    switch (c) {
+    case '\a': printf("\\a"); break;
+    case '\b': printf("\\b"); break;
+    case '\f': printf("\\f"); break;
+    case '\n': printf("\\n"); break;
+    case '\r': printf("\\r"); break;
+    case '\t': printf("\\t"); break;
+    case '\v': printf("\\v"); break;
+    default:
+      printf("\\%x", c); break;
+    }
+  }
+  else if (c < 0x7F) {
+    printf("%c", c);
+  }
+  else {
+    printf("\\%x", c);
+  }
+}
+
+void print_char_attr(struct CharTest* test)
+{
+  int i;
+
+  printf("%s", test->name);
+
+  for (i = 0; i < 256; ++i) {
+    if ((*test->evaluator)(i))
+      print_char(i);
+  }
+  printf("\n");
+}
+
+    
+int main(void)
+{
+  int i;
+
+  for (i = 0; i < TESTLIST_SIZE; ++i)
+    print_char_attr(&testList[i]);
+
+  return 0;
+}
+
diff --git a/ircd/test/ircd_string_t.c b/ircd/test/ircd_string_t.c
new file mode 100644 (file)
index 0000000..3c73aa8
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * ircd_string_t.c - string test program
+ */
+#include "ircd_string.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(void)
+{
+  char* vector[20];
+  char* names;
+  int count;
+  int i;
+
+  names = strdup(",,,a,b,a,X,ne,blah,A,z,#foo,&Bar,foo,,crud,Foo,z,x,bzet,,");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+
+  names = strdup("foo");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+  
+  names = strdup("");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+
+  names = strdup("a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z");
+  printf("input: %s\n", names);
+  count = unique_name_vector(names, ',', vector, 20);
+  printf("count: %d\n", count);
+  printf("output:");
+  for (i = 0; i < count; ++i)
+    printf(" %s", vector[i]);
+  printf("\n");
+  free(names);
+
+  return 0;
+}
+  
diff --git a/ircd/uping.c b/ircd/uping.c
new file mode 100644 (file)
index 0000000..a7dc45f
--- /dev/null
@@ -0,0 +1,608 @@
+/*
+ * IRC - Internet Relay Chat, ircd/uping.c
+ * Copyright (C) 1994 Carlo Wood ( Run @ undernet.org )
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ */
+#include "uping.h"
+#include "client.h"
+#include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_log.h"
+#include "ircd_osdep.h"
+#include "ircd_string.h"
+#include "match.h"
+#include "numeric.h"
+#include "numnicks.h"
+#include "res.h"
+#include "s_bsd.h"    /* vserv */
+#include "s_conf.h"
+#include "s_debug.h"
+#include "s_misc.h"
+#include "s_user.h"
+#include "send.h"
+#include "sys.h"
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#define UPINGTIMEOUT 60   /* Timeout waiting for ping responses */
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+static void ping_server(struct UPing*);
+
+static struct UPing* pingList = 0;
+int UPingListener = -1; /* UDP listener socket for upings */
+
+/*
+ * pings_begin - iterator function for ping list 
+ */
+struct UPing* uping_begin(void)
+{
+  return pingList;
+}
+
+/*
+ * pings_erase - removes ping struct from ping list
+ */
+static void uping_erase(struct UPing* p)
+{
+  struct UPing* it;
+  struct UPing* last = 0;
+
+  assert(0 != p);
+  
+  for (it = pingList; it; last = it = it->next) {
+    if (p == it) {
+      if (last)
+        last->next = p->next;
+      else
+        pingList = p->next;
+      break;
+    }
+  }
+}
+
+/*
+ * uping_dns_callback - this gets called when the resolver either
+ * succeeds or fails to locate the servers address.
+ * If the dns query failed hp will be 0, otherwise it
+ * will contain the stuff a hostent normally contains.
+ */
+static void uping_dns_callback(void* v, struct DNSReply* r)
+{
+  struct UPing* ping = (struct UPing*) v;
+  assert(valid_ptr((void*)ping, sizeof(struct UPing)));
+
+  if (r) {
+    memcpy(&ping->sin.sin_addr, r->hp->h_addr, sizeof(struct in_addr));
+    ping_server(ping);
+  }
+  else
+  {
+    sendto_ops("UDP ping to %s failed: host lookup", ping->name);
+    end_ping(ping);
+  }
+}
+
+
+/*
+ * Setup a UDP socket and listen for incoming packets
+ */
+int uping_init(void)
+{
+  struct sockaddr_in from;
+  int fd;
+
+  memset(&from, 0, sizeof(from));
+#ifdef VIRTUAL_HOST
+  from.sin_addr = vserv.sin_addr;
+#else
+  from.sin_addr.s_addr = htonl(INADDR_ANY);
+#endif
+  from.sin_port = htons(atoi(UDP_PORT));
+  from.sin_family = AF_INET;
+
+  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+    Debug((DEBUG_ERROR, "UPING: UDP listener socket call failed: %s", strerror(errno)));
+    return -1;
+  }
+  if (!os_set_reuseaddr(fd)) {
+    ircd_log(L_ERROR, "UPING: setsockopt UDP listener: fd %d", fd);
+    Debug((DEBUG_ERROR, "UPING: set reuseaddr on UDP listener failed: %s", strerror(errno)));
+    close(fd);
+    return -1;
+  }
+  if (bind(fd, (struct sockaddr*) &from, sizeof(from)) == -1) {
+    ircd_log(L_ERROR, "UPING: bind UDP listener %d fd %d", htons(from.sin_port), fd);
+    Debug((DEBUG_ERROR, "UPING: bind on UDP listener failed : %s", strerror(errno)));
+    close(fd);
+    return -1;
+  }
+  if (!os_set_nonblocking(fd)) {
+    Debug((DEBUG_ERROR, "UPING: set non-blocking: %s", strerror(errno)));
+    close(fd);
+    return -1;
+  }
+  return fd;
+}
+
+
+/*
+ * max # of pings set to 15/sec.
+ */
+void polludp(int udpfd)
+{
+  struct sockaddr_in from;
+  size_t             len = 0;
+  static time_t      last = 0;
+  static int         counter = 0;
+  char               buf[BUFSIZE + 1];
+
+  Debug((DEBUG_DEBUG, "UPING: poll"));
+
+  if (IO_SUCCESS != os_recvfrom_nonb(udpfd, buf, BUFSIZE, &len, &from))
+    return;
+  /*
+   * count em even if we're getting flooded so we can tell we're getting
+   * flooded.
+   */
+  ++ServerStats->uping_recv;
+  if (CurrentTime == last) {
+    if (++counter > 10)
+      return;
+  }
+  else {
+    counter = 0;
+    last    = CurrentTime;
+  }
+  if (len < 19)
+    return;
+  sendto(udpfd, buf, len, 0, (struct sockaddr *)&from, sizeof(from));
+}
+
+
+/*
+ * start_ping
+ */
+static void start_ping(struct UPing* pptr)
+{
+  assert(valid_ptr((void*) pptr, sizeof(struct UPing)));
+
+  if (MyUser(pptr->client) || Protocol(pptr->client->from) < 10) {
+    sendto_one(pptr->client,
+       ":%s NOTICE %s :Sending %d ping%s to %s[%s] port %d",
+       me.name, pptr->client->name, pptr->count,
+       (pptr->count == 1) ? "" : "s", pptr->name,
+       ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port));
+  }
+  else
+  {
+    sendto_one(pptr->client,
+       "%s NOTICE %s%s :Sending %d ping%s to %s[%s] port %d",
+       NumServ(&me), NumNick(pptr->client), pptr->count,
+       (pptr->count == 1) ? "" : "s", pptr->name,
+       ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port));
+  }
+  pptr->timeout = CurrentTime + UPINGTIMEOUT;
+  pptr->active = 1;
+}
+
+/*
+ * ping_server - get the server host address if not valid
+ * then call start_ping
+ */
+static void ping_server(struct UPing* pptr)
+{
+  if (INADDR_NONE == pptr->sin.sin_addr.s_addr) {
+    char *s;
+
+    if ((s = strchr(pptr->name, '@')))
+      ++s;                     
+    else
+      s = pptr->name;
+
+    if (INADDR_NONE == (pptr->sin.sin_addr.s_addr = inet_addr(s))) {
+      struct DNSQuery query;
+      struct DNSReply* rpl;
+
+      query.vptr = (void*) pptr;
+      query.callback = uping_dns_callback;
+      if (0 == (rpl = gethost_byname(s, &query)))
+       return;
+      memcpy(&pptr->sin.sin_addr, rpl->hp->h_addr, sizeof(struct in_addr));
+    }
+  }
+  start_ping(pptr);
+}
+
+
+/*
+ * send_ping
+ *
+ */
+void send_ping(struct UPing* pptr)
+{
+  struct timeval tv;
+  char buf[BUFSIZE + 1];
+
+  assert(0 != pptr);
+  memset(buf, 0, sizeof(buf));
+
+  gettimeofday(&tv, NULL);
+  sprintf(buf, " %10lu%c%6lu", tv.tv_sec, '\0', tv.tv_usec);
+
+  Debug((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
+         buf, &buf[12],
+         ircd_ntoa((const char*) &pptr->sin.sin_addr), ntohs(pptr->sin.sin_port),
+         pptr->fd));
+
+  if (sendto(pptr->fd, buf, BUFSIZE, 0, (struct sockaddr*) &pptr->sin,
+             sizeof(struct sockaddr_in)) != BUFSIZE)
+  {
+    int err = errno;
+    if (pptr->client)
+    {
+      if (MyUser(pptr->client)
+#ifndef NO_PROTOCOL9
+         || (IsServer(pptr->client->from) && Protocol(pptr->client->from) < 10)
+#endif
+         )
+       sendto_one(pptr->client, ":%s NOTICE %s :UPING: sendto() failed: %s",
+                  me.name, pptr->client->name, strerror(errno));
+      else
+       sendto_one(pptr->client, "%s NOTICE %s%s :UPING: sendto() failed: %s",
+                  NumServ(&me), NumNick(pptr->client), strerror(errno));
+    }
+    Debug((DEBUG_DEBUG, "UPING: send_ping: sendto failed on %d: %s", pptr->fd, strerror(err)));
+    end_ping(pptr);
+    return;
+  }
+  ++pptr->sent;
+}
+
+/*
+ * read_ping
+ */
+void read_ping(struct UPing* pptr)
+{
+  struct sockaddr_in sin;
+  struct timeval     tv;
+  unsigned int       len;
+  unsigned int       pingtime;
+  char*              s;
+  char               buf[BUFSIZE + 1];
+  IOResult           ior;
+
+  assert(0 != pptr);
+
+  gettimeofday(&tv, NULL);
+
+  ior = os_recvfrom_nonb(pptr->fd, buf, BUFSIZE, &len, &sin);
+  if (IO_BLOCKED == ior)
+    return;
+  else if (IO_FAILURE == ior) {
+    int err = errno;
+    if (MyUser(pptr->client)
+#ifndef NO_PROTOCOL9
+        || (IsServer(pptr->client->from) && Protocol(pptr->client->from) < 10)
+#endif
+        )
+      sendto_one(pptr->client, ":%s NOTICE %s :UPING: recvfrom: %s",
+                 me.name, pptr->client->name, strerror(err));
+    else
+      sendto_one(pptr->client, "%s NOTICE %s%s :UPING: recvfrom: %s",
+                 NumServ(&me), NumNick(pptr->client), strerror(err));
+    Debug((DEBUG_SEND, "UPING: read_ping: recvfrom: %d", err));
+    end_ping(pptr);
+    return;
+  }    
+
+  if (len < 19)
+    return;                    /* Broken packet */
+
+  ++pptr->received;
+  pingtime = (tv.tv_sec - atol(&buf[1])) * 1000
+             + (tv.tv_usec - atol(buf + strlen(buf) + 1)) / 1000;
+
+  pptr->ms_ave += pingtime;
+  if (!(pptr->ms_min) || (pptr->ms_min > pingtime))
+    pptr->ms_min = pingtime;
+  if (pingtime > pptr->ms_max)
+    pptr->ms_max = pingtime;
+  
+  pptr->timeout = CurrentTime + UPINGTIMEOUT;
+
+  Debug((DEBUG_SEND, "read_ping: %d bytes, ti %lu: [%s %s] %lu ms",
+      len, pptr->timeout, buf, (buf + strlen(buf) + 1), pingtime));
+
+  s = pptr->buf + strlen(pptr->buf);
+  sprintf(s, " %u", pingtime);
+
+  if (pptr->received == pptr->count)
+    end_ping(pptr);
+  return;
+}
+
+
+/*
+ * m_uping  -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = pinged server
+ * parv[2] = port
+ * parv[3] = hunted server
+ * parv[4] = number of requested pings
+ */
+int m_uping(struct Client* cptr, struct Client *sptr, int parc, char *parv[])
+{
+  struct ConfItem *aconf;
+  int port;
+  int fd;
+  struct UPing* pptr = 0;
+
+  if (!IsPrivileged(sptr))
+  {
+    sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+    return -1;
+  }
+
+  if (parc < 2)
+  {
+    sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "UPING");
+    return 0;
+  }
+
+  if (MyUser(sptr))
+  {
+    if (parc == 2)
+    {
+      parv[parc++] = UDP_PORT;
+      parv[parc++] = me.name;
+      parv[parc++] = "5";
+    }
+    else if (parc == 3)
+    {
+      if (IsDigit(*parv[2]))
+       parv[parc++] = me.name;
+      else
+      {
+       parv[parc++] = parv[2];
+       parv[2] = UDP_PORT;
+      }
+      parv[parc++] = "5";
+    }
+    else if (parc == 4)
+    {
+      if (IsDigit(*parv[2]))
+      {
+       if (IsDigit(*parv[3]))
+       {
+         parv[parc++] = parv[3];
+         parv[3] = me.name;
+       }
+       else
+         parv[parc++] = "5";
+      }
+      else
+      {
+       parv[parc++] = parv[3];
+       parv[3] = parv[2];
+       parv[2] = UDP_PORT;
+      }
+    }
+  }
+  if (hunt_server(1, cptr, sptr,
+      ":%s UPING %s %s %s %s", 3, parc, parv) != HUNTED_ISME)
+    return 0;
+
+  if (BadPtr(parv[4]) || atoi(parv[4]) <= 0)
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :UPING: Illegal number of packets: %s",
+         me.name, parv[0], parv[4]);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :UPING: Illegal number of packets: %s",
+         NumServ(&me), NumNick(sptr), parv[4]);
+    return 0;
+  }
+
+  /* Check if a CONNECT would be possible at all (adapted from m_connect) */
+  for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+  {
+    if (aconf->status == CONF_SERVER &&
+       match(parv[1], aconf->name) == 0)
+      break;
+  }
+  if (!aconf)
+  {
+    for (aconf = GlobalConfList; aconf; aconf = aconf->next)
+    {
+      if (aconf->status == CONF_SERVER &&
+         (match(parv[1], aconf->host) == 0 ||
+          match(parv[1], strchr(aconf->host, '@') + 1) == 0))
+       break;
+    }
+  }
+  if (!aconf)
+  {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :UPING: Host %s not listed in ircd.conf",
+         me.name, parv[0], parv[1]);
+    else
+      sendto_one(sptr,
+         "%s NOTICE %s%s :UPING: Host %s not listed in ircd.conf",
+         NumServ(&me), NumNick(sptr), parv[1]);
+    return 0;
+  }
+
+  if (IsUPing(sptr))
+    cancel_ping(sptr, sptr);  /* Cancel previous ping request */
+
+  /*
+   * Determine port: First user supplied, then default : 7007
+   */
+  if (BadPtr(parv[2]) || (port = atoi(parv[2])) <= 0)
+    port = atoi(UDP_PORT);
+
+  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+    int err = errno;
+    sendto_ops("m_uping: socket: %s", (err != EMFILE) 
+                ? strerror(err) : "No more sockets");
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, 
+                 ":%s NOTICE %s :UPING: Unable to create udp ping socket",
+                 me.name, parv[0]);
+    else
+      sendto_one(sptr,
+                 "%s NOTICE %s%s :UPING: Unable to create udp ping socket",
+                 NumServ(&me), NumNick(sptr));
+    ircd_log(L_ERROR, "UPING: Unable to create UDP socket");
+    return 0;
+  }
+
+  if (!os_set_nonblocking(fd)) {
+    if (MyUser(sptr) || Protocol(cptr) < 10)
+      sendto_one(sptr, ":%s NOTICE %s :UPING: Can't set fd non-blocking",
+            me.name, parv[0]);
+    else
+      sendto_one(sptr, "%s NOTICE %s%s :UPING: Can't set fd non-blocking",
+            NumServ(&me), NumNick(sptr));
+    close(fd);
+    return 0;
+  }
+  pptr = (struct UPing*) MyMalloc(sizeof(struct UPing));
+  assert(0 != pptr);
+  memset(pptr, 0, sizeof(struct UPing));
+
+  pptr->fd = fd;
+  pptr->sin.sin_port = htons(port);
+  pptr->sin.sin_addr.s_addr = aconf->ipnum.s_addr;
+  pptr->sin.sin_family = AF_INET;
+  pptr->count = IRCD_MIN(20, atoi(parv[4]));
+  strcpy(pptr->name, aconf->host);
+  pptr->client = sptr;
+  pptr->index = -1;
+
+  pptr->next = pingList;
+  pingList = pptr;
+
+  SetUPing(sptr);
+  ping_server(pptr);
+  return 0;
+}
+
+void end_ping(struct UPing* pptr)
+{
+  Debug((DEBUG_DEBUG, "end_ping: %p", pptr));
+  delete_resolver_queries((void*) pptr);
+  if (pptr->client)
+  {
+    if (MyUser(pptr->client)
+        || (IsServer(pptr->client->from) && Protocol(pptr->client->from) < 10))
+    {
+      if (pptr->lastsent)      /* Started at all ? */
+      {
+       if (0 < pptr->received) /* Received any pings at all? */
+       {
+         sendto_one(pptr->client, ":%s NOTICE %s :UPING %s%s",
+             me.name, pptr->client->name, pptr->name, pptr->buf);
+          /* XXX - warning long unsigned int format, unsigned int arg (7, 8, 9) */
+         sendto_one(pptr->client,
+             ":%s NOTICE %s :UPING Stats: sent %d recvd %d ; "
+             "min/avg/max = %1lu/%1lu/%1lu ms",
+             me.name, pptr->client->name, pptr->sent,
+             pptr->received, pptr->ms_min,
+             (2 * pptr->ms_ave) / (2 * pptr->received), 
+              pptr->ms_max);
+       }
+       else
+         sendto_one(pptr->client,
+             ":%s NOTICE %s :UPING: no response from %s within %d seconds",
+             me.name, pptr->client->name, pptr->name,
+             UPINGTIMEOUT);
+      }
+      else
+       sendto_one(pptr->client,
+           ":%s NOTICE %s :UPING: Could not start ping to %s %d",
+           me.name, pptr->client->name, pptr->name, ntohs(pptr->sin.sin_port));
+    }
+    else
+    {
+      if (pptr->lastsent)      /* Started at all ? */
+      {
+       if (0 < pptr->received) /* Received any pings at all? */
+       {
+         sendto_one(pptr->client, "%s NOTICE %s%s :UPING %s%s",
+             NumServ(&me), NumNick(pptr->client), pptr->name, pptr->buf);
+          /* XXX - warning: long unsigned int format, unsigned int arg(9, 10, 11) */
+         sendto_one(pptr->client,
+             "%s NOTICE %s%s :UPING Stats: sent %d recvd %d ; "
+             "min/avg/max = %1lu/%1lu/%1lu ms",
+             NumServ(&me), NumNick(pptr->client), pptr->sent,
+             pptr->received, pptr->ms_min,
+             (2 * pptr->ms_ave) / (2 * pptr->received), 
+              pptr->ms_max);
+       }
+       else
+         sendto_one(pptr->client,
+             "%s NOTICE %s%s :UPING: no response from %s within %d seconds",
+             NumServ(&me), NumNick(pptr->client), pptr->name,
+             UPINGTIMEOUT);
+      }
+      else
+       sendto_one(pptr->client,
+           "%s NOTICE %s%s :UPING: Could not start ping to %s %d",
+           NumServ(&me), NumNick(pptr->client), pptr->name, 
+            ntohs(pptr->sin.sin_port));
+    }
+  }
+  close(pptr->fd);
+  pptr->fd = -1;
+  uping_erase(pptr);
+  if (pptr->client)
+    ClearUPing(pptr->client);
+  MyFree(pptr);
+}
+
+void cancel_ping(struct Client *sptr, struct Client* acptr)
+{
+  struct UPing* ping;
+  struct UPing* ping_next;
+
+  Debug((DEBUG_DEBUG, "UPING: cancelling uping for %s", sptr->name));
+  for (ping = pingList; ping; ping = ping_next) {
+    ping_next = ping->next;
+    if (sptr == ping->client) {
+      ping->client = acptr;
+      end_ping(ping);
+    }
+  }
+  ClearUPing(sptr);
+}
+
index e195fab43eeed5fc4b37122579f561cce29bf9f5..b972025f67b54fa61e14b5fa20b1b40f2183c0be 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdio.h>
-#include <signal.h>
-#include <sys/resource.h>
-#include "h.h"
-#include "struct.h"
-#include "send.h"
-#include "s_misc.h"
 #include "userload.h"
+#include "client.h"
 #include "ircd.h"
 #include "numnicks.h"
-#include "s_serv.h"
 #include "querycmds.h"
+#include "s_misc.h"
+#include "send.h"
+#include "struct.h"
+#include "sys.h"
 
-RCSTAG_CC("$Id$");
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
 
-struct current_load_st current_load;   /* The current load */
+struct current_load_st current_load;    /* The current load */
 
-static struct current_load_st cspm_sum;        /* Number of connections times number
-                                          of seconds per minute. */
-static struct current_load_st csph_sum;        /* Number of connections times number
-                                          of seconds per hour. */
-static struct current_load_st cspm[60];        /* Last 60 minutes */
-static struct current_load_st csph[72];        /* Last 72 hours */
+static struct current_load_st cspm_sum; /* Number of connections times number
+                                           of seconds per minute. */
+static struct current_load_st csph_sum; /* Number of connections times number
+                                           of seconds per hour. */
+static struct current_load_st cspm[60]; /* Last 60 minutes */
+static struct current_load_st csph[72]; /* Last 72 hours */
 
-static int m_index, h_index;   /* Array indexes */
+static int m_index, h_index;    /* Array indexes */
 
 /*
  * update_load
@@ -58,26 +57,26 @@ static int m_index, h_index;        /* Array indexes */
  */
 void update_load(void)
 {
-  static struct tm tm_now;     /* Current time. */
-  static time_t last_sec;      /* Seconds of last time that
-                                  update_load() called. */
+  static struct tm tm_now;      /* Current time. */
+  static time_t last_sec;       /* Seconds of last time that
+                                   update_load() called. */
   static time_t last_min;
-  static time_t last;          /* Last time that update_load() was called. */
-  static struct current_load_st last_load;     /* The load last time that
-                                                  update_load() was called. */
-  static int initialized;      /* Boolean, set when initialized. */
-  register int diff_time;      /* Temp. variable used to hold time intervals
-                                  in seconds, minutes or hours. */
+  static time_t last;           /* Last time that update_load() was called. */
+  static struct current_load_st last_load;      /* The load last time that
+                                                   update_load() was called. */
+  static int initialized;       /* Boolean, set when initialized. */
+  int diff_time;        /* Temp. variable used to hold time intervals
+                                   in seconds, minutes or hours. */
 
   /* Update `current_load' */
-  current_load.client_count = nrof.local_clients;
-  current_load.conn_count = nrof.local_clients + nrof.local_servers;
+  current_load.client_count = UserStats.local_clients;
+  current_load.conn_count = UserStats.local_clients + UserStats.local_servers;
 
   /* Nothing needed when still in the same second */
-  if (!(diff_time = now - last))
+  if (!(diff_time = CurrentTime - last))
   {
-    last_load = current_load;  /* Update last_load to be the load last
-                                  time that update_load() was called. */
+    last_load = current_load;   /* Update last_load to be the load last
+                                   time that update_load() was called. */
     return;
   }
 
@@ -98,13 +97,13 @@ void update_load(void)
       tm_now.tm_min -= 60 * diff_time;
       if ((tm_now.tm_hour += diff_time) > 23)
       {
-       tm_now = *localtime(&now);      /* Only called once a day */
-       if (!initialized)
-       {
-         initialized = 1;
-         last_sec = 60;
-         last_min = tm_now.tm_min;
-       }
+        tm_now = *localtime(&CurrentTime);      /* Only called once a day */
+        if (!initialized)
+        {
+          initialized = 1;
+          last_sec = 60;
+          last_min = tm_now.tm_min;
+        }
       }
     }
 
@@ -129,10 +128,10 @@ void update_load(void)
     last_min = tm_now.tm_min;
 
     if (diff_time < 0)
-      diff_time += 60;         /* update_load() must be called at
-                                  _least_ once an hour */
+      diff_time += 60;          /* update_load() must be called at
+                                   _least_ once an hour */
 
-    if (diff_time > 1)         /* Did more then one minute pass ? */
+    if (diff_time > 1)          /* Did more then one minute pass ? */
     {
       /* Calculate the constant load during those extra minutes */
       cspm_sum.conn_count = last_load.conn_count * 60;
@@ -145,21 +144,21 @@ void update_load(void)
       /* Increase minute index */
       if (++m_index == 60)
       {
-       m_index = 0;
-       /* Keep a list of the last 72 hours */
-       csph[h_index] = csph_sum;
-       if (++h_index == 72)
-         h_index = 0;
+        m_index = 0;
+        /* Keep a list of the last 72 hours */
+        csph[h_index] = csph_sum;
+        if (++h_index == 72)
+          h_index = 0;
       }
 
-      if (--diff_time <= 0)    /* '<' to prevent endless loop if update_load()
-                                  was not called once an hour :/ */
-       break;
+      if (--diff_time <= 0)     /* '<' to prevent endless loop if update_load()
+                                   was not called once an hour :/ */
+        break;
 
       /* Add extra minutes to the Connections*Seconds/Hour sum */
       csph_sum.conn_count += cspm_sum.conn_count - cspm[m_index].conn_count;
       csph_sum.client_count +=
-         cspm_sum.client_count - cspm[m_index].client_count;
+          cspm_sum.client_count - cspm[m_index].client_count;
       csph_sum.local_count += cspm_sum.local_count - cspm[m_index].local_count;
 
       /* Store extra minutes in the array */
@@ -178,7 +177,7 @@ void update_load(void)
     /* How long did last_load last ? */
     diff_time = tm_now.tm_sec - last_sec;
     last_sec = tm_now.tm_sec;
-    if (diff_time == 1)                /* Just one second ? */
+    if (diff_time == 1)         /* Just one second ? */
     {
       cspm_sum.conn_count += last_load.conn_count;
       cspm_sum.client_count += last_load.client_count;
@@ -193,12 +192,12 @@ void update_load(void)
       cspm_sum.local_count += last_load.local_count * diff_time;
     }
   }
-  last_load = current_load;    /* Update last_load to be the load last
-                                  time that update_load() was called. */
-  last = now;
+  last_load = current_load;     /* Update last_load to be the load last
+                                   time that update_load() was called. */
+  last = CurrentTime;
 }
 
-void calc_load(aClient *sptr)
+void calc_load(struct Client *sptr)
 {
   /* *INDENT-OFF* */
   static const char *header =
@@ -210,11 +209,11 @@ void calc_load(aClient *sptr)
     "total clients",
     "total connections"
   };
-  int i, j, times[5][3];       /* [min,hour,day,Yest,YYest]
-                                  [local,client,conn] */
+  int i, j, times[5][3];        /* [min,hour,day,Yest,YYest]
+                                   [local,client,conn] */
   int last_m_index = m_index, last_h_index = h_index;
 
-  update_load();               /* We want stats accurate as of *now* */
+  update_load();                /* We want stats accurate as of *now* */
 
   if (--last_m_index < 0)
     last_m_index = 59;
@@ -234,7 +233,7 @@ void calc_load(aClient *sptr)
     for (j = 0; j < 24; ++j)
     {
       if (--last_h_index < 0)
-       last_h_index = 71;
+        last_h_index = 71;
       times[i][0] += csph[last_h_index].local_count;
       times[i][1] += csph[last_h_index].client_count;
       times[i][2] += csph[last_h_index].conn_count;
@@ -249,27 +248,28 @@ void calc_load(aClient *sptr)
     sendto_one(sptr, ":%s NOTICE %s :%s", me.name, sptr->name, header);
     for (i = 0; i < 3; ++i)
       sendto_one(sptr,
-         ":%s NOTICE %s :%4d.%1d  %4d.%1d  %4d  %4d  %4d   %s",
-         me.name, sptr->name,
-         times[0][i] / 10, times[0][i] % 10,
-         times[1][i] / 10, times[1][i] % 10,
-         times[2][i], times[3][i], times[4][i], what[i]);
+          ":%s NOTICE %s :%4d.%1d  %4d.%1d  %4d  %4d  %4d   %s",
+          me.name, sptr->name,
+          times[0][i] / 10, times[0][i] % 10,
+          times[1][i] / 10, times[1][i] % 10,
+          times[2][i], times[3][i], times[4][i], what[i]);
   }
   else
   {
-    sendto_one(sptr, "%s NOTICE %s%s :%s", NumServ(&me), NumNick(sptr), header);
+    sendto_one(sptr, "%s NOTICE %s%s :%s",
+        NumServ(&me), NumNick(sptr), header);
     for (i = 0; i < 3; ++i)
       sendto_one(sptr,
-         "%s NOTICE %s%s :%4d.%1d  %4d.%1d  %4d  %4d  %4d   %s",
-         NumServ(&me), NumNick(sptr),
-         times[0][i] / 10, times[0][i] % 10,
-         times[1][i] / 10, times[1][i] % 10,
-         times[2][i], times[3][i], times[4][i], what[i]);
+          "%s NOTICE %s%s :%4d.%1d  %4d.%1d  %4d  %4d  %4d   %s",
+          NumServ(&me), NumNick(sptr),
+          times[0][i] / 10, times[0][i] % 10,
+          times[1][i] / 10, times[1][i] % 10,
+          times[2][i], times[3][i], times[4][i], what[i]);
   }
 }
 
 void initload(void)
 {
   memset(&current_load, 0, sizeof(current_load));
-  update_load();               /* Initialize the load list */
+  update_load();                /* Initialize the load list */
 }
index c0b52a905e90439afd2863218413130a5a561576..8f0ff42708e6e5d0b80cb39ced42fa139983b0a8 100644 (file)
@@ -30,13 +30,13 @@ awk '{if (NF == 6) \
 else \
         { print $1 " "  $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
 
-cvsversion=`cat ../.patches | \
-    awk -F. '{ \
-        if ($(NF)~/\+$/) \
-           printf(".0"); \
-       else \
-           printf(".%d.(%s)", NF - 3, $(NF)); \
-    }'`
+cvsversion=`cat ../.patches | \
+    awk -F. '{ \
+        if ($(NF)~/\+$/) \
+#          printf(".0"); \
+#      else \
+#          printf(".%s", $(NF)); \
+    }'`
 
 /bin/cat >version.c <<!SUB!THIS!
 /*
@@ -62,47 +62,36 @@ cvsversion=`cat ../.patches | \
  * This file is generated by version.c.SH. Any changes made will go away.
  */
 
-#include "sys.h"
-#include "h.h"
-#include "patchlevel.h"
 #include "version.h"
+#include "patchlevel.h"
 
 const char *generation = "$generation";
 const char *creation = "$creation";
-const char *version = BASE_VERSION PATCH1 "$cvsversion" PATCH2 PATCH3 PATCH4 PATCH5 PATCH6\
-       PATCH7 PATCH8 PATCH9 PATCH10 PATCH11 PATCH12 PATCH13 PATCH14 PATCH15\
-       PATCH16 PATCH17 PATCH18 PATCH19 PATCH20 PATCH21 PATCH22 PATCH23 PATCH24\
-       PATCH25 PATCH26 PATCH27 PATCH28 PATCH29 PATCH30 PATCH31 PATCH32;
+const char *version = BASE_VERSION RELEASE PATCHLEVEL;
 
 const char *infotext[] = {
     "IRC --",
-    "Based on the original code written by Jarkko Oikarinen, version 2.6:",
-    "Copyright 1988, 1989, 1990, 1991 University of Oulu, Computing Center",
+    "This program is free software; see LICENSE in the distribution",
     "",
+    "Based on the original code written by Jarkko Oikarinen, version 2.6:",
     "Wiz         Jarkko Oikarinen         <jto@tolsun.oulu.fi>",
     "",
-    "This program is free software; you can redistribute it and/or",
-    "modify it under the terms of the GNU General Public License as",
-    "published by the Free Software Foundation; either version 2, or",
-    "(at your option) any later version.",
-    "",
-    "The UnderNet code is based upon version 2.8.10.",
-    "The main developers of version 2.7 and 2.8 are:",
-    "",
-    "Avalon      Darren Reed              <avalon@coombs.anu.edu.au>",
-    "msa         Markku Savela            <msa@tel4.tel.vtt.fi>",
-    "Wumpus      Greg Lindahl             <lindahl@pbm.com>",
+    "The main developer of version u2.9 and u2.10 was:",
+    "Run         Carlo Wood               <carlo@runaway.xs4all.nl>",
     "",
-    "The main developer of version u2.9 and u2.10 is:",
+    "The current head developer of the u2.10 source tree is:",
+    "Bleep        Thomas Helvey            <tomh@inxpress.net>",
     "",
-    "Run         Carlo Wood               <carlo@runaway.xs4all.nl>",
+    "Contributors to this release:",
+    "Isomer, Gte-, WildThang, David M, Run, Nemesi",
+    "Debugging and support:",
+    "SeKs, Maniac-, HeKTik, OmniDynmc, Aurorian, Quantum, Jesus",
+    "Special thanks to Angel and Buff for believing in us and putting"
+    "up with frantic late night phone calls"
     "",
     "Thanks goes to all other people who contributed to any version.",
     "A full listing of all coders can be found in doc/Authors in the",
-    "source.  Contributers to version u2.10 can be found on",
-    "http://coder-com.undernet.org/posters.html",
-    "Thanks also to those who provided me with accounts; the kind sys",
-    "admins who let me and others continue to develop IRC.",
+    "source.",
     "",
     "[$sumsserv] [$sumchan] [$sumsbsd] [$sumsuser]",
     "[$sumhash] [$sumsmisc] [$sumircd]",
index 58b8f31e402965e221efded9d39c5dfcac8fb473..0c2b5b4a525144b4c01080ddebdf459917c00cd3 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.c)
  * Copyright (C) 1990 Jarkko Oikarinen and
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id$
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <sys/stat.h>
-#include <utmp.h>
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#include <stdlib.h>
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef USE_SYSLOG
-#include <syslog.h>
-#endif
-#include "h.h"
-#include "struct.h"
-#include "common.h"
-#include "s_serv.h"
+#include "whocmds.h"
+#include "IPcheck.h"
+#include "channel.h"
+#include "client.h"
+#include "hash.h"
+#include "ircd.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
+#include "list.h"
+#include "match.h"
 #include "numeric.h"
-#include "send.h"
+#include "numnicks.h"
+#include "querycmds.h"
+#include "random.h"
+#include "s_bsd.h"
 #include "s_conf.h"
 #include "s_misc.h"
-#include "match.h"
-#include "hash.h"
-#include "s_bsd.h"
-#include "whowas.h"
-#include "list.h"
-#include "s_err.h"
-#include "parse.h"
-#include "ircd.h"
 #include "s_user.h"
+#include "send.h"
+#include "sprintf_irc.h"
+#include "struct.h"
 #include "support.h"
-#include "s_user.h"
-#include "channel.h"
-#include "random.h"
+#include "sys.h"
+#include "userload.h"
 #include "version.h"
+#include "whowas.h"
 #include "msg.h"
-#include "userload.h"
-#include "numnicks.h"
-#include "sprintf_irc.h"
-#include "querycmds.h"
-#include "IPcheck.h"
-
-RCSTAG_CC("$Id$");
-
-/*
- * m_who() 
- * m_who with support routines rewritten by Nemesi, August 1997
- * - Alghoritm have been flattened (no more recursive)
- * - Several bug fixes
- * - Strong performance improvement
- * - Added possibility to have specific fields in the output
- * See readme.who for further details.
- */
-
-/* Macros used only in here by m_who and its support functions */
-
-#define WHOSELECT_OPER 1
-#define WHOSELECT_EXTRA 2
-
-#define WHO_FIELD_QTY 1
-#define WHO_FIELD_CHA 2
-#define WHO_FIELD_UID 4
-#define WHO_FIELD_NIP 8
-#define WHO_FIELD_HOS 16
-#define WHO_FIELD_SER 32
-#define WHO_FIELD_NIC 64
-#define WHO_FIELD_FLA 128
-#define WHO_FIELD_DIS 256
-#define WHO_FIELD_REN 512
-
-#define WHO_FIELD_DEF ( WHO_FIELD_NIC | WHO_FIELD_UID | WHO_FIELD_HOS | WHO_FIELD_SER )
-
-#define IS_VISIBLE_USER(s,ac) ((s==ac) || (!IsInvisible(ac)))
 
-#if defined(SHOW_INVISIBLE_LUSERS) || defined(SHOW_ALL_INVISIBLE_USERS)
-#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac) || ((b & WHOSELECT_EXTRA) && MyConnect(ac) && IsAnOper(s)))
-#else
-#define SEE_LUSER(s, ac, b) (IS_VISIBLE_USER(s, ac))
-#endif
-
-#ifdef SHOW_ALL_INVISIBLE_USERS
-#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b) || ((b & WHOSELECT_EXTRA) && IsOper(s)))
-#else
-#define SEE_USER(s, ac, b) (SEE_LUSER(s, ac, b))
-#endif
-
-#ifdef UNLIMIT_OPER_QUERY
-#define SHOW_MORE(sptr, counter) (IsAnOper(sptr) || (!(counter-- < 0)) )
-#else
-#define SHOW_MORE(sptr, counter) (!(counter-- < 0))
-#endif
-
-#ifdef OPERS_SEE_IN_SECRET_CHANNELS
-#ifdef LOCOP_SEE_IN_SECRET_CHANNELS
-#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && IsAnOper(s)))
-#else
-#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr) || ((b & WHOSELECT_EXTRA) && IsOper(s)))
-#endif
-#else
-#define SEE_CHANNEL(s, chptr, b) (!SecretChannel(chptr))
-#endif
-
-
-/*
- * A little spin-marking utility to tell us wich clients we have already
- * processed and wich not
- */
-static int who_marker = 0;
-static void move_marker(void)
-{
-  if (!++who_marker)
-  {
-    aClient *cptr = client;
-    while (cptr)
-    {
-      cptr->marker = 0;
-      cptr = cptr->next;
-    }
-    who_marker++;
-  }
-}
-#define CheckMark(x, y) ((x == y) ? 0 : (x = y))
-#define Process(cptr) CheckMark(cptr->marker, who_marker)
+#include <arpa/inet.h>        /* inet_ntoa */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 /*
  * The function that actually prints out the WHO reply for a client found
  */
-static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
-    int fields, char *qrt)
+void do_who(struct Client* sptr, struct Client* acptr, struct Channel* repchan,
+            int fields, char* qrt)
 {
-  Reg1 char *p1;
-  Reg2 aChannel *chptr;
+  char *p1;
+  struct Channel *chptr = repchan;
 
   static char buf1[512];
   /* NOTE: with current fields list and sizes this _cannot_ overrun, 
      and also the message finally sent shouldn't ever be truncated */
 
   p1 = buf1;
-  chptr = repchan;
   buf1[1] = '\0';
 
   /* If we don't have a channel and we need one... try to find it,
@@ -170,17 +83,17 @@ static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
   if (!chptr && (!fields || (fields & (WHO_FIELD_CHA | WHO_FIELD_FLA))) &&
       !IsChannelService(acptr))
   {
-    Reg3 Link *lp;
-    for (lp = acptr->user->channel; lp && !chptr; lp = lp->next)
-      if (PubChannel(lp->value.chptr) &&
-         (acptr == sptr || !is_zombie(acptr, chptr)))
-       chptr = lp->value.chptr;
+    struct Membership* chan;
+    for (chan = acptr->user->channel; chan && !chptr; chan = chan->next_channel)
+      if (PubChannel(chan->channel) &&
+          (acptr == sptr || !IsZombie(chan)))
+        chptr = chan->channel;
   }
 
   /* Place the fields one by one in the buffer and send it
      note that fields == NULL means "default query" */
 
-  if (fields & WHO_FIELD_QTY)  /* Query type */
+  if (fields & WHO_FIELD_QTY)   /* Query type */
   {
     *(p1++) = ' ';
     if (BadPtr(qrt))
@@ -191,7 +104,7 @@ static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
 
   if (!fields || (fields & WHO_FIELD_CHA))
   {
-    Reg3 char *p2;
+    char *p2;
     *(p1++) = ' ';
     if ((p2 = (chptr ? chptr->chname : NULL)))
       while ((*p2) && (*(p1++) = *(p2++)));
@@ -201,36 +114,35 @@ static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
 
   if (!fields || (fields & WHO_FIELD_UID))
   {
-    Reg3 char *p2 = acptr->user->username;
+    char *p2 = acptr->user->username;
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
 
   if (fields & WHO_FIELD_NIP)
   {
-    Reg3 char *p2;
-    p2 = inetntoa(acptr->ip);
+    const char* p2 = ircd_ntoa((const char*) &acptr->ip);
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
 
   if (!fields || (fields & WHO_FIELD_HOS))
   {
-    Reg3 char *p2 = acptr->user->host;
+    char *p2 = acptr->user->host;
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
 
   if (!fields || (fields & WHO_FIELD_SER))
   {
-    Reg3 char *p2 = acptr->user->server->name;
+    char *p2 = acptr->user->server->name;
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
 
   if (!fields || (fields & WHO_FIELD_NIC))
   {
-    Reg3 char *p2 = acptr->name;
+    char *p2 = acptr->name;
     *(p1++) = ' ';
     while ((*p2) && (*(p1++) = *(p2++)));
   }
@@ -255,11 +167,11 @@ static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
     if (IsAnOper(sptr))
     {
       if (IsInvisible(acptr))
-       *(p1++) = 'i';
+        *(p1++) = 'i';
       if (SendWallops(acptr))
-       *(p1++) = 'w';
+        *(p1++) = 'w';
       if (SendDebug(acptr))
-       *(p1++) = 'g';
+        *(p1++) = 'g';
     }
   }
 
@@ -267,16 +179,16 @@ static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
   {
     *p1++ = ' ';
     if (!fields)
-      *p1++ = ':';             /* Place colon here for default reply */
+      *p1++ = ':';              /* Place colon here for default reply */
     p1 = sprintf_irc(p1, "%d", acptr->hopcount);
   }
 
   if (!fields || (fields & WHO_FIELD_REN))
   {
-    Reg3 char *p2 = acptr->info;
+    char *p2 = acptr->info;
     *p1++ = ' ';
     if (fields)
-      *p1++ = ':';             /* Place colon here for special reply */
+      *p1++ = ':';              /* Place colon here for special reply */
     while ((*p2) && (*(p1++) = *(p2++)));
   }
 
@@ -288,524 +200,3 @@ static void do_who(aClient *sptr, aClient *acptr, aChannel *repchan,
       me.name, sptr->name, ++p1);
 }
 
-/*
- *  m_who
- *
- *  parv[0] = sender prefix
- *  parv[1] = nickname mask list
- *  parv[2] = additional selection flag, only 'o' for now.
- *            and %flags to specify what fields to output
- *            plus a ,querytype if the t flag is specified
- *            so the final thing will be like o%tnchu,777
- *  parv[3] = _optional_ parameter that overrides parv[1]
- *            This can be used as "/quote who foo % :The Black Hacker
- *            to find me, parv[3] _can_ contain spaces !.
- */
-
-int m_who(aClient *UNUSED(cptr), aClient *sptr, int parc, char *parv[])
-{
-  Reg1 char *mask;             /* The mask we are looking for              */
-  Reg2 char ch;                        /* Scratch char register                    */
-  Reg3 Link *lp, *lp2;
-  Reg4 aChannel *chptr;                /* Channel to show                          */
-  Reg5 aClient *acptr;         /* Client to show                           */
-
-  int bitsel;                  /* Mask of selectors to apply               */
-  int matchsel;                        /* Wich fields the match should apply on    */
-  int counter;                 /* Query size counter,
-                                  initially used to count fields           */
-  int commas;                  /* Does our mask contain any comma ?
-                                  If so is a list..                        */
-  int fields;                  /* Mask of fields to show                   */
-  int isthere = 0;             /* When this set the user is member of chptr */
-  char *nick;                  /* Single element extracted from
-                                  the mask list                            */
-  char *p;                     /* Scratch char pointer                     */
-  char *qrt;                   /* Pointer to the query type                */
-  static char mymask[512];     /* To save the mask before corrupting it    */
-
-  /* Let's find where is our mask, and if actually contains something */
-  mask = ((parc > 1) ? parv[1] : NULL);
-  if (parc > 3 && parv[3])
-    mask = parv[3];
-  if (mask && ((mask[0] == '\0') ||
-      (mask[1] == '\0' && ((mask[0] == '0') || (mask[0] == '*')))))
-    mask = NULL;
-
-  /* Evaluate the flags now, we consider the second parameter 
-     as "matchFlags%fieldsToInclude,querytype"           */
-  bitsel = fields = counter = matchsel = 0;
-  qrt = NULL;
-  if (parc > 2 && parv[2] && *parv[2])
-  {
-    p = parv[2];
-    while (((ch = *(p++))) && (ch != '%') && (ch != ','))
-      switch (ch)
-      {
-       case 'o':
-       case 'O':
-         bitsel |= WHOSELECT_OPER;
-         continue;
-       case 'x':
-       case 'X':
-         bitsel |= WHOSELECT_EXTRA;
-#ifdef WPATH
-         if (IsAnOper(sptr))
-           write_log(WPATH, "# " TIME_T_FMT " %s!%s@%s WHO %s %s\n",
-               now, sptr->name, sptr->user->username, sptr->user->host,
-               (BadPtr(parv[3]) ? parv[1] : parv[3]), parv[2]);
-#endif /* WPATH */
-         continue;
-       case 'n':
-       case 'N':
-         matchsel |= WHO_FIELD_NIC;
-         continue;
-       case 'u':
-       case 'U':
-         matchsel |= WHO_FIELD_UID;
-         continue;
-       case 'h':
-       case 'H':
-         matchsel |= WHO_FIELD_HOS;
-         continue;
-       case 'i':
-       case 'I':
-         matchsel |= WHO_FIELD_NIP;
-         continue;
-       case 's':
-       case 'S':
-         matchsel |= WHO_FIELD_SER;
-         continue;
-       case 'r':
-       case 'R':
-         matchsel |= WHO_FIELD_REN;
-         continue;
-      }
-    if (ch == '%')
-      while ((ch = *p++) && (ch != ','))
-      {
-       counter++;
-       switch (ch)
-       {
-         case 'c':
-         case 'C':
-           fields |= WHO_FIELD_CHA;
-           break;
-         case 'd':
-         case 'D':
-           fields |= WHO_FIELD_DIS;
-           break;
-         case 'f':
-         case 'F':
-           fields |= WHO_FIELD_FLA;
-           break;
-         case 'h':
-         case 'H':
-           fields |= WHO_FIELD_HOS;
-           break;
-         case 'i':
-         case 'I':
-           fields |= WHO_FIELD_NIP;
-           break;
-         case 'n':
-         case 'N':
-           fields |= WHO_FIELD_NIC;
-           break;
-         case 'r':
-         case 'R':
-           fields |= WHO_FIELD_REN;
-           break;
-         case 's':
-         case 'S':
-           fields |= WHO_FIELD_SER;
-           break;
-         case 't':
-         case 'T':
-           fields |= WHO_FIELD_QTY;
-           break;
-         case 'u':
-         case 'U':
-           fields |= WHO_FIELD_UID;
-           break;
-         default:
-           break;
-       }
-      };
-    if (ch)
-      qrt = p;
-  }
-
-  if (!matchsel)
-    matchsel = WHO_FIELD_DEF;
-  if (!fields)
-    counter = 7;
-
-  if (qrt && (fields & WHO_FIELD_QTY))
-  {
-    p = qrt;
-    if (!((*p > '9') || (*p < '0')))
-      p++;
-    if (!((*p > '9') || (*p < '0')))
-      p++;
-    if (!((*p > '9') || (*p < '0')))
-      p++;
-    *p = '\0';
-  }
-  else
-    qrt = NULL;
-
-  /* I'd love to add also a check on the number of matches fields per time */
-  counter = (2048 / (counter + 4));
-  if (mask && (strlen(mask) > 510))
-    mask[510] = '\0';
-  move_marker();
-  commas = (mask && strchr(mask, ','));
-
-  /* First treat mask as a list of plain nicks/channels */
-  if (mask)
-  {
-    strcpy(mymask, mask);
-    for (p = NULL, nick = strtoken(&p, mymask, ","); nick;
-       nick = strtoken(&p, NULL, ","))
-    {
-      if (IsChannelName(nick) && (chptr = FindChannel(nick)))
-      {
-       isthere = (IsMember(sptr, chptr) != NULL);
-       if (isthere || SEE_CHANNEL(sptr, chptr, bitsel))
-       {
-         for (lp = chptr->members; lp; lp = lp->next)
-         {
-           acptr = lp->value.cptr;
-           if ((bitsel & WHOSELECT_OPER) && !(IsAnOper(acptr)))
-             continue;
-           if ((acptr != sptr) && (lp->flags & CHFL_ZOMBIE))
-             continue;
-           if (!(isthere || (SEE_USER(sptr, acptr, bitsel))))
-             continue;
-           if (!Process(acptr))        /* This can't be moved before other checks */
-             continue;
-           if (!(isthere || (SHOW_MORE(sptr, counter))))
-             break;
-           do_who(sptr, acptr, chptr, fields, qrt);
-         }
-       }
-      }
-      else
-      {
-       if ((acptr = FindUser(nick)) &&
-           ((!(bitsel & WHOSELECT_OPER)) || IsAnOper(acptr)) &&
-           Process(acptr) && SHOW_MORE(sptr, counter))
-       {
-         do_who(sptr, acptr, NULL, fields, qrt);
-       }
-      }
-    }
-  }
-
-  /* If we didn't have any comma in the mask treat it as a
-     real mask and try to match all relevant fields */
-  if (!(commas || (counter < 1)))
-  {
-    int minlen, cset;
-    static struct in_mask imask;
-    if (mask)
-    {
-      matchcomp(mymask, &minlen, &cset, mask);
-      if (matchcompIP(&imask, mask))
-       matchsel &= ~WHO_FIELD_NIP;
-      if ((minlen > NICKLEN) || !(cset & NTL_IRCNK))
-       matchsel &= ~WHO_FIELD_NIC;
-      if ((matchsel & WHO_FIELD_SER) &&
-         ((minlen > HOSTLEN) || (!(cset & NTL_IRCHN))
-         || (!markMatchexServer(mymask, minlen))))
-       matchsel &= ~WHO_FIELD_SER;
-      if ((minlen > USERLEN) || !(cset & NTL_IRCUI))
-       matchsel &= ~WHO_FIELD_UID;
-      if ((minlen > HOSTLEN) || !(cset & NTL_IRCHN))
-       matchsel &= ~WHO_FIELD_HOS;
-    }
-
-    /* First of all loop through the clients in common channels */
-    if ((!(counter < 1)) && matchsel)
-      for (lp = sptr->user->channel; lp; lp = lp->next)
-       for (chptr = lp->value.chptr, lp2 = chptr->members; lp2;
-           lp2 = lp2->next)
-       {
-         acptr = lp2->value.cptr;
-         if (!(IsUser(acptr) && Process(acptr)))
-           continue;           /* Now Process() is at the beginning, if we fail
-                                  we'll never have to show this acptr in this query */
-         if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
-           continue;
-         if ((mask) &&
-             ((!(matchsel & WHO_FIELD_NIC))
-             || matchexec(acptr->name, mymask, minlen))
-             && ((!(matchsel & WHO_FIELD_UID))
-             || matchexec(acptr->user->username, mymask, minlen))
-             && ((!(matchsel & WHO_FIELD_SER))
-             || (!(acptr->user->server->flags & FLAGS_MAP)))
-             && ((!(matchsel & WHO_FIELD_HOS))
-             || matchexec(acptr->user->host, mymask, minlen))
-             && ((!(matchsel & WHO_FIELD_REN))
-             || matchexec(acptr->info, mymask, minlen))
-             && ((!(matchsel & WHO_FIELD_NIP))
-             || ((((acptr->ip.s_addr & imask.mask.s_addr) !=
-             imask.bits.s_addr)) || (imask.fall
-             && matchexec(inet_ntoa(acptr->ip), mymask, minlen)))))
-           continue;
-         if (!SHOW_MORE(sptr, counter))
-           break;
-         do_who(sptr, acptr, chptr, fields, qrt);
-       }
-
-    /* Loop through all clients :-\, if we still have something to match to 
-       and we can show more clients */
-    if ((!(counter < 1)) && matchsel)
-      for (acptr = me.prev; acptr; acptr = acptr->prev)
-      {
-       if (!(IsUser(acptr) && Process(acptr)))
-         continue;
-       if ((bitsel & WHOSELECT_OPER) && !IsAnOper(acptr))
-         continue;
-       if (!(SEE_USER(sptr, acptr, bitsel)))
-         continue;
-       if ((mask) &&
-           ((!(matchsel & WHO_FIELD_NIC))
-           || matchexec(acptr->name, mymask, minlen))
-           && ((!(matchsel & WHO_FIELD_UID))
-           || matchexec(acptr->user->username, mymask, minlen))
-           && ((!(matchsel & WHO_FIELD_SER))
-           || (!(acptr->user->server->flags & FLAGS_MAP)))
-           && ((!(matchsel & WHO_FIELD_HOS))
-           || matchexec(acptr->user->host, mymask, minlen))
-           && ((!(matchsel & WHO_FIELD_REN))
-           || matchexec(acptr->info, mymask, minlen))
-           && ((!(matchsel & WHO_FIELD_NIP))
-           || ((((acptr->ip.s_addr & imask.mask.s_addr) != imask.bits.s_addr))
-           || (imask.fall
-           && matchexec(inet_ntoa(acptr->ip), mymask, minlen)))))
-         continue;
-       if (!SHOW_MORE(sptr, counter))
-         break;
-       do_who(sptr, acptr, NULL, fields, qrt);
-      }
-  }
-
-  /* Make a clean mask suitable to be sent in the "end of" */
-  if (mask && (p = strchr(mask, ' ')))
-    *p = '\0';
-  sendto_one(sptr, rpl_str(RPL_ENDOFWHO),
-      me.name, parv[0], BadPtr(mask) ? "*" : mask);
-
-  /* Notify the user if we decided that his query was too long */
-  if (counter < 0)
-    sendto_one(sptr, err_str(ERR_QUERYTOOLONG), me.name, parv[0], "WHO");
-
-  return 0;
-}
-
-#define MAX_WHOIS_LINES 50
-
-/*
- * m_whois
- *
- * parv[0] = sender prefix
- * parv[1] = nickname masklist
- *
- * or
- *
- * parv[1] = target server
- * parv[2] = nickname masklist
- */
-int m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  Reg2 Link *lp;
-  Reg3 anUser *user;
-  aClient *acptr, *a2cptr;
-  aChannel *chptr;
-  char *nick, *tmp, *name;
-  char *p = NULL;
-  int found, len, mlen, total;
-  static char buf[512];
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
-    return 0;
-  }
-
-  if (parc > 2)
-  {
-    aClient *acptr;
-    /* For convenience: Accept a nickname as first parameter, by replacing
-       it with the correct servername - as is needed by hunt_server() */
-    if (MyUser(sptr) && (acptr = FindUser(parv[1])))
-      parv[1] = acptr->user->server->name;
-    if (hunt_server(0, cptr, sptr, ":%s WHOIS %s :%s", 1, parc, parv) !=
-       HUNTED_ISME)
-      return 0;
-    parv[1] = parv[2];
-  }
-
-  total = 0;
-  for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL)
-  {
-    int invis, showperson, member, wilds;
-
-    found = 0;
-    collapse(nick);
-    wilds = (strchr(nick, '?') || strchr(nick, '*'));
-    /* Do a hash lookup if the nick does not contain wilds */
-    if (wilds)
-    {
-      /*
-       * We're no longer allowing remote users to generate requests with wildcards.
-       */
-      if (!MyConnect(sptr))
-       continue;
-      for (acptr = client; (acptr = next_client(acptr, nick));
-         acptr = acptr->next)
-      {
-       if (!IsRegistered(acptr) || IsServer(acptr) || IsPing(acptr))
-         continue;
-       /*
-        * I'm always last :-) and acptr->next == NULL!!
-        */
-       if (IsMe(acptr))
-         break;
-       /*
-        * '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;
-        */
-       user = acptr->user;
-       name = (!*acptr->name) ? "?" : acptr->name;
-
-       invis = acptr != sptr && IsInvisible(acptr);
-       member = (user && user->channel) ? 1 : 0;
-       showperson = (wilds && !invis && !member) || !wilds;
-       if (user)
-         for (lp = user->channel; lp; lp = lp->next)
-         {
-           chptr = lp->value.chptr;
-           member = IsMember(sptr, chptr) ? 1 : 0;
-           if (invis && !member)
-             continue;
-           if (is_zombie(acptr, chptr))
-             continue;
-           if (member || (!invis && PubChannel(chptr)))
-           {
-             showperson = 1;
-             break;
-           }
-           if (!invis && HiddenChannel(chptr) && !SecretChannel(chptr))
-             showperson = 1;
-         }
-       if (!showperson)
-         continue;
-
-       if (user)
-       {
-         a2cptr = user->server;
-         sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
-             parv[0], name, user->username, user->host, acptr->info);
-       }
-       else
-       {
-         a2cptr = &me;
-         sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
-             parv[0], name, "<unknown>", "<unknown>", "<unknown>");
-       }
-
-       found = 1;
-
-      exact_match:
-       if (user && !IsChannelService(acptr))
-       {
-         mlen = strlen(me.name) + strlen(parv[0]) + 12 + strlen(name);
-         for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next)
-         {
-           chptr = lp->value.chptr;
-           if (ShowChannel(sptr, chptr) &&
-               (acptr == sptr || !is_zombie(acptr, chptr)))
-           {
-             if (len + strlen(chptr->chname) + mlen > BUFSIZE - 5)
-             {
-               sendto_one(sptr, ":%s %d %s %s :%s",
-                   me.name, RPL_WHOISCHANNELS, parv[0], name, buf);
-               *buf = '\0';
-               len = 0;
-             }
-             if (IsDeaf(acptr))
-               *(buf + len++) = '-';
-             if (is_chan_op(acptr, chptr))
-               *(buf + len++) = '@';
-             else if (has_voice(acptr, chptr))
-               *(buf + len++) = '+';
-             else if (is_zombie(acptr, chptr))
-               *(buf + len++) = '!';
-             if (len)
-               *(buf + len) = '\0';
-             strcpy(buf + len, chptr->chname);
-             len += strlen(chptr->chname);
-             strcat(buf + len, " ");
-             len++;
-           }
-         }
-         if (buf[0] != '\0')
-           sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
-               me.name, parv[0], name, buf);
-       }
-
-       sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name,
-           parv[0], name, a2cptr->name, a2cptr->info);
-
-       if (user)
-       {
-         if (user->away)
-           sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
-               parv[0], name, user->away);
-
-         if (IsAnOper(acptr))
-           sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
-               me.name, parv[0], name);
-
-         if (MyConnect(acptr))
-           sendto_one(sptr, rpl_str(RPL_WHOISIDLE), me.name,
-               parv[0], name, now - user->last, acptr->firsttime);
-       }
-       if (found == 2 || total++ >= MAX_WHOIS_LINES)
-         break;
-      }
-    }
-    else
-    {
-      /* No wildcards */
-      if ((acptr = FindUser(nick)))
-      {
-       found = 2;              /* Make sure we exit the loop after passing it once */
-       user = acptr->user;
-       name = (!*acptr->name) ? "?" : acptr->name;
-       a2cptr = user->server;
-       sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
-           parv[0], name, user->username, user->host, acptr->info);
-       goto exact_match;
-      }
-    }
-    if (!found)
-      sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick);
-    if (p)
-      p[-1] = ',';
-    if (!MyConnect(sptr) || total >= MAX_WHOIS_LINES)
-      break;
-  }
-  sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
-
-  return 0;
-}
index a893490e02d32c56c29192274a8cb8729269408b..ee0050043999bf9b48decd6927d9f445eb08c3c9 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * IRC - Internet Relay Chat, ircd/whowas.c
  * Copyright (C) 1990 Markku Savela
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
+ *
  * --- avalon --- 6th April 1992
  * rewritten to scrap linked lists and use a table of structures which
  * is referenced like a circular loop. Should be faster and more efficient.
- */
-
-/*
+ *
  * --- comstud --- 25th March 1997
  * Everything rewritten from scratch.  Avalon's code was bad.  My version
  * is faster and more efficient.  No more hangs on /squits and you can
  * safely raise NICKNAMEHISTORYLENGTH to a higher value without hurting
  * performance.
- */
-
-/*
+ *
  * --- comstud --- 5th August 1997
  * Fixed for Undernet..
- */
-
-/*
+ *
  * --- Run --- 27th August 1997
  * Speeded up the code, added comments.
+ *
+ * $Id$
  */
-
-#include "sys.h"
-#include <stdlib.h>
-#include "common.h"
-#include "h.h"
-#include "struct.h"
-#include "numeric.h"
-#include "send.h"
-#include "s_misc.h"
-#include "s_err.h"
 #include "whowas.h"
+#include "client.h"
 #include "ircd.h"
+#include "ircd_alloc.h"
+#include "ircd_chattr.h"
+#include "ircd_string.h"
 #include "list.h"
+#include "numeric.h"
+#include "s_misc.h"
 #include "s_user.h"
+#include "send.h"
+#include "struct.h"
 #include "support.h"
+#include "sys.h"
+#include "msg.h"
 
-RCSTAG_CC("$Id$");
-
-static aWhowas whowas[NICKNAMEHISTORYLENGTH];
-static aWhowas *whowashash[WW_MAX];
-static aWhowas *whowas_next = whowas;
+#include <assert.h>
+#include <stdlib.h>
 
-static unsigned int hash_whowas_name(register const char *name);
 
-extern char *canonize(char *);
+static struct Whowas  whowas[NICKNAMEHISTORYLENGTH];
+static struct Whowas* whowas_next = whowas;
+struct Whowas* whowashash[WW_MAX];
 
 /*
  * Since the introduction of numeric nicks (at least for upstream messages,
@@ -86,7 +77,7 @@ extern char *canonize(char *);
  * But - it was written anyway.  So lets look at the structure of the
  * whowas history now:
  *
- * We still have a static table of 'aWhowas' structures in which we add
+ * We still have a static table of 'struct Whowas' structures in which we add
  * new nicks (plus info) as in a rotating buffer.  We keep a global pointer
  * `whowas_next' that points to the next entry to be overwritten - or to
  * the oldest entry in the table (which is the same).
@@ -140,8 +131,8 @@ extern char *canonize(char *);
  */
 
 typedef union {
-  aWhowas *newww;
-  aWhowas *oldww;
+  struct Whowas *newww;
+  struct Whowas *oldww;
 } Current;
 
 #define WHOWAS_UNUSED ((unsigned int)-1)
@@ -155,55 +146,44 @@ typedef union {
  * If the entry used was already in use, then this entry is
  * freed (lost).
  */
-void add_history(aClient *cptr, int still_on)
+void add_history(struct Client *cptr, int still_on)
 {
-  register Current ww;
+  Current ww;
   ww.newww = whowas_next;
 
   /* If this entry has already been used, remove it from the lists */
   if (ww.newww->hashv != WHOWAS_UNUSED)
   {
-    if (ww.oldww->online)      /* No need to update cnext/cprev when offline! */
+    if (ww.oldww->online)       /* No need to update cnext/cprev when offline! */
     {
       /* Remove ww.oldww from the linked list with the same `online' pointers */
       *ww.oldww->cprevnextp = ww.oldww->cnext;
 
-      if (ww.oldww->cnext)
-       MyCoreDump;
-#if 0
-      if (ww.oldww->cnext)     /* Never true, we always catch the
-                                  oldwwest nick of this client first */
-       ww.oldww->cnext->cprevnextp = ww.oldww->cprevnextp;
-#endif
+      assert(0 == ww.oldww->cnext);
 
     }
     /* Remove ww.oldww from the linked list with the same `hashv' */
     *ww.oldww->hprevnextp = ww.oldww->hnext;
 
-    if (ww.oldww->hnext)
-      MyCoreDump;
-#if 0
-    if (ww.oldww->hnext)
-      ww.oldww->hnext->hprevnextp = ww.oldww->hprevnextp;
-#endif
+    assert(0 == ww.oldww->hnext);
 
     if (ww.oldww->name)
-      RunFree(ww.oldww->name);
+      MyFree(ww.oldww->name);
     if (ww.oldww->username)
-      RunFree(ww.oldww->username);
+      MyFree(ww.oldww->username);
     if (ww.oldww->hostname)
-      RunFree(ww.oldww->hostname);
+      MyFree(ww.oldww->hostname);
     if (ww.oldww->servername)
-      RunFree(ww.oldww->servername);
+      MyFree(ww.oldww->servername);
     if (ww.oldww->realname)
-      RunFree(ww.oldww->realname);
+      MyFree(ww.oldww->realname);
     if (ww.oldww->away)
-      RunFree(ww.oldww->away);
+      MyFree(ww.oldww->away);
   }
 
   /* Initialize aWhoWas struct `newww' */
   ww.newww->hashv = hash_whowas_name(cptr->name);
-  ww.newww->logoff = now;
+  ww.newww->logoff = CurrentTime;
   DupString(ww.newww->name, cptr->name);
   DupString(ww.newww->username, cptr->user->username);
   DupString(ww.newww->hostname, cptr->user->host);
@@ -216,19 +196,19 @@ void add_history(aClient *cptr, int still_on)
     ww.newww->away = NULL;
 
   /* Update/initialize online/cnext/cprev: */
-  if (still_on)                        /* User just changed nicknames */
+  if (still_on)                 /* User just changed nicknames */
   {
     ww.newww->online = cptr;
-    /* Add aWhowas struct `newww' to start of 'online list': */
+    /* Add struct Whowas struct `newww' to start of 'online list': */
     if ((ww.newww->cnext = cptr->whowas))
       ww.newww->cnext->cprevnextp = &ww.newww->cnext;
     ww.newww->cprevnextp = &cptr->whowas;
     cptr->whowas = ww.newww;
   }
-  else                         /* User quitting */
+  else                          /* User quitting */
     ww.newww->online = NULL;
 
-  /* Add aWhowas struct `newww' to start of 'hashv list': */
+  /* Add struct Whowas struct `newww' to start of 'hashv list': */
   if ((ww.newww->hnext = whowashash[ww.newww->hashv]))
     ww.newww->hnext->hprevnextp = &ww.newww->hnext;
   ww.newww->hprevnextp = &whowashash[ww.newww->hashv];
@@ -245,9 +225,9 @@ void add_history(aClient *cptr, int still_on)
  * Client `cptr' signed off: Set all `online' pointers
  * corresponding to this client to NULL.
  */
-void off_history(const aClient *cptr)
+void off_history(const struct Client *cptr)
 {
-  aWhowas *temp;
+  struct Whowas *temp;
 
   for (temp = cptr->whowas; temp; temp = temp->cnext)
     temp->online = NULL;
@@ -263,13 +243,13 @@ void off_history(const aClient *cptr)
  * nicks for "upstream" messages in ircu2.10, this is only used for
  * looking up non-existing nicks in client->server messages.
  */
-aClient *get_history(const char *nick, time_t timelimit)
+struct Client *get_history(const char *nick, time_t timelimit)
 {
-  aWhowas *temp = whowashash[hash_whowas_name(nick)];
-  timelimit = now - timelimit;
+  struct Whowas *temp = whowashash[hash_whowas_name(nick)];
+  timelimit = CurrentTime - timelimit;
 
   for (; temp; temp = temp->hnext)
-    if (!strCasediff(nick, temp->name) && temp->logoff > timelimit)
+    if (0 == ircd_strcmp(nick, temp->name) && temp->logoff > timelimit)
       return temp->online;
 
   return NULL;
@@ -277,8 +257,8 @@ aClient *get_history(const char *nick, time_t timelimit)
 
 void count_whowas_memory(int *wwu, size_t *wwum, int *wwa, size_t *wwam)
 {
-  register aWhowas *tmp;
-  register int i;
+  struct Whowas *tmp;
+  int i;
   int u = 0, a = 0;
   size_t um = 0, am = 0;
 
@@ -292,8 +272,8 @@ void count_whowas_memory(int *wwu, size_t *wwum, int *wwa, size_t *wwam)
       um += (strlen(tmp->servername) + 1);
       if (tmp->away)
       {
-       a++;
-       am += (strlen(tmp->away) + 1);
+        a++;
+        am += (strlen(tmp->away) + 1);
       }
     }
 
@@ -303,84 +283,24 @@ void count_whowas_memory(int *wwu, size_t *wwum, int *wwa, size_t *wwam)
   *wwam = am;
 }
 
-/*
- * m_whowas
- *
- * parv[0] = sender prefix
- * parv[1] = nickname queried
- * parv[2] = maximum returned items (optional, default is unlimitted)
- * parv[3] = remote server target (Opers only, max returned items 20)
- */
-int m_whowas(aClient *cptr, aClient *sptr, int parc, char *parv[])
-{
-  register aWhowas *temp;
-  register int cur = 0;
-  int max = -1, found = 0;
-  char *p, *nick, *s;
-
-  if (parc < 2)
-  {
-    sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
-    return 0;
-  }
-  if (parc > 2)
-    max = atoi(parv[2]);
-  if (parc > 3)
-    if (hunt_server(1, cptr, sptr, ":%s WHOWAS %s %s :%s", 3, parc, parv))
-      return 0;
-
-  parv[1] = canonize(parv[1]);
-  if (!MyConnect(sptr) && (max > 20))
-    max = 20;                  /* Set max replies at 20 */
-  for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL)
-  {
-    /* Search through bucket, finding all nicknames that match */
-    found = 0;
-    for (temp = whowashash[hash_whowas_name(nick)]; temp; temp = temp->hnext)
-    {
-      if (!strCasediff(nick, temp->name))
-      {
-       sendto_one(sptr, rpl_str(RPL_WHOWASUSER),
-           me.name, parv[0], temp->name, temp->username,
-           temp->hostname, temp->realname);
-       sendto_one(sptr, rpl_str(RPL_WHOISSERVER), me.name, parv[0],
-           temp->name, temp->servername, myctime(temp->logoff));
-       if (temp->away)
-         sendto_one(sptr, rpl_str(RPL_AWAY),
-             me.name, parv[0], temp->name, temp->away);
-       cur++;
-       found++;
-      }
-      if (max >= 0 && cur >= max)
-       break;
-    }
-    if (!found)
-      sendto_one(sptr, err_str(ERR_WASNOSUCHNICK), me.name, parv[0], nick);
-    /* To keep parv[1] intact for ENDOFWHOWAS */
-    if (p)
-      p[-1] = ',';
-  }
-  sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]);
-  return 0;
-}
 
 void initwhowas(void)
 {
-  register int i;
+  int i;
 
   for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
     whowas[i].hashv = WHOWAS_UNUSED;
 }
 
-static unsigned int hash_whowas_name(register const char *name)
+unsigned int hash_whowas_name(const char *name)
 {
-  register unsigned int hash = 0;
-  register unsigned int hash2 = 0;
-  register char lower;
+  unsigned int hash = 0;
+  unsigned int hash2 = 0;
+  unsigned char lower;
 
   do
   {
-    lower = toLower(*name);
+    lower = ToLower(*name);
     hash = (hash << 1) + lower;
     hash2 = (hash2 >> 1) + lower;
   }
@@ -389,3 +309,4 @@ static unsigned int hash_whowas_name(register const char *name)
   return ((hash & WW_MAX_INITIAL_MASK) << BITS_PER_COL) +
       (hash2 & BITS_PER_COL_MASK);
 }
+
diff --git a/tools/autodoc.py b/tools/autodoc.py
new file mode 100644 (file)
index 0000000..e95f563
--- /dev/null
@@ -0,0 +1,70 @@
+#
+# Structure AutoDocumentator for ircu.
+# 26/02/2000 --Gte
+#
+# Creates a 'structs.html', containing HTML Table definitions
+# for all structures encountered in *.h in the current directory.
+#
+# $Id: autodoc.py,v 1.1 2000-03-18 05:20:30 bleep Exp $
+
+import string, fnmatch, os
+
+def parse(filename):
+       OutFile = open('structs.html', 'a')
+       OutFile.write("<B><H2>"+filename+"</H2>")
+       stage = 1
+       try:
+               IncFile = open(filename, 'r')
+               line = IncFile.readline()
+       
+               while line != "": 
+                       line = string.replace(line,"\n","") # Stript out LF's.
+                       splitline = string.split(line, " ")
+                       try:
+                               if ((stage == 2) & (splitline[0] == "};")):
+                                       OutFile.write("</TABLE><P>"+"\n")
+                                       stage = 1
+                               if (stage == 2):
+                                       # Begin reading member information.
+                                       declr = string.split(string.strip(line), ";", 1)
+                                       comment = string.replace(declr[1], "*", "")
+                                       comment = string.replace(comment, "/", "")
+       
+                                       OutFile.write("<tr>\n")
+                                       OutFile.write("<td WIDTH=\"22%\">"+string.strip(declr[0])+"</td>\n")
+                                       if (declr[1][-1] == "/"):
+                                               OutFile.write("<td WIDTH=\"78%\">"+string.strip(comment)+"</td>\n")
+                                       else:
+                                               # Loop until end of comment string.
+                                               while (declr[-1] != "/"):
+                                                       line = IncFile.readline()
+                                                       line = string.replace(line,"\n","") # Stript out LF's.
+                                                       declr = string.strip(line)
+                                                       comment = comment + line
+                                               comment = string.replace(comment, "*", "")
+                                               comment = string.replace(comment, "/", "")
+                                               OutFile.write("<td WIDTH=\"78%\">"+string.strip(comment)+"</td>\n")
+                                       OutFile.write("</tr>\n")                                                
+       
+                               if ((splitline[0] == "struct") & (splitline[2] == "{") & (stage == 1)):
+                                       # We've found a "Standard" structure definition.
+                                       OutFile.write("Structure table for: \"<B>"+splitline[1]+"</B>\"<P>\n")
+                                       OutFile.write("<table BORDER CELLSPACING=0 CELLPADDING=2 WIDTH=\"100%\" ><tr><td VALIGN=TOP WIDTH=\"22%\"><b>Variable</b></td><td VALIGN=TOP WIDTH=\"78%\"><b>Description</b></td></tr>")
+                                       # Now, carry on until we encounter a "};".
+                                       stage = 2
+                       except IndexError:
+                               pass
+                       line = IncFile.readline()
+       
+               IncFile.close
+               OutFile.write("<HR>")
+       
+       except IOError:
+               print("** Error, File does not exist.") 
+       OutFile.close
+
+files = os.listdir(".")
+files.sort()
+for file in files:
+       if (fnmatch.fnmatch(file, "*.h")):
+               parse(file)
diff --git a/tools/untabify b/tools/untabify
new file mode 100644 (file)
index 0000000..6a48b63
--- /dev/null
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+#
+# untabify - convert tabs to spaces
+#
+# $Id: untabify,v 1.1 2000-03-18 05:20:30 bleep Exp $
+use Text::Tabs;
+$tabstop = 8;
+while (<>) { print expand($_) }
+