]> jfr.im git - irc/unrealircd/unrealircd.git/commitdiff
Import of Unreal3.0 (STABLE)
authorcmunk <redacted>
Mon, 28 Feb 2000 22:45:44 +0000 (22:45 +0000)
committercmunk <redacted>
Mon, 28 Feb 2000 22:45:44 +0000 (22:45 +0000)
176 files changed:
.CHANGES.NEW [new file with mode: 0644]
.NEW_CONFIG [new file with mode: 0644]
CREDITS.potential [new file with mode: 0644]
Changes [new file with mode: 0644]
Config [new file with mode: 0755]
Donation [new file with mode: 0644]
INSTALL [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile.dist [new file with mode: 0644]
READTHIS.NOW [new file with mode: 0644]
TODO [new file with mode: 0644]
TSpre.doc [new file with mode: 0644]
Unreal.nfo [new file with mode: 0644]
bsdinstall [new file with mode: 0755]
crypt/Makefile [new file with mode: 0644]
crypt/README [new file with mode: 0644]
crypt/crypter [new file with mode: 0644]
crypt/mkpasswd.c [new file with mode: 0644]
doc/ADD-TO-IRCRC [new file with mode: 0644]
doc/Authors [new file with mode: 0644]
doc/Crule.readme [new file with mode: 0644]
doc/Elite.Changes [new file with mode: 0644]
doc/History/19.mu1-New [new file with mode: 0644]
doc/History/2.8-New [new file with mode: 0644]
doc/History/Advertisement [new file with mode: 0644]
doc/History/Etiquette [new file with mode: 0644]
doc/History/README.patches [new file with mode: 0644]
doc/INSTALL [new file with mode: 0644]
doc/Manual [new file with mode: 0644]
doc/Operators [new file with mode: 0644]
doc/conf.doc [new file with mode: 0644]
doc/example.conf [new file with mode: 0644]
doc/faq [new file with mode: 0644]
doc/irc.1 [new file with mode: 0644]
doc/ircd.8 [new file with mode: 0644]
doc/m4macros [new file with mode: 0644]
doc/server-compile-guide [new file with mode: 0644]
doc/tao.of.irc [new file with mode: 0644]
doc/unrealircd.doc [new file with mode: 0644]
dynconf [new file with mode: 0644]
extras/extras.txt [new file with mode: 0644]
extras/tsp/Makefile [new file with mode: 0644]
extras/tsp/README [new file with mode: 0644]
extras/tsp/README.sscript [new file with mode: 0644]
extras/tsp/socker.c [new file with mode: 0644]
extras/tsp/sscript-lib.doc [new file with mode: 0644]
extras/tsp/sscript.c [new file with mode: 0644]
extras/tsp/sscript.h [new file with mode: 0644]
extras/tsp/tsp-client.c [new file with mode: 0644]
extras/tsp/tsp-server [new file with mode: 0755]
extras/tsp/tsp-server-run.c [new file with mode: 0644]
include/channel.h [new file with mode: 0644]
include/cio.h [new file with mode: 0644]
include/ciofunc.h [new file with mode: 0644]
include/class.h [new file with mode: 0644]
include/common.h [new file with mode: 0644]
include/config.h [new file with mode: 0644]
include/dbuf.h [new file with mode: 0644]
include/dynconf.h [new file with mode: 0644]
include/fdlist.h [new file with mode: 0644]
include/h.h [new file with mode: 0644]
include/hash.h [new file with mode: 0644]
include/inet.h [new file with mode: 0644]
include/license.h [new file with mode: 0644]
include/msg.h [new file with mode: 0644]
include/nameser.h [new file with mode: 0644]
include/numeric.h [new file with mode: 0644]
include/relinfo.h [new file with mode: 0644]
include/res.h [new file with mode: 0644]
include/resolv.h [new file with mode: 0644]
include/resource.h [new file with mode: 0644]
include/sjoin.h [new file with mode: 0644]
include/sock.h [new file with mode: 0644]
include/stamp.h [new file with mode: 0644]
include/struct.h [new file with mode: 0644]
include/sys.h [new file with mode: 0644]
include/userload.h [new file with mode: 0644]
include/version.h [new file with mode: 0644]
include/whowas.h [new file with mode: 0644]
include/win32/settings.h [new file with mode: 0644]
include/win32/setup.h [new file with mode: 0644]
ircd [new file with mode: 0755]
ircdcron/ircd.cron [new file with mode: 0755]
ircdcron/ircdchk [new file with mode: 0755]
ircdreg [new file with mode: 0755]
killircd [new file with mode: 0755]
makeconf [new file with mode: 0755]
makefile.win32 [new file with mode: 0644]
networks/972-scripterz.network [new file with mode: 0644]
networks/altirc.network [new file with mode: 0644]
networks/bunker7.network [new file with mode: 0644]
networks/digitalirc.network [new file with mode: 0644]
networks/dragonwings.network [new file with mode: 0644]
networks/fireirc.network [new file with mode: 0644]
networks/global-irc.network [new file with mode: 0644]
networks/infinity.network [new file with mode: 0644]
networks/megairc.network [new file with mode: 0644]
networks/mp3fans.network [new file with mode: 0644]
networks/neohorizon.network [new file with mode: 0644]
networks/networks.ndx [new file with mode: 0644]
networks/nevernet.network [new file with mode: 0644]
networks/newmilennium.network [new file with mode: 0644]
networks/realchat.network [new file with mode: 0644]
networks/roxnet.network [new file with mode: 0644]
networks/solargalaxy.network [new file with mode: 0644]
networks/solarxtreme.network [new file with mode: 0644]
networks/spynet.network [new file with mode: 0644]
networks/ss.network [new file with mode: 0644]
networks/template.network [new file with mode: 0644]
networks/tspre.network [new file with mode: 0644]
networks/unrealircd.conf [new file with mode: 0644]
networks/uzaynet.network [new file with mode: 0644]
networks/v64net.network [new file with mode: 0644]
newnet [new file with mode: 0755]
rehash [new file with mode: 0755]
src/Config.c [new file with mode: 0644]
src/Makefile [new file with mode: 0644]
src/bsd.c [new file with mode: 0644]
src/buildm4 [new file with mode: 0644]
src/channel.c [new file with mode: 0644]
src/chkconf.c [new file with mode: 0644]
src/cio_init.c [new file with mode: 0644]
src/cio_main.c [new file with mode: 0644]
src/class.c [new file with mode: 0644]
src/cloak.c [new file with mode: 0644]
src/conftool.c [new file with mode: 0644]
src/crule.c [new file with mode: 0644]
src/dbuf.c [new file with mode: 0644]
src/dynconf.c [new file with mode: 0644]
src/fdlist.c [new file with mode: 0644]
src/hash.c [new file with mode: 0644]
src/help.c [new file with mode: 0644]
src/ircd.c [new file with mode: 0644]
src/list.c [new file with mode: 0644]
src/match.c [new file with mode: 0644]
src/md5.c [new file with mode: 0644]
src/packet.c [new file with mode: 0644]
src/parse.c [new file with mode: 0644]
src/res.c [new file with mode: 0644]
src/res_comp.c [new file with mode: 0644]
src/res_init.c [new file with mode: 0644]
src/res_mkquery.c [new file with mode: 0644]
src/res_skipname.c [new file with mode: 0644]
src/s_auth.c [new file with mode: 0644]
src/s_bsd.c [new file with mode: 0644]
src/s_conf.c [new file with mode: 0644]
src/s_debug.c [new file with mode: 0644]
src/s_err.c [new file with mode: 0644]
src/s_extra.c [new file with mode: 0644]
src/s_kline.c [new file with mode: 0644]
src/s_misc.c [new file with mode: 0644]
src/s_numeric.c [new file with mode: 0644]
src/s_serv.c [new file with mode: 0644]
src/s_socks.c [new file with mode: 0644]
src/s_unreal.c [new file with mode: 0644]
src/s_user.c [new file with mode: 0644]
src/send.c [new file with mode: 0644]
src/strtoul.c [new file with mode: 0644]
src/support.c [new file with mode: 0644]
src/userload.c [new file with mode: 0644]
src/version.c.SH [new file with mode: 0644]
src/whowas.c [new file with mode: 0644]
src/win32.c [new file with mode: 0644]
src/win32.rc [new file with mode: 0644]
src/win32/Icon1.ico [new file with mode: 0644]
src/win32/Win32GUI.c [new file with mode: 0644]
src/win32/Win32GUI.rc [new file with mode: 0644]
src/win32/Win32New.h [new file with mode: 0644]
src/win32/bar.bmp [new file with mode: 0644]
src/win32/ico00001.ico [new file with mode: 0644]
src/win32/resource.h [new file with mode: 0644]
src/win32/sysicon1.ico [new file with mode: 0644]
src/win32/unrealircd.bmp.gz [new file with mode: 0644]
src/win32/version.c [new file with mode: 0644]
virtual-ip [new file with mode: 0644]
win32 [new file with mode: 0644]

diff --git a/.CHANGES.NEW b/.CHANGES.NEW
new file mode 100644 (file)
index 0000000..1431ff1
--- /dev/null
@@ -0,0 +1,6 @@
+|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
+|             UnrealIRCd 3.0                    |
+|               Configuration                   |
+|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
+| http://unreal.tspre.org                       |
+|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
diff --git a/.NEW_CONFIG b/.NEW_CONFIG
new file mode 100644 (file)
index 0000000..84dfeb9
--- /dev/null
@@ -0,0 +1,8 @@
+|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
+| UnrealIRCD Custom Create Network Configuration|
+|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
+|                                               |
+| This will not be too hard, just follow the    |
+| instructions, and answer the questions...     |
+|                                               |
+|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|
diff --git a/CREDITS.potential b/CREDITS.potential
new file mode 100644 (file)
index 0000000..02c3dfc
--- /dev/null
@@ -0,0 +1,2 @@
+List of helpers in the alpha/beta phase:
+* Headbang, Alpha/beta tester
\ No newline at end of file
diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..d8dd2d3
--- /dev/null
+++ b/Changes
@@ -0,0 +1,315 @@
+/*
+ * UnrealIRCd Changes File - (C) Carsten Munk 1999
+ * $Id$
+ * 
+ * This program is free software; you can 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.
+ *
+*/
+*** BUGS ***
+* When a +q sets +L it sets it but displays an error msg
+(??:
+*** Stskeeps (cmunk@rox-56506.fyremoon.net) has joined channel #a
+*** #a 951758184
+*** Mode change "+q Stskeeps" on channel #a by Stskeeps
+*** Mode change "-oaATcfebW" for user Stskeeps by Stskeeps
+*** Channel mode +l <max> is requried for +L to be set
+*** Mode change "+l 1" on channel #a by Stskeeps
+*** Mode change "+L #moo" on channel #a by Stskeeps
+)
+
+*** Unreal3.0-Morrigan(fix) ***
+* NOTE: If your system clock is wrong you will have problems with TOPICs
+  being set on all servers. That is because TOPICs which are _new_ are 
+  taken instead of old
+- Fixed +f not banning when * is specified
+- Fixed +q (chan owners) not being able to set +L (partially fixed)
+- Fixed /tsctl segfaulting the server
+- Fixed the killing bug. The cause was that when m_mode was called in the
+  NICKv2 parsing routine, it sent out a :nick MODE :+x which was an unknown 
+  nick, and the NICK was being sent just after, causing it to kill the user
+  (was a _huge_ bastard to find)
+- If someone changes their nick to irc and WebTV is enabled, problems
+  occur FIX: deny change to that in m_nick (bug fixed)
+- Added lost unrealircd.bmp.gz file
+
+*** Unreal3.0-Morrigan ***
+- Added the new GUI main coded by DrBin, first coding by {X}
+- Added v64net.network
+- Added 972-scripterz.network
+- Made NO_FDLIST compilation work as well
+- Fixed DCCDENY bug (p->mask, p->mask) (*slaps sts*)
+- +F not flood off if netsplit happens
+- Made TODO, made "Unable to write tunefile" show an error if *nix
+- Added stormdancing.network
+- send.c sendto_realops problem solved
+- Fixed a segfaulting bug in /tsctl reported by x-wartech
+- Fixed segfaulting bug with -oh bounce stuff in channel.c reported by Dana
+- Fixed +q bug reported by several people, inc DrBin
+- Added networks/fireirc.network
+- Fixed +f * option not banning correctly
+- Fixed fdlist on win32 problem
+- Added /HTM for high traffic mode status (partially added)
+- Added networks/digitalirc.network
+- G:lines expire every 5th second now
+- /stats T now show incoming and outgoing rate
+- Some HTM stuff
+- Some release stuff
+- Fixed up some NICKv2 stuff, more faster stuff:)
+- Moved old Changes stuff to Changes.old
+- Made so /path ~path or ".."'s in T:lines arent possible
+- Made it so certain files ie ircd.conf,oper.motd, unrealircd.conf, ircd.log
+  can't be used in a T:line
+- Added dynconf option to specify SOCKS kill message & ban message & bantime
+- Fixed SOCKS exception bug (!!)
+- Fixed some indention in dynconf.c and a memory leak problem (what were you
+   smoking code?:P)
+- iNAH bugfixes( call them fixes and ill smash you;))
+- Recoded color striping to be ALOT more accurate and faster
+- Using hybrid IsMember()
+- Fixed +F bug (again)
+- Added FDlists, does those work on win32?
+- De-Potvinized addline, addmotd, and addomotd (should run faster)
+- Made addline, addmotd, addomotd display to the user what was written
+- Removed /snote and /snotes (no one used them)
+- GPL stuff
+- Some comestic tkl fixes..
+- Fixed +F bug
+- Made +F connect notices more bandwidth friendly, 
+  only bad things:
+    - Not showing port in connect +F
+    - On servers rejoin you get +F flooded (will be fixed in an later
+       release)
+- Made ALLOW_CHATOPS a unrealircd.conf option rather than a #define
+- Fixed a bug where you had to be +AC to see adminchats
+- chatops, adchat, nachat, techat, wallops no longer require a leading :
+- More TKL stuff..
+- m_chatops uses sendto_umode now, and also removed sendto_chatops
+- Remote rehashes now support the - flags, ex -dcc, -vhost etc
+- Fixed more G:Line stuff
+- Fixed G:Line bug with not expiring correctly - thanks Dark-Prince for
+  being guinea pig, and to JojoII for finding it
+- Fixed +ix remote bug reported by RevPsych
+- /list can now make opers see +s channels
+- Did some SJOIN2 work..
+- Fixed /whois bug with WHOIS_Channels
+- Fixed a minor, yet annoying bug in the dynconf version system, thanks to GoNiS
+- Fixed bug: EpicII stripping too much of /oper fail notice
+- Fixed bug: SJOIN TS Change notice should not show when (ts == oldts)
+- Fixed WEBTV_NONOTICE bug with CTCPs - thanks rjameson
+- Fixed +h can +o themselves bug, thanks to Mikey, HERZ and many other
+  people
+- Added TSP client/server
+- Fixed m_netinfo stuff..
+- Fixed a bug with the new m_names and +h (chanmode)
+- Removed .CHANGES.NEW2 - not in use anyways
+- Now using new m_names from bahamut by Lucas Madar (DarkRot)
+- Removed zombie code
+- Fixed up the MODE_ADMINONLY code
+- Fixed some bugs in can_send
+- Added TS Change notice to SJOIN
+- Fixed a +f bug, and fixed SJOIN resynch bug (serious)
+- Fixed up the remote rehash code a bit
+- Updated conf.doc
+- Added some WebTV stuff, read config.h
+- Removed the NO_DEFAULT_INVISIBLE define from config.h
+- Added MODE_I to unrealircd.conf, auto setting of +i when a user connects
+- Fixed a minor unrealircd.conf bug
+- Fixed up all SJOIN fuzz, made RESYNCMODES be 12
+- Fixed this bug:
+   * After sync on other server 
+      *** Stskeeps is using modes +oiwghsaHATcCreWIdt
+    should be:
+       Stskeeps is using modes +owghskaATcfrebW
+
+- Made unrealircd.conf option to hide U:lines from non-opers in /links
+- Updated the unrealircd.conf and all the .network files to support the
+  version system, and for unrealircd.conf to support HIDE_ULINES
+- Made a versioning system for unrealircd.conf and *.network (This will
+  allow us to makesure _old_ versions are not being used when new features
+  are added to the files)
+- TKL/zap bugfix!!
+- Channel mode +H errors in numeric 459 now, coded by Rev_Null- thanks
+- Moved RPL_WHOISSPECIAL to 320
+- Another TKL bug.
+- TKL bug fixed
+- Made TKL backwards compatible
+- TKLs are now syncing
+- Bug fixes..
+- Fixed TKL<->GLINE protocol problems
+- Renamed chmode +I to +V as it screwed up some clients thinking it was
+  IRCnet..
+- Took out m_fjoin, not in use
+- Fixed up +e so it works with mIRC channel dialog now
+- Added channel mode +H, only setable by SkoAdmin, makes +I users unable to
+  join channel - code&thanks to RevPsych & Rev_Null
+- Removed all MegaIRC references
+- Fixed VHOST desynch bug..
+- Removed aGline record
+- Fixed some idention in msg.h
+- Fixed warning in s_misc.c
+- Removes /ns, /cs, /ms, /os, /hs commands (not in use)
+- Fixed bug where /statserv needed a : for more than one param
+- Fixed so that /trace only cloaks hostname if it is an oper
+- Fixed token non case sensitive problem
+- Fixed warning in mp2parv..
+- Fixed DEBUGMODE compile bug..
+- Fixed BOTMOTD bug..
+- Fixed some bugs (1.16->1.17) and removed aClient->user->host and replaced
+  it by realhost. Saves memory
+- Fixing up for beta release
+- Updated networks/networks.ndx
+- Reason in temp and static K:lines like |kc.gline will show user klined
+  file kc.gline (only legal names are |kc.*)
+- Added e:lines to the docs
+- Added solargalaxy.network
+- Fixed a minor +S (chanmode) bug
+- Fixed a bug where if a channel was +n it would display a
+  must be +v msg rather than no external msgs (thank Potvin for that one)
+- Made dccdeny's notice +e users when a file is rejected
+- Added NOTICE in m_sajoin/m_sapart (You were forced to join/part #)
+- Added e:lines, SOCKS check exception lines
+  format: e:ip (not hostname):*:*
+- Added doc/faq entry about debian on sparcs..
+- added debian sparc support (read doc/faq)
+- SJOIN sortof working. Straight testing needed
+- made /botmotd use NOTICE AUTH (so all bots will see it)
+- fixed NICKv2 umode field when no mode bug..
+- added T (TechAdmin) to the SMO flags
+- fixed a little _mistake_ in the /dusers error message
+- fixed a bug where +c (chanmode) blocked all privmsgs :P
+- m_sjoin compiled, need to make it unreal3.0 compatible
+- added include/sjoin.h for SJOIN stuff
+- Deleted :server prefix from SWHOIS burst.
+- Added UMODE_SETHOST (+t), and set NICKv2 up to only send when a real
+  virthost. Spares bandwidth:) +t is _not_ user setable
+- Removed UMODE_COFOUND, UMODE_WMASTER, not in use anymore.
+- Fixed up MODE_LINK, MODE_FLOODLIMIT syncronization,
+  you can mode do /mode # -lf without parameters
+- Gave Unreal correct orgin (df4.6.5)
+- Gave /stats N,S a header
+- Added network solarxtreme.network
+- /stats N returns .network file information
+- /stats S returns unrealircd.conf information
+- Added a virtualhost field to NICKv2
+- Updated conf.doc
+- Removed all traces of CLIENT_COMPILE
+- Some Linux-ALPHA support.. i need accces to a alpha box :P
+  Fixes done by Ramuh (irc.risanet.com) originally for UltimateIRCd, 
+  thanks to ShadowMastr for forwarding me..
+- Removed all traces of services.h..
+- NICKv2 working.. :)
+- Updated doc/faq slightly
+- Updated doc/example.conf with new lines an Oflags
+- Implemented NICKv2 (umode field in NICK)
+- Similar topics are sent along now .. was a bug ? (thanks Headbang,
+    WonderWal, etc)
+- Fixed up compile warnings
+- Fixed channel.c warning in can_join
+- Removed SHOW_PASSWORD define, not in use anymore
+- Removed USE_CASETABLES define, not in use anymore
+- Removed TIMED_KLINE define, not in use anymore
+- Added OPER_NO_HIDING define
+- Removed RelicNet +z, unreal isnt at use at relicnet anyways and 
+  i still dont believe that potvin _thought_ he could make them use it?
+  hah!
+- Added REMOVE_ADVERTISING define (off by default) , check include/config.h
+  and src/s_user.c (m_message) for more info (by ice)
+- Fixed channel name similarity bug reported by IXpfah
+- Comment on Nickflood/joinflood thing (stskeeps): Services can do that?
+- Fixed up some version.c.SH stuff
+- Added SJOIN protoctl for preparing for SJOIN
+- Split up PROTOCTL_SUPPORTED in PROTOCTL_SERVER and PROTOCTL_CLIENT
+- Added networks/uzaynet.network
+- NOTICE auth, tells you that it found a bad SOCKS.
+- Made umode +d work correctly
+- Made it so users can't see the RPL_WHOISCHANNELS for a
+  +I user
+- Fixed a bug in +I where a +I user couldn't see themself
+  in /names
+- Fixed a minor bug in /chgident
+- Added bot.motd support on +B and /botmotd
+- /join 0 now shows "Left all channels" in reason why left
+- Added +H umode, hides oper status
+  in /who /who 0 o /whois (so opers
+  can spy on a channel and no one knows
+- win32: s_socks.c small problem fixed
+- Fixed a bug in the new zline code
+- Fixed a typo in the Win32 socks check (oops)
+- (development) added TODO.maybe
+- Added /vhost login password
+  read the s_extra.c on vhost.conf format
+- vhost.conf, added /rehash -vhost
+- Removed s_user.c/m_message warning
+- SOCKS check functioning
+- Removed src/list2.c - not in use
+- Removed networks/agitated.network, no longer existing network
+- Added networks/bunker7.network
+- Deleted ircdbug
+- Renamed LICENCE to LICENSE
+- /version shows alpha while in development..
+- (development) added include/stamp.h for static development stamping
+- send.c optimations from ircu :)
+- Added codemastr as offical developer
+- Now using GPL v2
+- NOTICE AUTH problem solved, i hope
+- Took out UNIXPORT code
+- Removed traces of R_LINE* in config.h
+- SOCKS check in progress
+- Fixed the Blowbug
+- TSCTL svstime works now :P correctly that is
+- nick is using modes +rx
+  instead of "nick is using modes [+rx]
+- Removed some lame brackets
+- /close sendto_ops() now
+- Fixed small SVSNICK bug (.)
+- Fixed +L resync bug..
+- df4.6.7 SVSNICK - fixes desynchs
+- Took out all the R_LINES code
+- Took out all SERVICES_MODE code
+- Took out all USE_SERVICES code
+- Added .crjava patch by Fish read include/config.h for more info..
+- Added IRCu .ack patch you can now use "ONE" in password line in I:Lines
+  to ensure only one connecting from that kind of I:line per IP.
+- /Lusers <mask> is not working anymore.. took out possible flood thing..
+- /List - IRCops should be able to see +s now (thanks Headbang and others)
+- RPL_YOURHOST - Your host is server, running version x
+  Removed [hostname].
+- RPL_MYINFO now selfupdates when adding new modes (channel and user)
+- Fixed umodestring
+- Umode +d avail to everyone now:P
+- Fixed channel mode +r defunctional bug
+  (thanks to gdb and the coder-com people who learnt me to use gdb:P)
+- SVSFLINE <+/-/*> [mask] [reason]
+     + = add (mask + reason)
+     - = delete (mask)
+     * = wipe all services F:Lines
+  (13/12/1999 working.)
+- Fixed server<->server token problem
+- Moved /info data to m_info_send
+- Made SIGSEGV do core too.. MAIL THEM TO ME ALONG WITH THE src/ircd FILE
+  if it tells ya to! 
+- Fixed "GLINE @moo.org 10 :moo\r" G:Line bug (they haunt me)
+- New F:Line system (dccdeny.conf)
+- Removed OLD F:lines
+- Fixed up /stats f/F 
+- Made /rehash -dcc      = rehashes dccdeny.conf
+       /rehash -dyn      = rehashes dynamic configuration (RISK OF TERMINATE:P)
+       /rehash -rest     = rehashes channel restrict config chrestrict.conf
+- New channel restrict system
+  (chrestrict.conf)
+  # = comment
+  allow #moo             = can join #moo
+  msg message            = shows message when cannot join cos of allow
+
diff --git a/Config b/Config
new file mode 100755 (executable)
index 0000000..6d361d3
--- /dev/null
+++ b/Config
@@ -0,0 +1,1676 @@
+#!/bin/sh
+#
+# Based off Config by Michael Graff (explorer@flame.org)
+# Copyright 1996, 1997
+#
+# (original that is =P)
+# UnrealIRCd - by Techie
+#
+# You may distribute this file without changes freely providing this notice
+# remains intact.  This file may not be redistributed or made available for
+# distribution without the author's prior consent.
+#
+# $Id$
+IRCD_VERSION="Unreal3.0"
+CONF_DATE=`date`
+LAST_VERSION="very very old"
+#
+trap "" 13 14 15
+MV=mv
+RM=rm
+SETUP=include/setup.h
+OPTIONS_H=include/settings.h
+OPTIONS=Settings
+AUTO_CONFIG=""
+#
+STDLIBH=undef
+STDDEFH=undef
+SYSSYSLOGH=undef
+MALLOCH=undef
+PARAMH=undef
+UNISTDH=undef
+STRINGH=undef
+STRINGSH=undef
+RUSAGEH=undef
+NOINDEX=undef
+NSTRERROR=undef
+NSTRTOKEN=undef
+NSTRTOK=undef
+NINETADDR=undef
+NINETNTOA=undef
+NINETNETOF=undef
+GETTIMEOFDAY=undef
+LRAND48=undef
+STRTOUL=undef
+NEEDSKIPNAME=""
+CCPATH=''
+SIGNAL=''
+BLOCKING=''
+TMP=/tmp/.Configtmp$$.c
+EXEC=/tmp/.Configtmp$$
+PLATE=/tmp/.ConPlate$$
+c=''
+n=''
+#
+DIR=`pwd`
+#
+# Some reasonable defaults
+#
+DEFOPT="-O -g"
+DEFCFLAGS="$DEFOPT"
+DEFLIBS="none"
+OSNAME="an unrecgonized operating system"
+#
+IRCNET=""
+NOSPOOF="1"
+NOSPOOF_SEED01="0x12345678"
+NOSPOOF_SEED02="0x9abcdef0"
+KLINE_ADDRESS=""
+DPATH="$DIR"
+SPATH="$DIR/src/ircd"
+MODE_X=""
+TRUEHUB=""
+CRYPT_OPER_PASSWORD=""
+CRYPT_LINK_PASSWORD=""
+LISTEN_SIZE="5"
+MAXSENDQLENGTH="3000000"
+BUFFERPOOL="(9 * MAXSENDQLENGTH)"
+NICKNAMEHISTORYLENGTH="2000"
+MAXCONNECTIONS="1024"
+SHOWOPERS="Yes"
+
+#
+# load $OPTIONS if present
+#
+if [ -r "$OPTIONS" ] ; then
+    . $OPTIONS
+fi
+
+#
+2>/dev/null
+if [ "`eval echo -n 'a'`" = "-n a" ] ; then
+        c='\c'
+else
+        n='-n'
+fi
+
+clear
+
+if [ "$LAST_VERSION" != "$IRCD_VERSION" ] ; then
+    if [ -r .CHANGES.NEW ] ; then
+        more .CHANGES.NEW
+        echo $n "[Enter to begin]"
+        read cc
+    fi
+fi
+
+if [ "$1" = "-n" ] ; then
+    if [ "$LAST_VERSION" != "$IRCD_VERSION" ] ; then
+        echo "You specified the no-questions-asked configure, but the version"
+        echo "of Config which created your Settings file was $LAST_VERSION,"
+        echo "And the current version is $IRCD_VERSION."
+        echo " "
+        echo "Please read the prompts carefully since some of them may have"
+        echo "changed."
+        echo " "
+    else
+        AUTO_CONFIG=Yes
+    fi
+fi
+
+#
+# Take a wild stab at the OS, and take reasonable defaults for each
+#
+OS=`uname -a`
+case "$OS" in
+    *NetBSD*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="-lcrypt"
+        OSNAME="NetBSD"
+        ;;
+    *FreeBSD*2.2.*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="-lcrypt"
+        OSNAME="FreeBSD 2.2.x"
+        CRYPT_OPER_PASSWORD=""
+        CRYPT_LINK_PASSWORD=""
+       echo "You are using FreeBSD 2.2.x; do NOT crypt passwords at this time"
+        ;;
+    *FreeBSD*2.2*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="none"
+        OSNAME="FreeBSD 2.2"
+        CRYPT_OPER_PASSWORD=""
+        CRYPT_LINK_PASSWORD=""
+        echo "You are using FreeBSD 2.2; do NOT crypt passwords at this time"
+        ;;
+    *FreeBSD*3*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="-lcrypt"
+        OSNAME="FreeBSD 3.x"
+        CRYPT_OPER_PASSWORD=""
+        CRYPT_LINK_PASSWORD=""
+        echo "You are using FreeBSD 3.x; You can use encrypted passwords now."
+        ;;
+    *FreeBSD*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="none"
+        OSNAME="FreeBSD"
+        CRYPT_OPER_PASSWORD=""
+        CRYPT_LINK_PASSWORD=""
+        echo "You are using FreeBSD ; do NOT crypt passwords at this time"
+        ;;
+    *SCO_SV*)
+        DEFCFLAGS="$DEFOPT -DSCOUNIX"
+        DEFLIBS="-lsocket"
+        OSNAME="SCO Openserver"
+        NEEDSKIPNAME="Yep"
+        echo "You're using SCO Unix. For more support, contact potvin@eliteircd.on.ca"
+        ;;
+    *Apple*)
+       DEFCFLAGS="$DEFOPT"
+       DEFLIBS="none"
+       OSNAME="MacOS X"
+    ;;
+
+    *OSF1*alpha*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="none"
+        OSNAME="OSF/1 or Digital Unix"
+        ;;
+    *AmigaOS*68020*)
+        DEFCFLAGS="$DEFOPT -D_AMIGA -m68020"
+        DEFLIBS=""
+        OSNAME="AmigaOS (68020)"
+        ;;
+    *AmigaOS*68030*)
+        DEFCFLAGS="$DEFOPT -D_AMIGA -m68030"
+        DEFLIBS=""
+        OSNAME="AmigaOS (68030)"
+        ;;
+    *AmigaOS*68040*)
+        DEFCFLAGS="$DEFOPT -D_AMIGA -m68040"
+        DEFLIBS=""
+        OSNAME="AmigaOS (68040)"
+        ;;
+    *AmigaOS*68060*)
+        DEFCFLAGS="$DEFOPT -D_AMIGA -m68060"
+        DEFLIBS=""
+        OSNAME="AmigaOS (68060)"
+        ;;
+    *SunOS*4.*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS="none"
+        OSNAME="SunOS 4.x"
+        ;;
+    *SunOS*5.*)
+        DEFCFLAGS="$DEFOPT -DSOL20"
+        DEFLIBS="-lsocket -lnsl -lresolv"
+        OSNAME="Solaris 2.x (or SunOS 5.x)"
+        ;;
+    *Linux*)
+       cat > $TMP << __EOF__
+#include <stdio.h>
+main()
+{
+       printf("%d\n",
+#ifndef __GLIBC__
+0);
+#else
+__GLIBC__);
+#endif
+exit(0);
+}
+__EOF__
+        cc $TMP -o $EXEC >/dev/null 2>&1
+        GLIBCVERS=`$EXEC`
+        if [ -n "$GLIBCVERS" -a "$GLIBCVERS" -ge 2 ];then
+                OSNAME="Linux (with GLIBC 2.x or greater)"
+                DEFLIBS="-lcrypt -lresolv"
+        else
+                OSNAME="Linux"
+                DEFLIBS=""
+        fi
+        DEFCFLAGS="$DEFOPT"
+        ;;
+    *HP-UX*.09.*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS=""
+        OSNAME="HPUX 9.x"
+        ;;
+    *HP-UX*.10.*)
+        DEFCFLAGS="$DEFOPT"
+        DEFLIBS=""
+        OSNAME="HPUX 10.x"
+        ;;
+esac
+
+echo " "
+echo You are running $OSNAME...
+echo " "
+
+# Create Makefile if it doesn't exist...
+if [ ! -f Makefile ] ; then
+  cp Makefile.dist Makefile
+fi
+cat << __EOF__
+Welcome to the configuration for the Unreal IRCD.
+This UnrealIRCD version is: $IRCD_VERSION, Good Luck.
+
+Config will generate a system-specific $SETUP file, a top
+level Makefile, $OPTIONS_H, and a persistant options file named
+$OPTIONS
+
+Enter "none" at any prompt to effect a null entry.
+
+__EOF__
+runonce=""
+FOO=`egrep "^CC=" Makefile 2>/dev/null | sed -e 's/^[^=]*[ ]*=\(.*\)/\1/'`
+while [ -z "$CCPATH" ] ; do
+        MYP=`echo "$PATH" | sed -e 's/:/ /g'`
+        echo "Which compiler do you use, gcc or cc or...?"
+        echo $n "[$FOO] -> $c"
+        if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+            read cc
+        else
+            cc=""
+        fi
+        if [ -z "$cc" ] ; then
+                cc=$FOO
+                CCPATH=$FOO
+        elif [ -f $cc ] ; then
+                CCPATH=$cc
+        else
+                for i in $MYP; do
+                        if [ -f $i/$cc -a -z "$CCPATH" ] ; then
+                                CCPATH=$i/$cc
+                        fi
+                done
+        fi
+        if [ -z "$CCPATH" ]; then runonce="Yes"; fi
+done
+if [ "$FOO" != "$cc" ] ; then
+        MYP=`echo "$CCPATH" | sed -e 's@/@ @g'`
+        set $MYP
+        if [ $2 ] ; then
+                while [ $2 ] ; do
+                        shift
+                done
+        fi
+        if [ $1 = "gcc" ] ; then
+                CCPATH="$CCPATH"
+        fi
+fi
+echo "Compiler selected: $CCPATH"
+echo " "
+# Check it out
+cat > $TMP <<__EOF__
+main() {}
+__EOF__
+$CCPATH $TMP -o $EXEC >/dev/null 2>&1
+if [ ! -f $EXEC ] ; then
+        echo "You don't have $CCPATH or it's broken!"
+        exit 1
+fi
+# Fix Makefile
+#
+$RM -f Makefile.tmp
+sed -e "s@^CC=\(.*\)@CC=$CCPATH@" Makefile > Makefile.tmp
+cp Makefile.tmp Makefile
+$RM -f Makefile.tmp
+#
+echo "Enter additional flags to give to $CCPATH"
+FOO=`egrep "^XCFLAGS=" Makefile 2>/dev/null | sed -e 's/^[^=]*=[ ]*\(.*\)/\1/'`
+if [ -z "$FOO" ] ; then
+    echo "I recommend $DEFCFLAGS"
+    FOO="$DEFCFLAGS"
+fi
+echo $n "[$FOO] -> $c"
+if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+    read cc
+else
+    cc=""
+fi
+if [ -z "$cc" ] ; then
+        cc="$FOO"
+fi
+if [ "$cc" = "none" ] ; then
+        cc=''
+fi
+XCFLAGS=$cc
+# Fix Makefile
+#
+$RM -f Makefile.tmp
+sed -e "s@^XCFLAGS=\(.*\)@XCFLAGS=$XCFLAGS@" Makefile > Makefile.tmp
+cp Makefile.tmp Makefile
+$RM -f Makefile.tmp
+#
+cat <<__EOF__
+
+If you need to use any extra libraries when compiling the server,
+please tell me now (might need to look at the Makefiles) and please
+include all the -l and -L flags.
+
+You should use the recommended value unless you have a compelling reason
+not to...
+__EOF__
+LIBS=`egrep "^IRCDLIBS=" Makefile 2>/dev/null | sed -e 's/^[^=]*=\(.*\)/\1/' | tr -d "\012"`
+if [ -z "$LIBS" ] ; then
+    echo "I suggest: $DEFLIBS"
+    LIBS="$DEFLIBS"
+fi
+echo $n "[$LIBS] -> $c"
+if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+    read cc
+else
+    cc=""
+fi
+if [ -z "$cc" ] ; then
+        cc="$LIBS"
+fi
+if [ "$cc" = "none" ] ; then
+        cc=''
+fi
+LIBS=$cc
+# Fix Makefile
+#
+$RM -f Makefile.tmp
+sed -e "s@^IRCDLIBS=\(.*\)@IRCDLIBS=$LIBS@" Makefile > Makefile.tmp
+cp Makefile.tmp Makefile
+$RM -f Makefile.tmp
+#
+COMP="$CCPATH $XCFLAGS $TMP -o $EXEC $LIBS"
+#
+echo 'Checking out /usr/include'
+echo $n "...Looking for /usr/include/stdlib.h...$c"
+if [ -r /usr/include/stdlib.h ] ; then
+        STDLIBH=define
+        echo  'found!'
+else
+        echo 'not found :('
+fi
+echo $n "...Looking for stddef.h...$c"
+if [ -r /usr/include/stddef.h ] ; then
+        STDDEFH=define
+        echo  'found!'
+else
+        echo 'not found :('
+fi
+echo $n "...Looking for /usr/include/sys/syslog.h...$c"
+if [ -r /usr/include/sys/syslog.h ] ; then
+        SYSSYSLOGH=define
+        echo  'found!'
+else
+        echo 'not found :('
+fi
+#echo $n "...Looking for malloc.h...$c"
+#if [ -r /usr/include/malloc.h ] ; then
+#       MALLOCH=malloc.h
+#       echo  'found!'
+#elif [ -r /usr/include/sys/malloc.h ] ; then
+#       MALLOCH=sys/malloc.h
+#       echo  'found!'
+#else
+#       echo 'not found :('
+#       MALLOCH=undef
+#fi
+echo $n "...Looking for /usr/include/sys/param.h...$c"
+if [ -r /usr/include/sys/param.h ] ; then
+
+       PARAMH=define
+       echo  'found!'
+else
+       echo 'not found :('
+fi
+echo $n "...Looking for /usr/include/unistd.h...$c"
+if [ -r /usr/include/unistd.h ] ; then
+       UNISTDH=define
+       echo  'found!'
+else
+       echo 'not found :('
+fi
+echo $n "...Looking for /usr/include/string.h...$c"
+if [ -r /usr/include/string.h ] ; then
+       STRINGH=define
+       echo  'found!'
+else
+       echo 'not found :('
+fi
+echo $n "...Looking for /usr/include/strings.h...$c"
+if [ -r /usr/include/strings.h ] ; then
+       STRINGSH=define
+       echo  'found!'
+else
+       echo 'not found :('
+fi
+echo $n "...Looking for /usr/include/sys/rusage.h...$c"
+if [ -r /usr/include/sys/rusage.h ] ; then
+       RUSAGEH=define
+       echo  'found!'
+else
+       echo 'not found (good!)'
+fi
+#
+# to b or not to b
+#
+echo " "
+echo $n "To be or not to be...$c"
+cat > $TMP <<__EOF__
+main()
+{
+       char    a[3], b[3];
+       bzero(b,3);
+       bcopy(a,b,3);
+       (void)bcmp(a,b,3);
+       exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -eq 0 ] ; then
+       echo "and so it shall be! bcopy/bzero/bcmp are about!"
+       BZERO=bzero
+else
+       echo "and it wasn't.  No bcopy/bzero/bcmp...hmpf"
+       BZERO=memset
+fi
+echo " "
+echo $n "Which one, gettimeofday, or lrand48..$c"
+cat > $TMP <<__EOF__
+#include <stdio.h>
+#include <sys/time.h>
+main()
+ {
+   struct timeval tv;
+   (void) gettimeofday(&tv, NULL);
+ }
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -eq 0 ] ; then
+       echo "We have a winner! gettimeofday found."
+       GETTIMEOFDAY=define
+else
+       echo "No gettimeofday. Lets try lrand48."
+cat > $TMP <<__EOF__
+main()
+{
+   int a;
+   a=lrand48();
+}
+__EOF__
+       $COMP >/dev/null 2>&1
+       if [ $? -eq 0 ] ; then
+               echo "Bingo! lrand48!"
+               LRAND48=define
+       fi
+fi
+#
+# check for non-blocking fd style available..
+#
+echo " "
+echo 'Checking for POSIX/BSD/SYSV non-blocking stuff'
+if [ -f $TMP -o -d $TMP ] ; then
+       $RM -f $TMP
+fi
+cat > $PLATE <<__EOF__
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <signal.h>
+alarmed()
+{
+       exit(1);
+}
+main()
+{
+       char b[12], x[32];
+       int f, l = sizeof(x);
+       f = socket(AF_INET, SOCK_DGRAM, 0);
+       if (f >= 0 && !(fcntl(f, F_SETFL, BLOCKING))) {
+               signal(SIGALRM, alarmed);
+               alarm(3);
+               recvfrom(f, b, 12, 0, x, &l);
+               alarm(0);
+               exit(0);
+       }
+       exit(1);
+}
+__EOF__
+sed -e 's/BLOCKING/O_NONBLOCK/' $PLATE > $TMP
+$COMP >/dev/null 2>&1
+if [ 0 -eq $? ] ; then
+       $EXEC
+fi
+if [ 0 -eq $? ] ; then
+       BLOCK=O_NONBLOCK
+else
+       echo 'O_NONBLOCK not present/working in fcntl.h or sys/ioctl.h'
+       if [ -f $TMP -o -d $TMP ] ; then
+               $RM -f $TMP $EXEC;
+       fi
+       sed -e 's/BLOCKING/O_NDELAY/' $PLATE > $TMP
+       $COMP >/dev/null 2>&1
+       if [ 0 -eq $? ] ; then
+               $EXEC
+       fi
+       if [ 0 -eq $? ] ; then
+               BLOCK=O_NDELAY
+       else
+               echo 'O_NDELAY not present/working in fcntl.h or sys/ioctl.h'
+               if [ -f $TMP -o -d $TMP ] ; then
+                       $RM -f $TMP $EXEC;
+               fi
+               sed -e 's/BLOCKING/FIONBIO/' $PLATE > $TMP
+               $COMP >/dev/null 2>&1
+               if [ 0 -eq $? ] ; then
+                       echo 'FIONBIO not found!  No option found!'
+                       BLOCK=none
+               else
+                       BLOCK=FIONBIO
+               fi
+       fi
+fi
+$RM -f $TMP $PLATE $EXEC
+echo "Blocking selected: $BLOCK";
+#
+# reliable signals ?
+#
+echo 'Looking for reliable signals...'
+echo "Hmmm...wonder if you have 'action from POSIX..."
+cat > $TMP <<__EOF__
+#include <signal.h>
+
+main()
+{      /* poor replacement for NULL but who cares here ? */
+       sigaction(SIGTERM, (struct sigaction *)0L, (struct sigaction *)0L);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -eq 0 ] ; then
+       echo "Ooooh, you are a lucky one! 'action from POSIX!"
+       SIGNAL=posix
+else
+       $RM -f $EXEC $TMP
+       cat > $TMP <<__EOF__
+#include <signal.h>
+int    calls = 0;
+void   handler()
+{
+       if (calls)
+               return;
+       calls++;
+       kill(getpid(), SIGTERM);
+       sleep(1);
+}
+main()
+{
+       signal(SIGTERM, handler);
+       kill(getpid(), SIGTERM);
+       exit (0);
+}
+__EOF__
+       echo $n "Nope, but you have...$c"
+       $COMP >/dev/null 2>&1
+       $EXEC
+       if [ $? -eq 0 ] ; then
+               echo 'reliable signals! Cheers BSD!'
+               SIGNAL=bsd
+       else
+               echo "yucky, unreliable SYSV!"
+               SIGNAL=sysv
+       fi
+fi
+$RM -f $EXEC $TMP
+#
+echo 'Now those strings libraries...hmm...which one is it...'
+cat > $TMP <<__EOF__
+#$STRINGH STRINGH
+#$STRINGSH STRINGSH
+#ifdef STRINGH
+#include <string.h>
+#endif
+#ifdef STRINGSH
+#include <strings.h>
+#endif
+main()
+{
+       char *s = index("foo", 'o');
+       exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -eq 0 ] ; then
+       echo "Cool...you have index()!"
+else
+       NOINDEX=define
+       echo "Grmpf...I guess there is a strchr() out there somewhere..."
+fi
+$RM -f $EXEC $TMP
+#
+# getrusage or times ?
+#
+echo $n "One for debugging, mainly, getrusage(2) or times(2)...$c"
+cat > $TMP <<__EOF__
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+main()
+{
+       struct  rusage  rus;
+       (void)getrusage(RUSAGE_SELF, &rus);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -eq 0 ] ; then
+       TIMES=getrusage
+       echo "getrusage()"
+else
+       $RM -f $EXEC $TMP
+       cat > $TMP <<__EOF__
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/times.h>
+main()
+{
+       struct  tms     tmsbuf;
+       (void)times(&tmsbuf);
+}
+__EOF__
+       $COMP >/dev/null 2>&1
+       if [ $? -eq 0 ] ; then
+               TIMES=times
+               echo "times()"
+       else
+               echo "couldn't get either ?!"
+               TIMES=none
+       fi
+fi
+#
+# what do we need that isn't here already ?
+#
+echo "What else do I need that you don't have..."
+echo $n "Lets see...$c"
+cat > $TMP <<__EOF__
+main()
+{
+       unsigned long foo;
+
+       char  *s = strtoul("0x12345", &foo, 16);
+       exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+    echo $n " strtoul$c"
+    $RM -f Makefile.tmp
+    sed -e "s@^STRTOUL=\(.*\)@STRTOUL=strtoul.o@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+else
+    $RM -f Makefile.tmp
+    sed -e "s@^STRTOUL=\(.*\)@STRTOUL=@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+fi
+$RM -f $EXEC $TMP
+cat > $TMP <<__EOF__
+main()
+{
+       char  *s = strerror(0);
+       exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " strerror$c"
+       NSTRERROR=define
+fi
+$RM -f $EXEC $TMP
+cat > $TMP <<__EOF__
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+main()
+{
+       dn_skipname("","");
+       exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 -o "$OSNAME" = "Linux RedHat 5.0" -o -n "$NEEDSKIPNAME" ] ; then
+    echo $n " dn_skipname$c"
+    $RM -f Makefile.tmp
+    sed -e "s@^RES=\(.*\)@RES=res_skipname.o@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+else if [ $? -ne 0 -o "$OSNAME" = "Linux RedHat 5.1" -o -n "$NEEDSKIPNAME" ] ; then
+    echo $n " dn_skipname$c"
+    $RM -f Makefile.tmp
+    sed -e "s@^RES=\(.*\)@RES=res_skipname.o@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+else
+    $RM -f Makefile.tmp
+    sed -e "s@^RES=\(.*\)@RES=@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+fi
+fi
+$RM -f $EXEC $TMP
+cat > $TMP <<__EOF__
+#include <sys/types.h>
+main()
+{
+    u_int32_t foo;
+    exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+    echo $n " u_int32_t$c"
+    $RM -f Makefile.tmp
+    sed -e "s@^NEED_U_INT32_T=\(.*\)@NEED_U_INT32_T=-DNEED_U_INT32_T@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+else
+    $RM -f Makefile.tmp
+    sed -e "s@^NEED_U_INT32_T=\(.*\)@NEED_U_INT32_T=@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+fi
+$RM -f $EXEC $TMP
+cat > $TMP <<__EOF__
+#$STRINGH STRINGH
+#$STRINGSH STRINGSH
+#ifdef STRINGH
+#include <string.h>
+#endif
+#ifdef STRINGSH
+#include <strings.h>
+#endif
+main()
+{
+       char  *t = "a", **p = NULL, *s = strtoken(&p, t, ",");
+       if (!strcmp(t, s))
+               exit(0);
+       exit(1);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " strtoken$c"
+       NSTRTOKEN=define
+else
+       $EXEC
+       if [ $? -ne 0 ] ; then
+               echo $n " strtoken$c"
+               NSTRTOKEN=define
+       fi
+fi
+$RM -f $EXEC $TMP
+cat > $TMP <<__EOF__
+#$STRINGH STRINGH
+#$STRINGSH STRINGSH
+#ifdef STRINGH
+#include <string.h>
+#endif
+#ifdef STRINGSH
+#include <strings.h>
+#endif
+main()
+{
+       char  *t = "1\0", *s;
+       s = strtok(t, ",");
+       if (!strcmp(t, s))
+               exit(0);
+       exit(1);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " strtok$c"
+       NSTRTOK=define
+else
+       $EXEC
+       if [ $? -ne 0 ] ; then
+               echo $n " strtok$c"
+               NSTRTOK=define
+       fi
+fi
+$RM -f $EXEC $TMP
+cat > $TMP << __EOF__
+#include <sys/types.h>
+#include <netinet/in.h>
+main()
+{
+       struct  in_addr in;
+       (void)inet_addr("1.2.3.4");
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " inet_addr$c"
+       NINETADDR=define
+fi
+$RM -f $EXEC $TMP
+cat > $TMP << __EOF__
+#include <sys/types.h>
+#include <netinet/in.h>
+main()
+{
+       struct  in_addr in;
+       in.s_addr = 0x12345678;
+       (void)inet_ntoa(in);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " inet_ntoa$c"
+fi
+$RM -f $EXEC $TMP
+cat > $TMP << __EOF__
+#include <sys/types.h>
+#include <netinet/in.h>
+main()
+{
+       struct  in_addr in;
+       in.s_addr = 0x87654321;
+       (void)inet_netof(in);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " inet_netof$c"
+       NINETNETOF=define
+fi
+$RM -f $EXEC $TMP
+echo " "
+#
+#
+#
+echo " "
+echo "Ok, here's your chance...I think you should use $BLOCK, you want"
+echo "which of these ? O_NONBLOCK (POSIX) O_NDELAY (BSD) FIONBIO (SYSV)"
+echo $n "[$BLOCK] -> $c"
+if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+    read cc
+else
+    cc=""
+fi
+if [ "$cc" = "none" ] ; then
+       cc=''
+elif [ -z "$cc" ] ; then
+       cc=$BLOCK
+fi
+BLOCK=$cc
+echo "I found $SIGNAL signals."
+if [ "$cc" = "none" ] ; then
+       cc=''
+elif [ "$SIGNAL" = "posix" ] ; then
+       echo "Hmmm...I'm not sure if signal() is reliable or not either..."
+fi
+echo "You can choose between posix, bsd and sysv.  What'll it be ?"
+echo $n "[$SIGNAL] -> $c"
+if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+    read cc
+else
+    cc=""
+fi
+if [ "$cc" = "none" ] ; then
+       cc=''
+elif [ -z "$cc" ] ; then
+       cc=$SIGNAL
+fi
+SIGNAL=$cc
+if [ "$TIMES" = "none" ] ; then
+       echo "I didn't find either getrusage or times earlier...If you do have"
+       echo "either of these, please tell me now."
+else
+       echo "I found $TIMES, out of getrusage and times.  getrusage is"
+       echo "more informative.  If you wish to swap your choice, please"
+       echo "do so now."
+fi
+echo $n "[$TIMES] -> $c"
+if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+    read cc
+else
+    cc=""
+fi
+if [ "$cc" = "none" ] ; then
+       cc=''
+elif [ -z "$cc" ] ; then
+       cc=$TIMES
+fi
+TIMES=$cc
+
+$RM -f $EXEC $TMP $PLATE
+cat > $SETUP  <<__EOF__
+#ifndef __setup_include__
+#define __setup_include__
+#$PARAMH       PARAMH
+#$UNISTDH      UNISTDH
+#$STRINGH      STRINGH
+#$STRINGSH     STRINGSH
+#$STDLIBH      STDLIBH
+#$STDDEFH      STDDEFH
+#$SYSSYSLOGH   SYSSYSLOGH
+#$NOINDEX      NOINDEX
+#$NSTRERROR    NEED_STRERROR
+#$NSTRTOKEN    NEED_STRTOKEN
+#$NSTRTOK      NEED_STRTOK
+#$NINETADDR    NEED_INET_ADDR
+#$NINETNTOA    NEED_INET_NTOA
+#$NINETNETOF   NEED_INET_NETOF
+#$GETTIMEOFDAY GETTIMEOFDAY
+#$LRAND48      LRAND48
+__EOF__
+if [ "$MALLOCH" = "undef" ] ; then
+       echo "#undef    MALLOCH" >> $SETUP
+else
+       echo "#define   MALLOCH <$MALLOCH>" >> $SETUP
+fi
+if [ "$BZERO" = "memset" ] ; then
+       cat >> $SETUP <<__EOF__
+#define        bzero(a,b)      memset(a,0,b)
+#define        bcopy(a,b,c)    memcpy(b,a,c)
+#define        bcmp    memcmp
+__EOF__
+fi
+if [ "$BLOCK" = "O_NONBLOCK" ] ; then
+       echo "#define   NBLOCK_POSIX" >> $SETUP
+elif [ "$BLOCK" = "O_NDELAY" ] ; then
+       echo "#define   NBLOCK_BSD" >> $SETUP
+else
+       echo "#define   NBLOCK_SYSV" >> $SETUP
+fi
+if [ "$SIGNAL" = "posix" ] ; then
+       echo "#define   POSIX_SIGNALS" >> $SETUP
+elif [ "$SIGNAL" = "bsd" ] ; then
+       echo "#define   BSD_RELIABLE_SIGNALS" >> $SETUP
+else
+       echo "#define   SYSV_UNRELIABLE_SIGNALS" >> $SETUP
+fi
+if [ "$TIMES" = "times" ] ; then
+       echo "#define   TIMES_2" >> $SETUP
+       echo "#undef    GETRUSAGE_2" >> $SETUP
+elif [ "$TIMES" = "getrusage" ] ; then
+       echo "#undef    TIMES_2" >> $SETUP
+       echo "#define   GETRUSAGE_2" >> $SETUP
+else
+       echo "#undef    TIMES_2" >> $SETUP
+       echo "#undef    GETRUSAGE_2" >> $SETUP
+fi
+echo "#endif" >> $SETUP
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    if [ -n "$NOSPOOF" ] ; then
+       FOO="Yes"
+    else
+       FOO="No"
+    fi
+    echo ""
+    echo "Many operating systems are running with insecure TCP stacks."
+    echo "This allows IP spoofing attacks, which are very difficult for"
+    echo "operators to track down and ban."
+    echo ""
+    echo "If you are CERTAIN your operating system has secure TCP stacks"
+    echo "you do not need to define this.  If you are not certain, define"
+    echo "this and find out if you need it later or not.  You can mail the"
+    echo "source mailing list later; someone there can help you determine"
+    echo "if your OS is secure or not."
+    echo ""
+
+        if [ "$OSNAME" = "FreeBSD 2.2" ]; then
+        echo "Your version of FreeBSD is 2.2-Release or later, so you do not"
+        echo "need to run nospoof."
+        echo ""
+        FOO=No
+        fi
+
+        if [ "$OSNAME" = "FreeBSD" ]; then
+        echo "If your version of FreeBSD is 2.2-Release or later, you do not"
+        echo "need to run nospoof."
+        echo ""
+        fi
+
+    echo "Do you have an insecure operating system and therefore want to"
+    echo "use the server anti-spoof protection?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [Yy]*)
+           NOSPOOF="1"
+           ;;
+       [Nn]*)
+           NOSPOOF=""
+           ;;
+       *)
+           echo ""
+           echo "You need to enter either Yes or No here..."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+if [ -n "$NOSPOOF" ] ; then
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$NOSPOOF_SEED01"
+    echo "For security, the nospoof code uses two special values, called"
+    echo "seeds.  Here, please enter one of them.  The values are in"
+    echo "hexidecimal (base 16) using the digits 0123456789abcdef.  Each"
+    echo "value can contain up to 8 digits, and should be specified in the"
+    echo "form 0x12345678.  If you use the defaults, that should be ok, but"
+    echo "it is more secure if you choose your own special values and keep"
+    echo "them secret."
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
+           NOSPOOF_SEED01=$cc
+           ;;
+       [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
+           NOSPOOF_SEED01=0x$cc
+           ;;
+       *)
+           echo " "
+           echo "Read the instructions and try again...  You did not enter the"
+           echo "value correctly."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$NOSPOOF_SEED02"
+    echo "For security, the nospoof code uses two special values, called"
+    echo "seeds.  Here, please enter one of them.  The values are in"
+    echo "hexidecimal (base 16) using the digits 0123456789abcdef.  Each"
+    echo "value can contain up to 8 digits, and should be specified in the"
+    echo "form 0x12345678.  If you use the defaults, that should be ok, but"
+    echo "it is more secure if you choose your own special values and keep"
+    echo "them secret."
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       0x[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
+           NOSPOOF_SEED02=$cc
+           ;;
+       [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
+           NOSPOOF_SEED02=0x$cc
+           ;;
+       *)
+           echo " "
+           echo "Read the instructions and try again...  You did not enter the"
+           echo "value correctly."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+# this matches a NOSPOOF check waaaaaay up there
+fi
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$DPATH"
+    echo ""
+    echo "What directory are all the server configuration files in?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+done
+DPATH=$cc
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$SPATH"
+    echo ""
+    echo "What is the explicit path to where the ircd binary will be"
+    echo "installed?  This should point to a file, not a directory"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+done
+SPATH=$cc
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    if [ -n "$HUB" ] ; then
+       FOO="Hub"
+    else
+       FOO="Hub"
+    fi
+    echo ""
+    echo "Would you like to compile as a Halfhub or as a leaf?"
+    echo "The halfhub will be a real hub if set so in unrealircd.conf"
+    echo "Type Hub for selecting hub and Leaf for a leaf.."
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [Hh]*)
+           HUB="1"
+           ;;
+       [Ll]*)
+           HUB=""
+           ;;
+       *)
+           echo ""
+           echo "You need to enter either Hub or Leaf here..."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+DOMAINNAME="box.name"
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$DOMAINNAME"
+    echo ""
+    echo "What is your box hostname?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+done
+DOMAINNAME=$cc
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    if [ -n "$CRYPT_OPER_PASSWORD" ] ; then
+       FOO="Yes"
+    else
+       FOO="No"
+    fi
+    echo ""
+    echo "Do you use encrypted operator passwords?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [Yy]*)
+           CRYPT_OPER_PASSWORD="1"
+           ;;
+       [Nn]*)
+           CRYPT_OPER_PASSWORD=""
+           ;;
+       *)
+           echo ""
+           echo "You need to enter either Yes or No here..."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    if [ -n "$CRYPT_LINK_PASSWORD" ] ; then
+       FOO="Yes"
+    else
+       FOO="No"
+    fi
+    echo ""
+    echo "Do you use encrypted incoming link passwords? (N lines only,"
+    echo "C lines must remain unencrypted always)"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [Yy]*)
+           CRYPT_LINK_PASSWORD="1"
+           ;;
+       [Nn]*)
+           CRYPT_LINK_PASSWORD=""
+           ;;
+       *)
+           echo ""
+           echo "You need to enter either Yes or No here..."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$LISTEN_SIZE"
+    echo ""
+    echo "What listen() backlog value do you wish to use?  Some servers"
+    echo "have problems with more than 5, others work fine with many, many"
+    echo "more."
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [1-9]*)
+           LISTEN_SIZE="$cc"
+           ;;
+       *)
+           echo ""
+           echo "You need to enter a number here."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$NICKNAMEHISTORYLENGTH"
+    echo ""
+    echo "How far back do you want to keep the nickname history?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [1-9]*)
+           NICKNAMEHISTORYLENGTH="$cc"
+           ;;
+       *)
+           echo ""
+           echo "You need to enter a number here."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$MAXSENDQLENGTH"
+    echo ""
+    echo "What sendq length do you wish to have?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [1-9]*)
+           MAXSENDQLENGTH="$cc"
+           ;;
+       *)
+           echo ""
+           echo "You need to enter a number here."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+    FOO="$BUFFERPOOL"
+    echo ""
+    echo "What size of a bufferpool (total of ALL sendq's in use) do you"
+    echo "do you wish to have?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       \([1-9]*\))
+           BUFFERPOOL="$cc"
+           ;;
+       *)
+           echo ""
+           echo "You need to enter a number here, either based on"
+           echo "MAXSENDQLENGTH or a literal value.  Also, this value"
+           echo "MUST be enclosed in parens -- (9*MAXSENDQLENGTH), for example."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+if [ "$OSNAME" = "Linux" ] ; then
+    FOO="256"
+elif [ "$OSNAME" = "Linux (with GLIBC 2.x or greater)" ] ; then
+    FOO="256"
+else
+    FOO="$MAXCONNECTIONS"
+fi
+    echo ""
+    echo "How many file descriptors (or sockets) can the irc server use?"
+    echo $n "[$FOO] -> $c"
+    if [ -z "$AUTO_CONFIG" -o -n "$runonce" ] ; then
+       read cc
+    else
+       cc=""
+       runonce=Yes
+    fi
+    if [ -z "$cc" ] ; then
+       cc=$FOO
+    fi
+    case "$cc" in
+       [1-9][0-9][0-9]*)
+           MAXCONNECTIONS="$cc"
+           ;;
+       *)
+           echo ""
+           echo "You need to enter a number here, greater or equal to 100."
+           echo ""
+           FOO=""
+           ;;
+    esac
+done
+
+#
+# check FD_SETSIZE and override if needed.
+#
+
+cat > $TMP <<__EOF__
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifndef FD_SETSIZE
+#define FD_SETSIZE -1
+#endif
+
+/*
+ * Prints "notdef" if FD_SETSIZE is undefined,
+ *        "ok"     if FD_SETSIZE is at least as large as provided on the
+ *                 compile command line (-DMAXCONNECTIONS=1234)
+ *        "###"    if it is less.  (### is the FD_SETSIZE value)
+ */
+int
+main(int argc, char *argv[])
+{
+       if (FD_SETSIZE == -1)
+               printf("notdef\n");
+       else if (FD_SETSIZE >= MAXCONNECTIONS)
+               printf("ok\n");
+       else
+               printf("%d\n", FD_SETSIZE);
+
+       return 0;
+}
+__EOF__
+$COMP "-DMAXCONNECTIONS=$MAXCONNECTIONS" >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+    echo " "
+    echo "I could not derrive what your system allows for the maximum number"
+    echo "of connections becuase the test program did not compile."
+    echo " "
+    FD_SETSIZE=""
+else
+    fd_setsize_ok=`$EXEC`
+    case $fd_setsize_ok in
+       notdef)
+           echo " "
+           echo "I could not derrive what your system allows for the maximum"
+           echo "number of connections because the test program did not find"
+           echo "a system-supplied value for FD_SETSIZE.  Assuming it is"
+           echo "defined correctly but the test program cannot find it."
+           echo " "
+           FD_SETSIZE=""
+           ;;
+       ok)
+           echo " "
+           echo "Your system-supplied value for FD_SETSIZE is large enough"
+           echo "for ircd to leave it untouched."
+           echo " "
+           FD_SETSIZE=""
+           ;;
+       *)
+           echo " "
+           echo "Your system-supplied value for FD_SETSIZE is $fd_setsize_ok"
+           echo "but you requested $MAXCONNECTIONS for ircd.  FD_SETSIZE will"
+           echo "be overridden using -DFD_SETSIZE=$MAXCONNECTIONS when"
+           echo "compiling ircd."
+           echo " "
+           FD_SETSIZE=$MAXCONNECTIONS
+           ;;
+    esac
+fi
+
+if [ -n "$FD_SETSIZE" ] ; then
+    $RM -f Makefile.tmp
+    sed -e "s@^FD_SETSIZE=\(.*\)@FD_SETSIZE=-DFD_SETSIZE=$FD_SETSIZE@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+else
+    $RM -f Makefile.tmp
+    sed -e "s@^FD_SETSIZE=\(.*\)@FD_SETSIZE=@" Makefile > Makefile.tmp
+    cp Makefile.tmp Makefile
+    $RM -f Makefile.tmp
+fi
+
+$RM -f $EXEC $TMP
+
+$RM -f ./core
+#
+# create the $OPTIONS_H file
+#
+rm -f $OPTIONS_H
+cat > $OPTIONS_H << __EOF__
+
+/*
+ * VERSION: $IRCD_VERSION
+ * DATE:    $CONF_DATE
+ * OS:      $OSNAME
+ *
+ * You shouldn't have to edit this file, if you really need to change
+ * something, i'd suggest running Config again.
+ */
+
+#define MYOSNAME "$OS"
+#define DPATH "$DPATH"
+#define SPATH "$SPATH"
+#define DOMAINNAME "$DOMAINNAME"
+#define LISTEN_SIZE $LISTEN_SIZE
+#define MAXSENDQLENGTH $MAXSENDQLENGTH
+#define BUFFERPOOL $BUFFERPOOL
+#define MAXCONNECTIONS $MAXCONNECTIONS
+#define NICKNAMEHISTORYLENGTH $NICKNAMEHISTORYLENGTH
+__EOF__
+
+if [ -n "$CRYPT_OPER_PASSWORD" ] ; then
+    echo "#define CRYPT_OPER_PASSWORD 1" >> $OPTIONS_H
+else
+    echo "#undef CRYPT_OPER_PASSWORD" >> $OPTIONS_H
+fi
+if [ -n "$CRYPT_LINK_PASSWORD" ] ; then
+    echo "#define CRYPT_LINK_PASSWORD 1" >> $OPTIONS_H
+else
+    echo "#undef CRYPT_LINK_PASSWORD" >> $OPTIONS_H
+fi
+if [ -n "$HUB" ] ; then
+    echo "#define HUB 1" >> $OPTIONS_H
+else
+    echo "#undef HUB" >> $OPTIONS_H
+fi
+
+if [ -n "$NOSPOOF" ] ; then
+    echo "#define NOSPOOF 1" >> $OPTIONS_H
+else
+    echo "#undef NOSPOOF" >> $OPTIONS_H
+fi
+if [ -n "$NOSPOOF_SEED01" ] ; then
+    echo "#define NOSPOOF_SEED01 $NOSPOOF_SEED01" >> $OPTIONS_H
+fi
+if [ -n "$NOSPOOF_SEED02" ] ; then
+    echo "#define NOSPOOF_SEED02 $NOSPOOF_SEED02" >> $OPTIONS_H
+fi
+
+if [ "$OSNAME" = "Linux (with GLIBC 2.x or greater)" ]; then
+    echo "#define GLIBC2_x" >> $OPTIONS_H
+fi
+
+#
+# create the persistant file
+#
+rm -f $OPTIONS
+cat > $OPTIONS << __EOF__
+#
+# VERSION: $IRCD_VERSION
+# DATE:    $CONF_DATE
+# OS:      $OSNAME
+#
+# You shouldn't have to edit this file, if you really need to change
+# something, i'd suggest running Config again.
+#
+#
+IRCNET="$IRCNET"
+LAST_VERSION="$IRCD_VERSION"
+NOSPOOF="$NOSPOOF"
+NOSPOOF_SEED01="$NOSPOOF_SEED01"
+NOSPOOF_SEED02="$NOSPOOF_SEED02"
+DPATH="$DPATH"
+SPATH="$SPATH"
+CRYPT_OPER_PASSWORD="$CRYPT_OPER_PASSWORD"
+CRYPT_LINK_PASSWORD="$CRYPT_LINK_PASSWORD"
+LISTEN_SIZE="$LISTEN_SIZE"
+MAXSENDQLENGTH="$MAXSENDQLENGTH"
+BUFFERPOOL="$BUFFERPOOL"
+MAXCONNECTIONS="$MAXCONNECTIONS"
+NICKNAMEHISTORYLENGTH="$NICKNAMEHISTORYLENGTH"
+HUB="$HUB"
+DOMAINNAME="$DOMAINNAME"
+__EOF__
+
+if [ "$OSNAME" = "Linux (with GLIBC 2.x or greater)" ]; then
+   echo "GLIBC2_x="YES"" >> $OPTIONS
+   echo ""
+fi
+
+cat << __EOF__
+
+ _____________________________________________________________________
+|                                                                     |
+|                    UnrealIRCd Compile-Time Config                   |
+|                                                                     |
+| The file "$OPTIONS" was either created or rewritten to contain your |
+| answers to the above questions.                                     |
+|                                                                     |
+|_____________________________________________________________________|
+|_____________________________________________________________________|
+|                                                                     |
+| Now all you have todo is type 'make' and let it compile. When thats |
+| done, you will receive other instructions on what todo next.        |
+|                                                                     |
+|_____________________________________________________________________|
+|_____________________________________________________________________|
+| - The UnrealIRCd Team -                                             |
+| * Stskeeps  stskeeps@tspre.org
+| * codemastr codemastr@tspre.org
+|_____________________________________________________________________|
+__EOF__
diff --git a/Donation b/Donation
new file mode 100644 (file)
index 0000000..ea8f3c9
--- /dev/null
+++ b/Donation
@@ -0,0 +1,20 @@
+Send donations to:
+
+UnrealIRCd Project
+P.O.Box 52
+7400 Herning
+Denmark
+
+(if you want to that is.. I mean .. I do my coding for fun.. -
+ send a teddybear or something to my nephews or something for 
+ my nieces.. so they can keep quiet while I'm trying to do anything)
+ Disks, HD's, free internet time or alike are welcome ;p ;)
+
+-- Techie (which HAD got 20 MB free HD space out of 400 MB on his own puter)
+         (just got a 8.4gb and rh6.0 *_*)
+          (and used 200 MB on his shell to code this :>) .. 
+          - oh and btw i'm male:P (*looks at BlueFlame^*)
+
+
+[ $Id$ ]
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..8f58119
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,153 @@
+$Id$
+
+Installation Procedures for the UnrealIRCD:
+=======================================================================
+Created by Stskeeps <stskeeps@tspre.org>
+=======================================================================
+
+This document describes how to install ircd, the unix daemon that acts as 
+an IRC server.
+
+For more information on UnrealIRCD contact us at
+ unreal-dev@lists.sourceforge.net
+
+The UnrealIRCD is available from http://unreal.tspre.org
+along with the latest copy of this document.
+
+
+=======================================================================
+This version of the UnrealIRCD is known to compile on the following
+platforms, and with the following compilers.  If you wish to add to this
+list, send the relevant information to us.
+
+OS and Version      Compiler and Version     Comments
+------------------- ------------------------ -------------------------------
+NetBSD 1.2B         gcc 2.7.2
+
+FreeBSD 2.1.0       gcc 2.6.3                Do NOT use crypt at all...
+
+SunOS 4.1.4         gcc 2.7-96q1 (Cygnus)
+
+Solaris 2.4         gcc 2.7-96q1 (Cygnus)    (SunOS 5.4)
+
+Solaris 2.5         SunWorks Pro C           (SunOS 5.5.1)
+                    cc: SC4.0 18 Oct 1995 C 4.0
+
+Digital Unix 3.2    gcc 2.7-96q3 (Cygnus)
+
+Linux 2.0.24        gcc 2.7.2.1
+
+HPUX 9.01           gcc 2.6.3
+
+HPUX 10.01          gcc 2.7-96q3 (Cygnus)
+
+Linux PPC                                    (iMac)
+
+AmigaOS 3.0         GCC egcs-2.91.66         (compile with -D_AMIGA)
+
+Windows NT/95       MSVC++ 4.0              
+
+Linux Mandrake                                Read FAQ 
+=======================================================================
+Unpacking the Distribution
+
+If you are reading this, you have most likely already done this, but to 
+recap:
+
+The UnrealIRCD server comes tarred and gziped. To uncompress it and expand
+it, use the following commands at the Unix prompt:
+
+gzip -d Unreal3.0.tar.gz
+tar -xvf Unreal3.0.tar
+
+This will create a new directory called Unreal3.0 and unpack the source
+into it.
+
+=======================================================================
+Editing the Configuration Files
+
+In previous versions of the source code many files had to be edited to
+make things right for any given server.
+
+In this version you DO NOT NEED TO EDIT THE Makefile OR ANY FILES
+IN include!  That is, unless you set some strange options.  If you
+find the need to edit include/config.h, for example,
+mail us and tell us why ; Config can be made smarter, and that will make
+it so you won't have to edit anything for the next version.
+
+=======================================================================
+Compiling Your Server
+
+Windows users: You must compile the Config program first. To do this
+run the following command:  $CC src\Config.c
+where $CC is the name of your compiler.  for MSVC users that is 'cl'
+
+To build the server, simply run
+       % ./Config
+to start the configuraton program.  This program looks at your system
+and generate the include/setup.h, include/settings.h, and Options files.
+You will be asked some questions.  Usually the default answers are the best
+ones and most correct.  To accept the default, just hit RETURN.
+
+Next, type 'make'. This will compile your server. Depending on your system,
+this may be a good time for a caffeine break. (MSVC users run 'nmake')
+
+Hopefully, the server will compile without incident. If it does not, and 
+you are not able to determine the error, please email
+unreal-dev@lists.sourceforge.net and hopefully someone will be able to help you with the problem.  If you
+do need to fix something, mail there with a patch.
+
+BE CERTAIN TO INCLUDE OPERATING SYSTEM INFORMATION (uname -a) AND COMPILER
+VERSION (gcc -v, for instance) IN ALL BUG REPORTS.
+
+
+=======================================================================
+Installing the Files
+
+'make install' does not work in this release -- it doesn't do anything
+except a compile if that is needed.
+
+The only files you need are the binary from src/ircd and and an ircd.conf
+(see below for copying doc/example.conf as your initial ircd.conf). You
+probably will want to create a MOTD file too, as well as place the man
+pages from the doc directory to appropriate place in your system.
+
+
+=======================================================================
+Configuring Your Server
+
+The previous step places a file named 'example.conf' into your irc 
+directory you specified to Config.
+
+To create an IRC configuration file, edit: ircd.conf
+
+Now edit this file to reflect your server. The file is mainly 
+self-explanatory. Note that if you plan to use your server on ROXnet,
+make sure that you have the following line:
+
+U:services.roxnet.org:*:*
+
+If you need help configuring your file, please connect to ROXnet,
+(irc.flirt.org or irc.roxnet.org) - go to channel #UnrealIRCd, and ask.
+
+
+=======================================================================
+Starting Your Server
+
+Simply enter the complete path to the executable into the Unix command 
+line, then hit return. Your server is now operational, assuming that you 
+have completed all the steps described above.
+
+NOTE: If you get something like the following when running ircd:
+
+ircd fd table too big
+Hard Limit: 256 IRC max: 1024
+Fix MAXCONNECTIONS
+
+You need to change config.h and recompile. Find the line that says 
+"#define MAXCONNECTIONS 1024", and change it to the number given after 
+"Hard Limit" (most likely 256), then make the server again, following the 
+above instructions.
+
+Enjoy!
+- The UnrealIRCd Team - unreal-dev@lists.sourceforge.net
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..d60c31a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Makefile.dist b/Makefile.dist
new file mode 100644 (file)
index 0000000..bebf33f
--- /dev/null
@@ -0,0 +1,205 @@
+#/************************************************************************
+#*   IRC - Internet Relay Chat, Makefile
+#*   Copyright (C) 1990, Jarkko Oikarinen
+#*
+#*   This program is free software; you can redistribute it and/or modify
+#*   it under the terms of the GNU General Public License as published by
+#*   the Free Software Foundation; either version 1, or (at your option)
+#*   any later version.
+#*
+#*   This program is distributed in the hope that it will be useful,
+#*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#*   GNU General Public License for more details.
+#*
+#*   You should have received a copy of the GNU General Public License
+#*   along with this program; if not, write to the Free Software
+#*   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#*  
+#*   $Id$
+#*/
+
+CC=gcc
+INCLUDEDIR=../include
+NETWORKSDIR=
+FROMDOS=/home/cmunk/bin/4dos
+# [CHANGEME]
+# Default flags:
+# Change XCFLAGS if you don't like what Config puts there.  Same with
+# IRCDLIBS.
+#
+# If you are configuring by hand, try "-O -g" for XCFLAGS, and leave
+# IRCDLIBS blank.  If that fails, try recomendations below.
+#
+XCFLAGS=
+IRCDLIBS=
+
+#
+# use the following on MIPS:
+#CFLAGS= -systype bsd43 -DSYSTYPE_BSD43 -I$(INCLUDEDIR)
+# For Irix 4.x (SGI), use the following:
+#CFLAGS= -g -cckr -I$(INCLUDEDIR)
+#
+# on NEXT use:
+#CFLAGS=-bsd -I$(INCLUDEDIR)
+#on NeXT other than 2.0:
+#IRCDLIBS=-lsys_s
+#
+# AIX 370 flags
+#CFLAGS=-D_BSD -Hxa -I$(INCLUDEDIR)
+#IRCDLIBS=-lbsd
+#
+# Dynix/ptx V2.0.x
+#CFLAGS= -I$(INCLUDEDIR) -O -Xo
+#IRCDLIBS= -lsocket -linet -lnsl -lseq
+# 
+# Dynix/ptx V1.x.x
+#IRCDLIBS= -lsocket -linet -lnsl -lseq
+#
+#use the following on SUN OS without nameserver libraries inside libc
+#IRCDLIBS=-lresolv
+#
+# Solaris 2
+#IRCDLIBS=-lsocket -lnsl -lresolv -L/usr/ucblib -R/usr/ucblib -lgen
+#
+# ESIX
+#CFLAGS=-O -I$(INCLUDEDIR) -I/usr/ucbinclude
+#IRCDLIBS=-L/usr/ucblib -L/usr/lib -lsocket -lucb -lns -lnsl
+#
+# LDFLAGS - flags to send the loader (ld). SunOS users may want to add
+# -Bstatic here.
+#
+#LDFLAGS=-Bstatic
+#
+#Dell SVR4
+#CC=gcc
+#CFLAGS= -I$(INCLUDEDIR) -O2
+#IRCDLIBS=-lsocket -lnsl -lucb
+
+# [CHANGEME]
+# IRCDMODE is the mode you want the binary to be.
+# The 4 at the front is important (allows for setuidness)
+#
+# WARNING: if you are making ircd SUID or SGID, check config.h to make sure
+#          you are not defining CMDLINE_CONFIG 
+IRCDMODE = 711
+
+# [CHANGEME]
+# IRCDDIR must be the same as DPATH in include/config.h
+#
+IRCDDIR=/usr/local/lib/ircd
+
+# [CHANGEME]
+# Some SunOS versions want this.  Try it without first.
+#RES=res_init.o res_comp.o res_mkquery.o
+# BSDI systems want this.
+#RES=res_skipname.o
+# The rest are perfectly content with this.
+RES=
+
+# [CHANGEME]
+# If you get a compile-time error dealing with u_int32_t, comment out
+# this line.
+# NEED_U_INT32_T=      -DNEED_U_INT32_T
+NEED_U_INT32_T=
+
+# [CHANGEME]
+# If you get a link-time error dealing with strtoul, comment out
+# this line.
+# STRTOUL=     strtoul.o
+STRTOUL=
+
+# [CHANGEME]
+# If you get crashes around a specific number of clients, and that client
+# load comes close or a little over the system-defined value of FD_SETSIZE,
+# override it here and see what happens.
+FD_SETSIZE=
+
+CFLAGS=-I$(INCLUDEDIR) $(XCFLAGS) $(NEED_U_INT32_T) $(FD_SETSIZE)
+
+SHELL=/bin/sh
+SUBDIRS=src
+BINDIR=$(IRCDDIR)
+MANDIR=/usr/local/man
+INSTALL=/usr/bin/install
+RM=rm
+CP=cp
+TOUCH=touch
+
+all:   build
+
+MAKEARGS =     'CFLAGS=${CFLAGS}' 'CC=${CC}' 'IRCDLIBS=${IRCDLIBS}' \
+               'LDFLAGS=${LDFLAGS}' 'IRCDMODE=${IRCDMODE}' \
+               'BINDIR=${BINDIR}' 'INSTALL=${INSTALL}' \
+               'INCLUDEDIR=${INCLUDEDIR}' 'IRCDDIR=${IRCDDIR}' \
+               'MANDIR=${MANDIR}' 'RM=${RM}' 'CP=${CP}' 'TOUCH=${TOUCH}' \
+               'RES=${RES}' 'SHELL=${SHELL}' 'STRTOUL=${STRTOUL}'
+
+server:
+build:
+       -@if [ ! -f include/setup.h ] ; then \
+               echo "Hmm...doesn't look like you've run Config..."; \
+               echo "Doing so now."; \
+               sh Config; \
+       fi
+       @for i in $(SUBDIRS); do \
+               echo "Building $$i";\
+               ( cd $$i; ${MAKE} ${MAKEARGS} build; ) \
+       done
+       @echo ' __________________________________________________ '
+       @echo '| Compile is now complete. Now you have to go do   |'
+       @echo '| The load-time configuration - try go read the    |'
+       @echo '| file "dynconf" using your favourite viewer or    |'
+       @echo '| editor. The file will contain instructions on how|'
+       @echo '| to do the dynamic configuration :)               |'
+       @echo '|                                                  |'
+       @echo '| Thanks for using Unreal IRCd! If you are in need |' 
+       @echo '| for any kind of help regarding the IRCd email us |'
+       @echo '| at unreal-dev@lists.sourceforge.net              |' 
+       @echo '|__________________________________________________|'
+
+clean:
+       $(RM) -f *~ \#* core *.orig include/*.orig
+       @for i in $(SUBDIRS); do \
+               echo "Cleaning $$i";\
+               ( cd $$i; ${MAKE} ${MAKEARGS} clean; ) \
+       done
+       -@if [ -f include/setup.h ] ; then \
+         echo "To really restart installation, remove include/setup.h" ; \
+       fi
+       -@if [ -f include/settings.h ] ; then \
+         echo "and include/settings.h" ; \
+       fi
+
+cleandir: clean
+       rm -rf include/networks.h include/setup.h include/settings.h Makefile Settings
+
+makex: fromdos
+       chmod +x Config newnet bsdinstall ircd ircdcron/ircdchk killircd
+       chmod +x makeconf rehash ircdreg
+
+fromdos: cleandir
+       $(FROMDOS) -dv *
+       $(FROMDOS) -dv src/*
+       $(FROMDOS) -dv include/*
+       $(FROMDOS) -dv doc/*
+       $(FROMDOS) -dv crypt/*
+       $(FROMDOS) -dv ircdcron/*
+makedist: makex
+       echo "Making UnrealIRCd compatible IRCd Dist."
+
+stamp: makedist
+       echo "/* Auto created release stamping */" > include/stamp.h
+       echo "#define RELEASEID2 \"`date +%s`\"" >> include/stamp.h
+       echo "#define RELEASESTUFF \"`hostname`\"" >> include/stamp.h
+       echo "" >> include/stamp.h
+
+depend:
+       @for i in $(SUBDIRS); do \
+               echo "Making dependencies in $$i";\
+               ( cd $$i; ${MAKE} ${MAKEARGS} depend; ) \
+       done
+
+install: all
+       @echo "Now install by hand; make install is broken."
+
diff --git a/READTHIS.NOW b/READTHIS.NOW
new file mode 100644 (file)
index 0000000..9543b85
--- /dev/null
@@ -0,0 +1,15 @@
+Some notes to remember:
+-----------------------
+* Don't EVER try to link it to incompatible IRCds (this does not
+  include services). It is *INCOMPATIBLE*. Please HEED this warning!!!
+
+* If you need any help you can email me at stskeeps@tspre.org
+
+* Please read the Changes file about release notes
+
+* Bugs? Read Unreal.nfo
+
+* Unreal IRCd is not meant to be a simple IRCd, rather an advanced
+  IRCd, please read the documentation before asking questions
+  
+[ $Id$ ]
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..a765785
--- /dev/null
+++ b/TODO
@@ -0,0 +1,21 @@
+TODO: (Possible 3.1)
+* Limit calls to these functions using parse()
+   0.00      3.91     0.00     6475     0.00     0.00  check_registered
+   0.00      3.91     0.00     6827     0.00     0.00 check_registered_user
+* Optimize:
+   0.00      3.91     0.00     1292     0.00     0.01  is_banned    
+  12.55      9.61     2.57    41320     0.06     0.10  check_lusers
+   4.64     11.54     0.95    41566     0.02     0.02  count_channels
+   3.08     13.96     0.63   850968     0.00     0.00  flush_connections
+    (fdlists?)
+   0.15     19.62     0.03       29     1.03     1.80  send_list
+* Add svsvline for global vlines
+* New /whowas system /who as well
+* Short MOTDs
+* B:Lines
+* Channel mode +d
+* Raising PING bug
+* Make alternative I/O engine using poll()
+* Remove some of the _little_ config.h defines and replace with
+  unrealircd.conf lines, ex ADMINCHAT, REMOTE_REHASH
+* X-Windows GUI (how bad it can be but hey! :P)
diff --git a/TSpre.doc b/TSpre.doc
new file mode 100644 (file)
index 0000000..419c3f5
--- /dev/null
+++ b/TSpre.doc
@@ -0,0 +1,28 @@
+
+       TSpre.org
+
+Many here maybe not heard of the Story
+how IRC started (and how EFnet started)
+EFnet's name means "Eris-Free Network". 
+Eris was a central hub at the fomer world-
+wide IRC network, that anyone could just add
+C:N pairs for and connect to.
+
+I was inspired of the tought of a network
+where anyone could link without application and all
+that shit..
+
+Combined with the IRCd i made (Unreal) and the tspre.org
+domain i got donated by Nutcais (my IRC bro). Ive decided to 
+start the TSpre IRC network, where anyone with TSpre servers
+(dreamforge, IRCu p9, and their alike)
+
+(mostly preffered is Unreal thou).. Its an experimental 
+network where people can test out thier IRCds and
+wIRds without having to fill out apps and so on.
+
+There are no real rules. So just have fun :)
+
+See http://www.tspre.org for more info on this=)
+
+--Stskeeps (stskeeps@tspre.org)
diff --git a/Unreal.nfo b/Unreal.nfo
new file mode 100644 (file)
index 0000000..4a521f3
--- /dev/null
@@ -0,0 +1,49 @@
+===============================================
+=            UnrealIRCd v3.0                  =
+===============================================
+ Was brought to you by:
+  * Stskeeps  <stskeeps@tspre.org>
+  * codemastr <codemastr@tspre.org>
+  
+ Precenses on the Internet:
+  * http://unreal.tspre.org or http://unreal.sourceforge.net
+  * ftp://unreal.sourceforge.net/pub/unreal
+  * ftp://ftp.shadow-realm.org/pub/ircd/UnrealIRCd
+ CVS Repository:
+  * Alpha versions (or beta)
+  ==========================  
+cvs -z9 -d :pserver:anonymous@cvs.unreal.sourceforge.net:/cvsroot/unreal login
+    (just press enter when it asks for password)
+cvs -z9 -d :pserver:anonymous@cvs.unreal.sourgeforge.net:/cvsroot/unreal co alpha
+
+  * To get support
+  ================
+    * IRC: /server irc.flirt.org 6667 - /join #unrealircd
+    * Mailing list: unreal-support@lists.sourceforge.net (for support)
+  
+  * Got a bug to report? 
+  ====================== 
+    * If the server crashes and dumps core do this:
+       * Go into the Unreal directory and type this:
+           gdb src/ircd core.filename
+         where core.filename is the filename in the dumping core message
+         if it loads gdb, (not saying "command not found" etc), type "bt" in
+         the program (type "quit" to get out again)
+        
+         The output coming out there please mail it to 
+         unreal-dev@lists.sourceforge.net, along with OS type,
+         what "uname -a" says, any clues what it is, if you did anything etc
+         etc. Please keep the core dump files if we ask you to mail us them 
+         if needed
+
+    * If you experince any wierdnesses (that doesnt crash the server)
+      please mail unreal-dev@lists.sourceforge.net with any clues on what
+      you did, what you experinced etc.
+
+  * Got a suggestion?
+  ===================
+    * Mail it to unreal-dev@lists.sourceforge.net :) or catch one from
+      the Unreal team online on IRC:)
+
\ No newline at end of file
diff --git a/bsdinstall b/bsdinstall
new file mode 100755 (executable)
index 0000000..25b565c
--- /dev/null
@@ -0,0 +1,84 @@
+#! /bin/sh
+#
+# $Id$
+# Old: @(#)install.sh  4.5     (Berkeley)      10/12/83
+#
+cmd=/bin/mv
+strip=""
+chmod="/bin/chmod 755"
+chown="chown -f root"
+chgrp="/bin/chgrp -f bin"
+while true ; do
+       case $1 in
+               -s )    strip="strip"
+                       shift
+                       ;;
+               -c )    cmd="/bin/cp"
+                       shift
+                       ;;
+               -m )    chmod="/bin/chmod $2"
+                       shift
+                       shift
+                       ;;
+               -o )    chown="/etc/chown -f $2"
+                       shift
+                       shift
+                       ;;
+               -g )    chgrp="/bin/chgrp -f $2"
+                       shift
+                       shift
+                       ;;
+               -d )    cmd="/bin/mkdir"
+                       shift
+                       ;;
+               * )     break
+                       ;;
+       esac
+done
+
+if [ ! ${2-""} ]
+then   echo "install: no destination specified"
+       exit 1
+fi
+if [ ${3-""} ]
+then   echo "install: too many files specified -> $*"
+       exit 1
+fi
+if [ $1 = $2 -o $2 = . ]
+then   echo "install: can't move $1 onto itself"
+       exit 1
+fi
+case $cmd in
+/bin/mkdir )
+       file=$2/$1
+       ;;
+* )
+       if [ '!' -f $1 ]
+       then    echo "install: can't open $1"
+               exit 1
+       fi
+       if [ -d $2 ]
+       then    file=$2/$1
+       else    file=$2
+       fi
+       /bin/rm -f $file
+       ;;
+esac
+
+case $cmd in
+/bin/mkdir )
+       if [ ! -d "$file" ]
+       then    $cmd $file
+       fi
+       ;;
+* )
+       $cmd $1 $file
+       if [ $strip ]
+       then    $strip $file
+       fi
+       ;;
+esac
+
+$chown $file
+$chgrp $file
+$chmod $file
diff --git a/crypt/Makefile b/crypt/Makefile
new file mode 100644 (file)
index 0000000..7bc4b1b
--- /dev/null
@@ -0,0 +1,38 @@
+#************************************************************************
+#*   IRC - Internet Relay Chat, ircd/crypt/Makefile
+#*   Copyright (C) 1991 Darren Reed
+#*
+#*   This program is free software; you can redistribute it and/or modify
+#*   it under the terms of the GNU General Public License as published by
+#*   the Free Software Foundation; either version 1, or (at your option)
+#*   any later version.
+#*
+#*   This program is distributed in the hope that it will be useful,
+#*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#*   GNU General Public License for more details.
+#*
+#*   You should have received a copy of the GNU General Public License
+#*   along with this program; if not, write to the Free Software
+#*   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#*
+#*   $Id$
+#*/
+#
+# Change this to the path of your local ircd.conf file
+#
+
+IRCDCONF = ../ircd.conf
+
+all: mkpasswd
+crypt: install
+
+mkpasswd: mkpasswd.c
+       cc -lcrypt -O mkpasswd.c -o mkpasswd
+
+install:
+       crypter ${IRCDCONF}
+       @echo 'done.'
+
+clean:
+       /bin/rm -f mkpasswd
diff --git a/crypt/README b/crypt/README
new file mode 100644 (file)
index 0000000..817cc20
--- /dev/null
@@ -0,0 +1,63 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/crypt/README
+ *   Copyright (C) 1991 Nelson Minar
+ *
+ *   This program is free software; you can 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$
+ */
+
+The change implemented here is that the operator password in irc.conf
+is no longer stored in plaintext form, but is encrypted the same way
+that user passwords are encrypted on normal UNIX systems. Ie, instead
+of having
+
+       O:*:goodboy:Nelson
+
+in your ircd.conf file, you have
+
+       O:*:sCnvYRmbFJ7oI:Nelson
+
+You still type "/oper Nelson goodboy" to become operator. However, if
+someone gets ahold of your irc.conf file, they can no longer figure
+out what the password is from reading it.  There are still other
+security holes, namely server-server passwords, but this closes one
+obvious problem.
+
+So how do you generate these icky looking strings for passwords?
+There's a simple program called mkpasswd to do that for you.  Just run
+mkpasswd, and at the prompt type in your plaintext password.  It will
+spit out the encrypted password, which you should then just copy into
+the irc.conf file. This should be done only when adding new passwords
+to your irc.conf file. To change over your irc.conf file to use
+encrypted passwords, define CRYPT_OPER_PASSWORD in config.h. You will
+need to recompile your server if you already compiled it with this
+feature disabled. Once compiled, edit the Makefile in this directory
+and chang "IRCDCONF" to your irc.conf file. Then "make install" in this
+directory to replace all the operator passwords in your irc.conf file
+with the encrypted format.
+
+Choose your passwords carefully. Do not choose something in a
+dictionary, make sure its at least 5 characters. Anything past 8
+characters is ignored.
+
+One thing to note about crypt() passwords - for every plaintext, there
+are 4096 different passwords. Some valid encryptions of "goodboy"
+include t1Ub2RhRQHd4g sCnvYRmbFJ7oI and Xr4Z.Kg5tcdy6. The first
+two characters (the "salt") determine which of the 4096 passwords
+you will get. mkpasswd chooses the salt randomly, or alternately
+will let you specify one on the command line.
+
+see also - crypt(3)
diff --git a/crypt/crypter b/crypt/crypter
new file mode 100644 (file)
index 0000000..0d6b376
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/local/bin/perl
+#************************************************************************
+#*   IRC - Internet Relay Chat, ircd/crypt/crypter
+#*   Copyright (C) 1991 Sean Batt
+#*
+#*   This program is free software; you can 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$
+#*
+#*/
+
+#From Sean Batt sean@coombs.anu.edu.au
+#
+#Temporary output file
+#
+$tmpfile = "/tmp/ircd.conf.tmp";
+
+#
+#Original ircd.conf file
+#
+$ircdconf = @ARGV[0];
+
+print "crypting ",$ircdconf,"\n";
+@saltset = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '.', '/');
+
+umask(0077);
+open ($ircdout, ">/tmp/ircd.conf.tmp") || die "open $!";
+
+while ($text = <>) {
+#if its not an "O" line we can ignore it
+    $text =~ /^o/i || print ($ircdout $text) && next;
+    chop($text);
+    @oline = split(':', $text);
+    $salt = $saltset[rand(time)%64].$saltset[(rand(time)>>6)%64];
+    $oline[2] = crypt(@oline[2], $salt);
+    print ($ircdout join(':',@oline)."\n");
+}
+close ($ircdout);
+close ($ircdin);
+print "/bin/cp ",$tmpfile," ",$ircdconf,"\n";
+(fork()==0) ? exec("/bin/cp", $tmpfile, $ircdconf) : wait;
+
+#unlink($tmpfile);
diff --git a/crypt/mkpasswd.c b/crypt/mkpasswd.c
new file mode 100644 (file)
index 0000000..de72fb5
--- /dev/null
@@ -0,0 +1,43 @@
+/* simple password generator by Nelson Minar (minar@reed.edu)
+ * copyright 1991, all rights reserved.
+ * You can use this code as long as my name stays with it.
+ *
+ * $Id$
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+extern char *getpass();
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+  static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+  char salt[3];
+  char * plaintext;
+  int i;
+
+  if (argc < 2) {
+    srandom(time(0));          /* may not be the BEST salt, but its close */
+    salt[0] = saltChars[random() % 64];
+    salt[1] = saltChars[random() % 64];
+    salt[2] = 0;
+  }
+  else {
+    salt[0] = argv[1][0];
+    salt[1] = argv[1][1];
+    salt[2] = '\0';
+    if ((strchr(saltChars, salt[0]) == NULL) || (strchr(saltChars, salt[1]) == NULL))
+      fprintf(stderr, "illegal salt %s\n", salt), exit(1);
+  }
+
+  plaintext = getpass("Enter Password: ");
+
+  printf("Encryption: %s\n", crypt(plaintext, salt));
+  return 0;
+}
+
diff --git a/doc/ADD-TO-IRCRC b/doc/ADD-TO-IRCRC
new file mode 100644 (file)
index 0000000..15eb48b
--- /dev/null
@@ -0,0 +1,72 @@
+# $Id$
+
+on ^367 * if ([$4] != []) {echo *** $1 \($3 - $stime($4)) $2} {echo *** $1-}
+on ^333 * echo *** Topic for $1 set by $2 on $stime($3)
+on ^317 * if (index(012345679 $3) != -1) {echo *** $1 has been idle for $2 seconds.  Signon at $stime($3)} {echo *** $1 has been idle for $2 seconds.}
+On ^329 "*" echo *** $1 : created $stime($2)
+on ^
+alias silence quote silence
+alias sile quote silence
+on ^raw_irc "% SILENCE %" echo *** $*
+
+@ hideit = 0
+on ^server_notice "% % NOTICE -- CLIENT*" if (hideit != 1) {echo *** $2-}
+alias show @ hideit = 0;echo *** You can now see clients connecting/exiting
+alias hide @ hideit = 1;echo *** You will no longer see clients connecting/exiting
+
+
+# ctime and sendq written by bry
+# modified by Mmmm
+
+alias ctime { 
+       ^on 211 -
+        if ( [$0] )
+           { ^assign SS $0- }
+           { ^assign SS $S }
+
+^on ^211 * {
+        eval ^assign hrs2 ${ ([$7]/60)/60}
+        eval ^assign min2 ${[$7]/60}
+
+        eval ^assign dys ${[$HRS2]/24}
+        eval ^assign hrs ${[$HRS2]-([$DYS]*24)}
+        eval ^assign min ${[$MIN2] - ( ([$HRS]+([$DYS]*24) )*60)}
+        eval ^assign sec ${[$7]-([$MIN2]*60)}
+        @ a = index(\[ $1) - 1
+        @ b = left($a $1)
+        if (index(. $b) == -1)
+        {eval echo *** $1 $[2]DYS days, $[2]HRS hrs, $[2]MIN min, $[2]SEC s}
+        {eval echo \ 2*** $1 $[2]DYS days, $[2]HRS hrs, $[2]MIN min, $[2]SEC s\ 2}
+        }
+        ^stats l $SS
+}
+
+alias sendq {
+       eval ^on ^211 "$SRV *" {
+               @ a = index(\[ $1) - 1
+               @ b = left($a $1)
+               if (index(. $b) == -1)
+                 {eval echo *** $[11]2 sendq $1}
+                 {eval echo *** $[11]2 sendq \ 2$1\ 2}
+       }
+        if ( [$0] )
+           { ^assign SRV $0- }
+           { ^assign SRV $S }
+       stats l $SRV
+       wait -cmd eval ^on ^211 -"$SRV *"
+}
+
+# If you use Daveman's toolbox or any auto rejoin line, remove the old
+# on raw_irc for KICK, and use the foll. one instead: (Run)
+#
+#ON ^RAW_IRC "% KICK % % *" {
+#    IF ([$3]==[$N]) 
+#      {
+#        //QUOTE JOIN $2
+#        ECHO $MID(11 5 $STIME($TIME())) * You have been kicked off channel $2 by $LEFT($INDEX(! $0) $0) \($MID(1 256 $4-)\) 
+#       } 
+#     {
+#        ECHO $MID(11 5 $STIME($TIME())) * $3 has been kicked off channel $2 by $LEFT($INDEX(! $0) $0) \($MID(1 256 $4-)\) 
+#      }
+#                           }
+
diff --git a/doc/Authors b/doc/Authors
new file mode 100644 (file)
index 0000000..6e1b1b0
--- /dev/null
@@ -0,0 +1,142 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/AUTHORS
+ *   Copyright (C) 1990
+ *
+ * AUTHORS FILE:
+ *   This file attempts to remember all contributors to the IRC
+ *   developement. Names can be only added this file, no name
+ *   should never be removed. This file must be included into all
+ *   distributions of IRC and derived works.
+ *
+ *   This program is free software; you can 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.
+ */
+
+IRC was conceived of and written by Jarkko Oikarinen <jto@tolsun.oulu.fi>.
+IRC was originally written in University of Oulu, Computing Center.
+Jan 1991 - IRC 2.6  jto@tolsun.oulu.fi
+       - Multiple Channels and protocol changes
+
+Contributions were made by a cast of dozens, including the following:
+
+Markku Jarvinen <mta@tut.fi>: Emacs-like editing facility for the client
+
+Kimmo Suominen <kim@kannel.lut.fi>: HP-UX port
+
+Jeff Trim <jtrim@orion.cair.du.edu>: enhancements and advice
+
+Vijay Subramaniam <vijay@lll-winken.llnl.gov>: advice and ruthless publicity
+
+Karl Kleinpaste <karl@cis.ohio-state.edu>: user's manual
+
+Greg Lindahl <gl8f@virginia.edu>: AUTOMATON code, the Wumpus GM automaton,
+myriad bug fixes
+
+Bill Wisner <wisner@hayes.fai.alaska.edu>: numerous bug fixes and code
+enhancements
+
+Tom Davis <conslt16@zeus.unl.edu> and Tim Russell <russell@zeus.unl.edu>:
+VMS modifications
+
+Markku Savela <msa@tel4.tel.vtt.fi>: advice, support, and being the
+incentive to do some of our *own* coding. :)
+
+Tom Hopkins <hoppie@buengf.bu.edu>: bug fixes, quarantine lines,
+consolidation of various patches.
+
+Christopher Davis <ckd@cs.bu.edu>: EFnet/Anet gateway coding,
+many automata ;), documentation fixing.
+
+Helen Rose <hrose@cs.bu.edu>: documentation updating, and fixing.
+
+Tom Hinds <rocker@bucsf.bu.edu>: emacs client updating.
+
+Tim Miller <cerebus@bu-pub.bu.edu>: various server and client-breaking
+features.
+
+Darren Reed <avalon@coombs.anu.edu.au>: various bug fixes and enhancements.
+Introduced nickname and channelname hash tables into the server.
+
+The version 2.2 release was coordinated by Mike Bolotski
+<mikeb@salmon.ee.ubc.ca>.
+
+The version 2.4 release was coordinated by Markku Savela and
+Chelsea Ashley Dyerman
+
+The version 2.5.2 release was coordinated by Christopher Davis, Helen Rose,
+and Tom Hopkins.
+
+The versions 2.6.2, 2.7 and 2.8 releases were coordinated by Darren Reed.
+
+Contributions for the 2.8 release from the following people:
+Matthew Green <phone@coombs.anu.edu.au>
+Chuck Kane <ckane@ece.uiuc.edu>
+Matt Lyle <matt@oc.com>
+Vesa Ruokonen <ruokonen@lut.fi>
+
+Markku Savela <Markku.Savela@vtt.fi> / April 1990
+Fixed various bugs in 2.2PL1 release server (2.2msa.4) and changed
+sockets to use non-blocking mode (2.2msa.9). [I have absolutely
+nothing to do with clients :-]
+
+Chelsea Ashley Dyerman <chelsea@earth.cchem.berkeley.edu> / April 1990
+Rewrote the Makefiles, restructuring of source tree. Added libIrcd.a to
+the Makefile macros, numerous reformatting of server text messages, and
+added mkversion.sh to keep track of compilation statistics. Numerous
+bug fixes and enhancements, and co-coordinator of the 2.4 release.
+
+Jarle Lyngaas (nmijl@alf.uib.no) added Note functions to ircd.
+
+Armin Gruner <gruner@informatik.tu-muenchen.de> / May, June 1990:
+* Patched KILL-line feature for ircd.conf, works now.
+  Enhancement:  Time intervals can be specified in passwd-field.
+  Result: KILL-Line is only active during these intervals
+* Patched PRIVMSG handling, now OPER can specify masks for sending
+  private messages, advantage: msg to all at a specified server or host.
+* Little tests on irc 2.5 alpha, fixed some little typos in client code.
+  Change: common/debug.c has been moved to ircd/s_debug.c, and a
+  irc/c_debug.c has been created, for the benefit that wrong server msg
+  are displayed if client does not recognize them. (strange, if a server
+  sends an 'unknown command', isn't it?)
+
+Tom Hopkins <hoppie@buengf.bu.edu> / September, October 1990:
+* Patched msa's K lines for servers (Q lines).
+* Consolidated several patches, including Stealth's logging patch. 
+* Fixed several minor bugs. 
+* Has done lots of other stuff that I can't seem to remember, but he
+  always works on code, so he has to have done alot more than three
+  lines worth. :) 
+
+Carsten Munk <stskeeps@mp3fans.co.uk> / May and futher 1999:
+* Made many features based on Elite.. :/
+
+Thanks go to those persons not mentioned here who have added their advice,
+opinions, and code to IRC.
+
+Various modifications, bugreports, cleanups and testing by:
+
+Hugo Calendar <hugo@ucscb.ucsc.edu>
+Bo Adler <adler@csvax.cs.caltech.edu>
+Michael Sandrof <ms5n+@andrew.cmu.edu>
+Jon Solomon <jsol@cs.bu.edu>
+Jan Peterson <jlp@hamblin.math.byu.edu>
+Nathan Glasser <nathan@brokaw.lcs.mit.edu>
+Helen Rose <hrose@eff.org>
+Mike Pelletier <stealth@caen.engin.umich.edu>
+Basalat Ali Raja <gwydion@tavi.rice.edu>
+Eric P. Scott <eps@toaster.sfsu.edu>
+Dan Goodwin <fornax@wpi.wpi.edu>
+Noah Friedman <friedman@ai.mit.edu>
+
+[ $Id$ ]
\ No newline at end of file
diff --git a/doc/Crule.readme b/doc/Crule.readme
new file mode 100644 (file)
index 0000000..7f23c70
--- /dev/null
@@ -0,0 +1,128 @@
+SmartRoute
+Rule based connects
+Draft 4 - Aug 19, 1994
+by Tony Vencill
+
+Rule based connects allow an admin to specify under what conditions
+a connect should not be allowed.  If no rules are specified for a
+given C and/or N line it will be allowed under any condition.
+
+A rule may consist of any legal combination of the following functions
+and operators.
+
+Functions
+---------
+connected(targetmask)     - true if a server other than that processing
+                            the rule is connected that matches the
+                            target mask
+directcon(targetmask)     - true if a server other than that processing
+                            the rule is directly connected that matches
+                            the target mask
+via(viamask, targetmask)  - true if a server other than that processing
+                            the rule matches the target mask and is
+                            connected via a directly connected server
+                            that matches the via mask
+directop()                - true if an oper is directly connected
+
+Unary operators
+---------------
+!    eg: !argument        - true if the argument is false
+
+Binary operartors
+-----------------
+&&   eg: arg1&&arg2       - true if arg1 and arg2 are both true
+||   eg: arg1||arg2       - true if arg1, arg2, or both are true
+
+Parenthesis () are allowed for grouping arguments, but if no parenthesis
+are included, && will take precedence over ||, ! will take precedence
+over both && and ||, and the function will be evaluated from left to
+right.  White space in a rule is ignored.  Invalid characters in a rule
+will lead to the rule being ignored.
+
+Examples
+--------
+
+A simple example of a connect rule might be:
+
+connected(*eu.under*)
+
+This might be used in a US undernet server for a Europe CN pair to
+insure that a second Europe link is not allowed if one US-EU link
+already exists.  Note that on the undernet, US server names are
+city.state.us.undernet.org and Europe server names are
+city.country.eu.undernet.org.
+
+A more interesting example might be:
+
+connected(*eu.under*) && 
+  ( !direct(*eu.under*) || via(manhat*, *eu.under*) )
+
+Imagine the Boston undernet server uses this rule on its Europe CN
+pairs.  This says that if a Europe server is already connected, a
+Boston-Europe connect will not be allowed.  It also says that if a
+Europe server does already exist and Boston is not directly connected
+to one or more Europe servers or Manhattan is, the Boston-Europe
+connect will not be allowed.  This has the effect of allowing multiple
+US-EU links but attempting to limit these links to one server (ie:
+Boston will not initiate its first Europe link if another server is
+already linking Europe).  This rule will also prefer to let Manhattan
+handle the US-EU link by disallowing Boston-Europe links if a Europe
+server is already linked to Manhattan.
+
+A example of the remaining function, directop(), is:
+
+connected(*eu.under*) || directop()
+
+If this line is used on Boston for the Paderborn CN pair, it will allow
+connects to Paderborn only if another Europe server is not already
+connected and there is not an oper on Boston.  If this rule is
+overrideable (ie: is applied only to autoconnects as described below),
+then it will disallow Boston autoconnects to Paderborn while a Boston
+oper is online, but allow oper-initiated connects to Paderborn under any
+circumstance.  This directop() function could be used to invoke less
+prefered routes only when an oper is not present to handle routing, or
+conversly to allow use of less preferable routes only when an oper is
+present to monitor their performance.
+
+ircd.conf entries
+-----------------
+
+A rule is listed in the ircd.conf file using a D or d line (which can
+be thought of as a "disallow" line).  D lines will apply to all oper
+and server originated connects, while d lines will apply only to
+autoconnects (ie: they are overrideable by opers).  The formats are:
+
+D:targetmask::rule
+d:targetmask::rule
+
+Remember that newlines are not allowed in conf lines.  Two examples
+(from above) are:
+
+D:*eu.under*::connected(*eu.under*)
+d:*eu.under*::connected(*eu.under*) || directop()
+
+Connects originating from other servers will be checked against and
+matching D lines, while matching d lines will be ignored as it will not
+be clear whether or not the connection attempt is oper initiated.
+
+Checking and viewing rules
+--------------------------
+
+The chkconf program that comes with the servers has been modified to
+also check your connect rules.  If running in debug mode, parsing errors
+will show up at debug level 8.  To view rules online, "/stats d" can be
+used to see all rules and "/stats D" can be used to view those rules
+which affect oper initiated connects and accepts.
+
+Processing and storage
+----------------------
+
+The rules are parsed when the conf file is read and transformed into a
+more efficiently computed form, then all applicable rules are
+evaluated each time a connect command is given or an autoconnect is
+due.  If more than one applicable rule is given, only one need
+evaluate to true for the connect to be allowed (ie: the rules are ored
+together).  Note that conditions that exist when the connect is
+initiated might differ from conditions when the link is established.
+
+[ $Id$ ]
\ No newline at end of file
diff --git a/doc/Elite.Changes b/doc/Elite.Changes
new file mode 100644 (file)
index 0000000..0c95ce2
--- /dev/null
@@ -0,0 +1,126 @@
+[ $Id$ ]
+---------------------------
+Version Elite2.0 ==========
+===========================
+- Since +x was rewritten, the ban bug is 100% fixed. :)
+- Rewrote +x hidden host function completely.
+- Fixed FUNNY bug with hiddenhost and /who (Reported by Prod|gy)
+- Added/Removed irc networks
+- Fixed bug in /watch (Reported/Fixed by Despise)
+- Added nick-change flood protection.
+- Added an awesome manual... ./manual to run
+- Removed /who notice for opers.
+- Added protection of /akill *@* :)
+- Removed java stuff completely. (Java clients are like normal IRC clients...right?)
+- Added new +a mode. This mode can only be set by +q channel owners. When you are +a in a
+       channel, you cannot be deopped or kicked. (Syntax: /mode #chan +a <nick>)
+- Added new +q channel mode. ChanServ must set the channel founder +q so they are also
+       known as channel owners via the ircd. Channel owners are protected and may set
+       other users +a which they will also be protected (but not chan owners).
+       (Syntax: /mode #chan +q <nick>)
+- Re-coded /MAP
+- Changed GLINE notices from sendto_ops to send to all opers with +e flag on.
+- Added (addnet) script, you can run this to add your net settings to the next release.
+- Changed <server> to <ircnetwork> in whois "Blah is an oper on <server>"
+- Added new +L channel mode. If a #chat has a limit (+l) of 10 users, and +L set to channel
+       #chat2, when a user trys to join #chat, they won't get "#chat is full", they will be
+       auto-joined to #chat2 - (Linked channels in other words).
+       (Syntax: /mode #chan +L <linked chan>)
+- Changes user@shadow-33.com to user@user-33.one.com (noone will know one.com is the realhost)
+- Changed +x for IP's from (x.x.x.***) to (x.x.x.network-#)
+- In oline flags * will introduce +e on oper up. (before: required +e in oline flag)
+- Removed +t usermode (UMODE_ALL) - wasn't used.
+- Made 'create your own network setting' feature more stable.
+- Added new channel mode (+x) to disable colored text in channel.
+- Added +C (Co Administrator)
+- Added +T (Technical Administrator)
+- Changed /map to numerics...
+- Made startup message when booting more stable.
+
+Version Elite1.3 (02/23/99)
+============================
+- Cleaned up version.c.SH
+- Added new net settings (netdomain & helpchan)
+- Added new net config creator in ./Config
+- Made ./Config more easier...
+- Created new usermode +j (Java user)
+- New hostname (java.shadownet.org) for java users.
+- Removed RUN_SERVICES code from entire ircd.
+
+Version Elite1.2.4 (02/14/99)
+============================
+- Fixed the nick crash bug! (damn m_kill small error)
+- New network(s) added.
+- Changed one thing in m_gline (nothing big)
+
+Version Elite1.2.3 (02/10/99)
+============================
+- Removed SOCKS checking. (possibly cause of crashing)
+- Added new networks
+
+Version Elite1.2.2 (02/02/99)
+============================
+- Fixed the crashing bug. (Changing nicks with linked servers)
+- Modified AceStar net settings.
+- Q-line notices are back (except for ULined clients).
+- Fixed /kill bug with services.
+
+Version Elite1.2.1 (01/29/99)
+============================
+- Fixed multiple notices from +N / -N
+- Added some text to s_err.c
+- Possibly fixed the odd crashing... ?
+
+Version Elite1.2 (01/24/99)
+============================
+- Netadmin can be used via +N in the oline slot now.
+- When +N is executed, net-wide oper msg's are sent about it.
+- Completely removed the freeze function (it's a toy unlike a command)
+- Changed abit of the GLINE adding notice.
+- Added logging to a file for glines (gline.log)
+- Implemented SOCKS checking (thx Rhom).
+- Changed channel lists only when 2 ppl in chan to 1.
+- Changed sendto_ops function in many places in s_user.c/s_serv.c to
+  sendto_locfailops.
+- Changed GNOTICE in s_user.c/s_serv.c to GLOBOPS
+- Fixed hiddenhost bug with /kill (+w could see real host of oper)
+- Fixed hiddenhost bug with /oper (+s could see real host of oper)
+
+[Special thanks goes out to Rhom for reporting/help patch bugs]
+
+Version Elite1.1.1 (12/12/98)
+=============================
+- Fixed /whois bug (had problems with mIRC clients *sigh*)
+- Fixed /topic bug (didn't allow topic changes at all.)
+
+Version Elite1.1 (12/6/98)
+============================
+- Fixed ./Config script (Net select)
+- Fixed /remgline bug.
+- If ULined clients, channels are not shown which they are in.
+- Fixed +e / +t / +b (non-opers could get +et before)
+- Fixed OperMode notice.
+- Fixed Gline sending extra Global on expire.
+- Fixed /whowas wrong hostname bug (by Thiago)
+- Fixed chkconf ZLINE error (by matt)
+- Added PhazeNet configuration
+- Added option for auto +x in ./Config
+- Freeze was disabled in this version (It will be back in 1.2)
+
+Version Elite1.0 (09/20/98)
+============================
+- Changed Shadow3.9 to Elite1.0 (Starting a new IRCD)
+- Changed some numeric's around in src/s_err.c
+- Auto +x on Oper up.
+- Fixed small error in ./ircd script.
+- Made ./Config more Linux-redhat friendly.
+- Added RelicNet to the ircd.
+- include/config.h is much more compatible with all IRC nets.
+- Added /gline (works 100%) [/gline <user@host> <seconds> <reason>].
+- Fixed up /map.
+- Added UMODE's +e & +t 
+  * e: EYES [Can see ppl who /whois, and other notices.]
+  * t: ALL [See's all net notices ie: See's all Client connectings...]
+- Fixed the hiddenhost bug with IP's...
+- Fixed major bug with hiddenhost which caused coredump.
+- Made a new script (makeconf) -- generates the ircd.conf file.
diff --git a/doc/History/19.mu1-New b/doc/History/19.mu1-New
new file mode 100644 (file)
index 0000000..2136000
--- /dev/null
@@ -0,0 +1,16 @@
+The foll. patches are NEW in  19.mu1 (besides the old patches of stats-w,
+ban, topic, client connect, signon time, trace times in previous .mu
+versions):
+
+* All the modifications contained in U3.2, namely - TSpre8, silence, bquiet
+
+* The K line comments patch.
+
+* The operfail notification patch
+
+* The mixed case userid reject patch
+
+For info on these check the file  README.patches
+
+                                                       - Mmmm
+[ $Id$ ]
\ No newline at end of file
diff --git a/doc/History/2.8-New b/doc/History/2.8-New
new file mode 100644 (file)
index 0000000..7586f8f
--- /dev/null
@@ -0,0 +1,34 @@
+
+For starters, not a lot is new.  What is ?
+
+       * STATS o and STATS h added;
+
+       * most STATS options are no longer oper-only;
+
+       * privacy fixes to all of WHO, WHOIS, TRACE and STATS;
+
+       * more options in the ircd.conf file;
+
+       * non-debilitating DNS/ident use (DNS routines written specifically
+         for ircd which indludes small local cache);
+
+       * less bugs;
+
+       * easier to compile;
+
+       * heaps and heaps of new numerics;
+
+       * more problems for old clients that do stupid things;
+
+       * more numeric replies which replace old NOTICE's;
+
+       * compulsory ident checks and optional result usage;
+
+       * sendQ can now be class dependant;
+
+       * server handles client flooding better;
+
+       * for more information on changes, bug fixes during development, see
+         ircd/ChangeLog and common/ChangeLog
+
+[ $Id$ ]
\ No newline at end of file
diff --git a/doc/History/Advertisement b/doc/History/Advertisement
new file mode 100644 (file)
index 0000000..880a725
--- /dev/null
@@ -0,0 +1,41 @@
+                 The Internet Relay Chat Program  -  IRC
+
+                      Author: Jeff Trim, April '89
+              Revised: Greg Lindahl, Oct '90 (gl8f@virginia.edu)
+            Re-Revised: Helen Rose, March '94 (hrose@kei.com)
+
+Have you ever wanted to talk with other computer users in other parts of
+the world?  Well guess what?  You can!  The program is called IRC and it
+is networked much over North America, Europe, and Asia, Oceania, and parts
+of Africa.  This program is a substitution for talk(1), ytalk(1) and many
+other multiple talk programs you might have read about.  When you are
+talking in IRC, everything you type will instantly be transmitted around
+the world to other users that might be watching their terminals at the
+time - they can then type something and RESPOND to your messages - and
+vise versa.  I should warn you that the program can be very addictive once
+you begin to make friends and contacts on IRC ;-) especially when you
+learn how to cuss in 14 languages.
+
+Topics of discussion on IRC are varied, just like the topics of Usenet
+newsgroups are varied. Technical and political discussions are
+popular, especially when world events are in progress. IRC is also a
+way to expand your horizons, as people from many countries and
+cultures are on, 24 hours a day. Most conversations are in English,
+but there are always channels in German, Japanese, and Finnish, and
+occasionally other languages.
+
+                       How To Get IRC (technical)
+
+IRC is a fully-distributed client-server system, much like
+NNTP-Usenet, with several clients availble in C and elisp. You may ftp
+documentation and clients from any of the following sites:
+
+many kinds of clients (C, elisp, X11, VMS, REXX for VM, MSDOS, Macintosh):
+cs.bu.edu:/irc/clients
+ftp.acsu.buffalo.edu:/pub/irc
+ftp.funet.fi:/pub/unix/irc
+coombs.anu.edu.au:/pub/irc
+
+If you have any questions about IRC installation, write to hrose@kei.com.
+
+[ $Id$ ]
\ No newline at end of file
diff --git a/doc/History/Etiquette b/doc/History/Etiquette
new file mode 100644 (file)
index 0000000..0376a17
--- /dev/null
@@ -0,0 +1,86 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/etiquette
+ *   Copyright (C) 1990, Lea Viljanen and Ari Husa
+ *
+ *   This program is free software; you can 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$
+ */
+
+HOW TO BEHAVE ON IRC
+
+Authors:      Lea Viljanen (LadyBug)  viljanen@kreeta.helsinki.fi
+              Ari Husa     (luru)     so-luru@tolsun.oulu.fi 
+
+
+1) Language
+
+   The most widely understood and spoken language on IRC is English. 
+However! As IRC is used in many different countries, English is by
+no means the only language. If you want to speak some other language
+than English (for example with your friends), go to a separate channel
+and set the topic (with /topic) to indicate that. For example
+   /topic Finnish only!
+would mean that this channel would be reserved for Finnish discussion.
+On the other hand, you should check the topic (with /list command) 
+before you move to a channel to see if there are any restrictions about 
+language.
+   On a channel not restricted by /topic, please speak a language
+everybody can understand. If you want to do otherwise, change channels
+and set the topic accordingly.
+
+
+2) Hello/Goodbye
+
+   It's not necessary to greet everybody on a channel personally.
+Usually one "Hello" or equivalent is enough. And don't expect everybody
+to greet you back. On a channel with 20 people that would mean one
+screenful of hellos. It's sensible not to greet, in order not to be rude
+to the rest of the channel. If you must say hello, do it with a private /msg.
+The same applies to goodbyes.
+
+
+3) Discussion
+
+   When you come to a new channel it's advised you to listen
+for a while to get an impression of what's discussed. Please feel free
+to join in, but do not try to force your topic into the discussion
+if that doesn't come naturally.
+
+
+4) {}|[]\
+
+   IRC has quite a lot of people from Scandinavian countries,
+the above characters are letters in their alphabet. This 
+has been explained on IRC about a thousand and one times, so
+read the following, do not ask it on IRC:
+
+   {     is an A with 2 dots over it
+   }     is an A with a small circle above it
+   |     is either an O with 2 dots over it or an O with a dash (/) through it
+   [, ], and \ are the preceding three letters in upper case.
+
+   There are a lot of people from Japan as well, who use Kanji characters
+which may look quite exotic as well. As I don't know Kanji I don't
+even try to explain any of the characters.
+
+5) ATTENTION!
+
+   Remember, people on IRC form their opinions about you only by 
+your actions, writings and comments on IRC. So think before you type.
+Do not "dump" to a channel or user (send large amounts of unwanted
+information). This is likely to get you /kicked off the channel or
+/killed off from irc. Dumping causes network 'burbs', connections going
+down because servers cannot handle the large amount of traffic any more.
diff --git a/doc/History/README.patches b/doc/History/README.patches
new file mode 100644 (file)
index 0000000..e6ff11b
--- /dev/null
@@ -0,0 +1,1902 @@
+[ $Id$ ]
+
+The available patches for 2.8*mu servers are:
+
+Tp8 = TimeStampPre8 - A protocol which disallows netsplit ops and channel
+                      desynchs.
+
+Bquiet - does not allow a person who is banned to speak over the channel
+
+Silence - Cuts off flooding at local server
+
+Anc = Anti-Nick collide - *Intentional* nick collides are impossible with
+                          this wonderful patch.
+
+W = Wallops - lets you send messages to other IRC ops
+
+ban = BanInformation - Lets you see who did a ban and when, as well
+
+sw = /stats w - lets you gather statistics on average client connects
+
+To = TopicInformation - Lets you see who set the topic for a channel and when
+
+S = Signon Time - Tells you when a local user signed onto IRC
+
+Cl = Client connect - Notifies opers on your server of client connects/
+                      disconnects (with disconnect reason)
+
+TT = Trace Times - displays the time (in secs) since your server last heard
+                   anything from a client/server, when you do /trace.
+
+KL = K-line comments - Allows you to modify the lame "no ghosts allowed" default 
+                       comment to whatever you wish, or alternately, display a 
+                        file to a rejected client.
+
+OF = Oper fail patch - displays a warning to current ops when someone fails
+                       in entering the right oper password.
+
+MC = Mixed case patch - useful for those pesky clone bots and hacked logins;
+               disallows userids which have mixed case or control chars
+
+N = Note - allows you keep a "note" for other users, amongst other things
+
+-----------------------------------------------------------------------------
+Explanations for these patches follow.....
+
+Help on patches written by Mandar Mirashi (mmmirash@mailhost.ecn.uoknor.edu)
+                           Mmmm on IRC.
+
+
+=============================================================================
+                                TIMESTAMP 
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+Info on TS protocol:
+
+                               TSpre7
+
+------
+Effects of the TS protocol:
+
+> No mode wars possible.
+  When you take someones op there are three possibilities:
+  - You were too late (You was already de-opped on your server).
+  - You take it (On the *whole* net).
+  - You start taking it (on your server, but it is 'bounced' (ie your mode
+    change is cancelled); This occurs when you try to do mode change
+    direct after a net re-connection in a situation were you hacked op by
+    net-break riding.
+> No desynchronisation possible.
+> No unnecessary MODE msg send. You can't send 'double' mode's that don't
+  make sense. Servers don't send unnecessary MODE's either.
+> Hacking op is from now on *only* possible by admins that hacked their
+  servercode, and therefor easier to prosecute. Also you can 'hack' op still
+  exactly like now (by riding net break) on an *opless* channel.
+> The protocol is fully compatible with older servers: It is invisible
+  and it works with old servers like this: Every 'block' of direct connected
+        2.8.x.TS servers will stay synchronized, Hacking op is impossible by means
+        of riding a net break between two TS-servers on channels that were created
+        within that block. In all other cases the same happens as without TS.
+
+Here follow technical details implemented in TSpre7:
+
+------
+
+Reference: 2.8.14/15.TSpre7
+Full list of TS-MODE-Change protocol:
+
+-Mode changes (originating by clients) are refused only:
+ 1) from a client that is directly connected and has no chan ops on 
+    the channel on its server.
+ 2) when not being a change of the internal state of a server (Well, refused
+    is to strong, propagation of the mode is just unnecessary and thus not
+    done).
+ 3) from someone flagged as de-opped-by-server. (flag is reset when this
+    person is opped again by anyone) (The server detecting this mode change
+    cancels the mode change, by bouncing it upstream, thus keeping the net
+    synchronized).
+
+-An extra parameter is added behind MODE changes *done* by servers, sended
+ *to* other servers. It is a Universal Time in ascii seconds. This extra
+ parameter is NOT sended when it is 0 (can happen with old servers on the
+ net), 0 means <NONE> rather then Jan 1st 1970 :).
+ This parameter is the creationtime of the channel being: the universal time at
+ which the channel was created by a *local* client; or the non-zero received
+ creation time from an other server (as parameter with a mode change) that
+ was earlier then its own; or equal 0 when the channel was created by
+ a non-local client and no MODE with TS was received (yet).
+
+-Of the channel_flags is 1 bit more used: CHFL_DEOPPED, set when de-opped
+ by a server (compare CHFL_CHANOP, set when channel operator). It's reset
+ when opped. (And starts reset on joining (creation?) of a channel, this
+ will be changed to 'set' on join, when all servers have TS; making detection
+ of op hacking by admins a bit easier).
+
+-Timestamps (sended by TS-servers) are handled as follows:
+ Received TS      Own TS      Bounced/Propagated
+    equal          equal       propagated
+    later          >0,earlier  if ops: bounced with own TS
+                               if no ops: propagated with own TS
+                               (own TS is sended upstream too, to make sure
+                                TS stays synchronized).
+    earlier        later       TS copied, propagated
+    none           any         propagated, own TS sended.
+    >0             none        if ops: propagated, no TS sended, own TS stays 0.
+                               if no ops: TS copied, propagated.
+
+-A mode change +/-o nick (+/- v) from a person that is deopped by a server
+ results in a -/+o nick back up stream (and is not propagated) if it was
+ an attempt to change the internal state of the receiving server.
+
+-kick is handled as mode -o, internal state 'not on channel' being 'already
+ de-opped'. Bounce includes JOIN and restoring o and v flags.
+ (Effect: You don't even *see* the kick on one side, on the other side
+  the person joins again and gets his flags back from the bouncing server).
+
+-A received TimeStamp that claims a creation time *earlier* then that
+ this server dissapeared from the net results in a HACK: notice (with
+ time difference in seconds). Bye OPER.. (This meaning, to hack op
+ on an existing channel that was created 15 minutes before you disconnected
+ your server, you will have generated a HACK notice: Clock set back at least
+ 900 seconds by <nick>.) (Not yet implemented, prob. in pre8).
+
+
+                               TSpre8
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: *** IMPORTANT; RFC
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Thu, 14 Apr 94 18:03:38 METDST
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Hi, please read this carefully and respond if you think it will result
+in INCORRECT behaviour under any circumstances:
+
+Here follow technical details implemented in TSpre8:
+
+------
+
+Reference: 2.8.17.TSpre8
+Full list of TS-MODE-Change protocol:
+
+-Mode changes (originating by clients) are refused only:
+ 1) from a client that is directly connected and has no chan ops on 
+    the channel on its server.
+ 2) when not being a change of the internal state of a server (Well, refused
+    is to strong, propagation of the mode is just unnecessary and thus not
+    done).
+ 3) from someone flagged as de-opped-by-server. (flag is reset when this
+    person is opped again by anyone) (The server detecting this mode change
+    cancels the mode change, by bouncing it upstream, thus keeping the net
+    synchronized).
+ 4) When a '0' as timestamp is received, originating from a server (see below).
+    Then the whole mode is ignored, a HACK notice is sent to all ops and the
+                string is propagated as received.
+
+-An extra parameter is added behind MODE changes *done* by servers, sent
+ *to* other servers *containing* a +o, -o, +v or -v.
+ It is a Universal Time in ascii seconds.
+ Whenever a HACK is detected, a HACK: notice is sent to all local opers,
+ and the full MODE is propagated with a '0' as timestamp, generating
+ a HACK notice on all other servers.
+ Otherwise this parameter is the creationtime of the channel being: the
+ universal time at which the channel was created by a *local* client;
+ or the non-zero received creation time from an other server (as parameter
+ with a mode change) that was earlier then its own; or equal 0 when the
+ channel was created by a non-local client and no MODE with TS was received
+ (yet).
+
+-Of the channel_flags is 1 bit more used: CHFL_DEOPPED, set when de-opped
+ by a server (compare CHFL_CHANOP, set when channel operator). It's reset
+ when opped. It starts *set* on joining (creation?) of a channel, making
+ detection of op hacking by admins a bit easier.
+
+-Timestamps (sent by TS-servers) are handled as follows:
+ Received TS      Own TS      Bounced/Propagated
+    equal          equal       propagated
+    later          >0,earlier  if ops: bounced with own TS
+                               if no ops: TS copied, propagated
+    earlier        later       TS copied, propagated
+    0 or none      any         HACK generated, 0 propagated, own TS is kept
+    >0             none        TS copied, propagated.
+
+-A mode change +/-o nick (+/- v) from a person that is deopped by a server
+ results in a -/+o nick back up stream (and is not propagated) if it was
+ an attempt to change the internal state of the receiving server.
+
+-kick is handled as mode -o, internal state 'not on channel' being 'already
+ de-opped'. Bounce includes JOIN and restoring o and v flags.
+ (Effect: You don't even *see* the kick on one side, on the other side
+  the person joins again and gets his flags back from the bouncing server).
+
+-A received TimeStamp that claims a creation time *earlier* then that
+ this server dissapeared from the net results in a HACK: notice (with
+ time difference in seconds). Bye OPER.. (This meaning, to hack op
+ on an existing channel that was created 15 minutes before you disconnected
+ your server, you will have generated a HACK notice: Clock set back at least
+ 900 seconds by <nick>.)
+
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: TSpre8 can work! :)
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Wed, 20 Apr 94 11:44:39 METDST
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Well... it took me a few days (a night and some dreams actually), but
+I think I found a solution for the problem I mentioned during the meeting :)
+
+Let me first repeat the problem:
+
+- I stated that TSpre8 would prevent op hacking by admins, but... later
+  I realized that that was impossible the way wanted it :(
+  My idea was at first: Simply generate a HACK notice when a server
+  comes on the net with a creation time earlier then when it did split off
+  (and earlier then my own creation time). This sounds nice, but in
+  even this simple case it doesn't work:
+
+Server A and B, users a and b:
+
+  A -- B 
+  |    
+ @a       TS=100
+
+Split at t=200
+
+  A    B
+  |    
+ @a 
+
+b joins at t=300
+
+  A(TS=100)  B(TS=300)
+  |          |
+ @a         @b
+
+Net joins:
+
+  A -- B
+  |    |
+  a    b
+
+Both are de-opped: b because he sends a TS of 300 with is greater (later)
+then 100 (correctly: he used the netbreak). And a is deopped with a
+HACK notice by B, because he introduces 1) a TS earlier then the existing
+TS (100<300) and 2) the 100 is earlier then the time the split occured.
+
+The reason why this goes wrong is simply because B *forgets* the channel
+AND the TS of 100, after the split... If B would *keep* in memory that
+the channel existed on A and with what TS, it would be possible, but only
+at cost of a lot of extra memory usage...
+
+Now my new idea :) It allows hacking, but only in not so very interesting
+cases... And at least it makes it extremely difficult for a newbee, so we
+might at least catch 99% before they understand how it works :)
+
+(This explanation should not be on a public ftp site anymore after a while :)
+
+New rules:
+
+- Servers that are OFF the net for more then one day are forgotten.
+- New servers (or forgotten servers), are always bounced except on channels
+  that have no ops (when they create a channel of their own thus :) unless
+  the receiving server is younger then one day and the introduced TS is
+  earlier then the start up time (minus 10 minutes :/) of the receiving server.
+  'Birthdays' of those servers are also kept.
+- A server that splitted off while a channel already existed, and thus
+  has a creation time earlier then the "received squit time" of that
+  server, is not allowed to introduce an earlier timestamp then the
+  creationtime of the channel (HACK), and also not an equal TS when
+  younger then one day.
+- A server introducing a server with an earlier "time of received squit"
+  inherrits that time as its own "time of received squit".
+
+This allows to hack op on a channel that didn't exist when you splitted
+(not interesting). You also can't keep a server off the net till you need
+it (a telnet connection), because those can't do anything for one day long,
+unless they send the TS *equal* to the existing TS (The only exception :(),
+having to connect between two and one days before the hack, break between
+zero and one day before the hack but before the channel existed, connect
+and hack with equal TS.
+
+What do you think? Just for fun? :)
+
+Apart from that it would be suspicious when someone connects/breaks every
+24 hours a "test" server, channels that exist longer then one day are
+unhackable.
+
+The "disadvantages" are: servers that break off the net for *longer* then
+one day, but keep a channel up with an op, on *both sides of the net, will
+be completely de-opped after reconnection.
+
+*** IMPORTANT:
+
+I am absolutely not sure ;) if there aren't any other disadvantages or
+unwanted effects :) Please, think this over and mail me if you find some
+objection...
+
+Run
+
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: 2.8.19.U3 RELEASED
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Sun, 22 May 94 14:15:41 METDST
+Cc: carlo@sg.tn.tudelft.nl
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Hi all :)
+
+Proud to present: 2.8.19.U3 :)
+
+I have spend *enormous* amounts of time in TESTING this version,
+and I really hope it is completely bug free, but the changes are
+very big, so maybe persons who only want to upgrade/compile ONCE
+should wait a little longer then the compile cracks we have here ;)
+
+For real testing we need the HUBs though! So please, don't hesitate,
+Delft (a HUB) is running it already for a long time, also linked to
+other 2.8.19.U3 test servers.
+
+Before I'll tell about whats new in U3, I want to especially thank
+President for the tremendous help in testing TSpre8 -- I would never
+have been able bring up the stength to go through the difficult
+periods without him being there to listen to my technical complaints ;)
+
+=======================================================================
+
+NEW in .U3
+----------
+
+First all, TSpre8.
+
+It did not become what I hoped/expected to be possible :(
+Hacking will still be possible, but at least it will be a LOT
+more difficult when you don't know what you are doing, and I think
+we WILL catch (new) admins that think they can abuse their powers
+to be GOD on "their" channel.
+
+Especially, nobody will be able to hack *anything* with a normal nick.
+And because server modes are more obvious a hack, this alone is a
+step forward against admin hacking prevention imho.
+
+The .patch file is 
+-rw-------   1 carlo    users      65142 May 22 01:29 irc2.8.19-TSpre8.patch
+big.
+
+I'll now brows through it and mentions changes in the order they appear
+in the .patch file, arbitrary order thus ;)
+
+Zombies
+-------
+
+As mentioned before on 'wastelanders', I changed the internal way a KICK
+is handled, to be able to stop illegal -hacked- kicks from *outside* the
+channel. This has no effect on server-server protocol nor on server-client
+protocol. But because this way it is possible to keep (a little) memory
+for channels you're not on (being kicked from) I thought it would be no
+more then logical to stop people from joining the usual 10 ten channels
+at the same time, *including* the ones you are kicked from (because they
+occupy memory). This memory is released when you 1) Try to rejoin (so with
+all people having a auto-rejoin-on kick NOTHING changed at all), or 2)
+when you do a part - this is new and only intended to use when you do
+NOT have auto-rejoin, when you do not even WANT to rejoin, or try, assuming
+you might not be banned, when you have been kicked like this of a lot of
+channels and all together are "on" 10 channels so you NEED to leave one
+before you can join another... For this rare case, you must know on
+*which* channels you "are", therefor this is visible when you do a
+/names, or /who or /whois to yourself. It is never visible for others.
+Example:
+
+12:07 * Run (Daryl@sg.tn.tudelft.nl) has joined channel #wasteland
+*** Mode change "+o Run" on channel #wasteland by Wasted
+*** #wasteland : created Fri May 13 17:08:34 1994
+<Macro> Hi Run !
+*** You have been kicked off channel #wasteland by Run (Test)
+*** Run is Daryl@sg.tn.tudelft.nl (/msg Run profile)
+*** on channels: !#wasteland 
+*** on irc via server Delft.NL.EU.undernet.org (Runaway Server
++[130.161.188.188])
+*** Run is away: Writting E-mail
+*** Run is an IRC Operator
+*** Run has been idle for 642 seconds.
+
+As you can see, the channel is marked with a '!' to show you are NOT
+not that channel... Both, a part #wasteland as well as a join (being
+not able to actually join because of ban, invite-only, key or limit), will
+remove you from this channel. The part will be sent back to (only) you, and
+everything has turned out to be 100% compatible with ircii protocol.
+Finally, of course the channel is removed when everyone is kicked and/or
+left the channel (a channel with only zombies is removed immedeately).
+
+#define RPL_CREATIONTIME     329
+--------------------------------
+
+A new numeric is sent when you ask for a MODE of a channel, by doing
+/MODE #channel
+without parameters.
+The reply is the same as before, but followed by a new numeric 329:
+
+/MODE #wasteland
+Delft.NL.EU.undernet.org 324 Run #wasteland +t
+Delft.NL.EU.undernet.org 329 Run #wasteland 768845314
+
+To supress this, you'll have to add something like:
+ON ^329 *
+to your .ircrc file. If you want to see this new numeric, you would
+add
+On ^329 "*" echo *** $1 : created $stime($2)
+
+It turns out that ircii clients ask for this mode when you join a
+channel, therefor you will see the creationtime when you join a channel,
+I'll leave it as an exercise to suppress this, but still being able to
+see it when you specifically ask for it :)
+
+New ircd.conf line
+------------------
+
+This is IMPORTANT :
+In order for Uworld to work you MUST add those lines to your ircd.conf file:
+
+U:Uworld.undernet.org::*
+U:Underworld.nl::*
+
+The later to allow the backup Underworld.nl to still function.
+If you forget this, or do it wrong, your server might refuse to accept
+certain mode changes from Uworld.undernet.org and start *bouncing*
+modes done by lusers that got op from it. The name of servers allowed
+to hack have to be agreed upon totally, by all admins. If one admin
+removes his U: line, the service will not work always correctly.
+
+When a server does a mode change that is detected to be a hack, you
+will see -as an oper, or +s luser- this notice:
+
+-> *uworld* opcom MODE #wasteland +o Mmmm
+!Uworld.undernet.org! Run is using Uworld to : MODE #wasteland +o Mmmm
+*** Notice -- HACK: Uworld.undernet.org MODE #wasteland +o Mmmm 
+*** Mode change "+o Mmmm" on channel #wasteland by Uworld.undernet.org
+
+Normally, this HACK notice would NOT take effect! You still *see* the
+HACK notice for the U: line server(s) but then they DO take effect.
+
+Every other message (some including the word HACK) do also take effect,
+and are only a warning that someone is MAYBE hacking...
+I didn't see it occur yet.
+
+Removed bugs
+------------
+
+I did find some bugs in TSpre7, never thought that was possible :)
+I forgot what it exactly was, but under (very rare) circumstances it
+could be pretty serious :/
+
+One rather important thing is that now the TimeStamp is sent during a
+net re.join when there are no ops. Before it was possible to create
+a partly TimeStamp less net on an opless channel. TSpre8 garantees
+that the TS is synchronized on the whole net at any time.
+
+Other messages
+--------------
+
+Apart from the (true) HACK notice, you can get a:
+
+BOUNCE or HACK: notice, which does take effect and is most probably
+just a bounce of a mode done by an attacker: someone immedeately after
+a net re.join with his net.ride ops trying to de-op the others.
+I don't think this will happen often because it will be clear to all lusers
+that it is useless to try.
+
+NET.RIDE on opless #channel notice, you'll see this if someone does
+really abuses a net break to get ops on some opless channel. The mode
+does take effect however.
+
+FULL bounce of modes
+--------------------
+
+When before someone would ride a net break, and try something, ONLY
+his +/- o/v modes. Other modes like +mlk 1 \\|/\|/  would still take
+effect. With TSpre8 this changed... All modes (except bans) are bounced
+when someone rides a net break. Also the bouncing is more compact, while
+with TSpre7 every o and v mode took one line, now all modes are kept into
+one line.
+
+More allowed
+------------
+
+Before you was (how lame) not allowed to mix things like k, o and v...
+Now you are allowed, why not? Also you can use up to six parameters,
+really gives you a power kick ;)
+
+*** Mode change "+vvvvvv flux epa Skip Run Mmmm gyn" on channel #wasteland by
++Run
+
+User friendly mask fixing
+-------------------------
+
+The lame way Avalon fixes a mask (for a ban) is like this:
+
+/mode * +bb *.tudelft.nl Daryl@sg*.tn.tudelft.nl
+
+becomes:
+
+*** Mode change "+bb *.tudelft!*@* Daryl!*@sg*.tn.tudelft.nl" on channel
++#wasteland by Run
+
+The same on a TSpre8 server gives:
+
+*** Mode change "+b *!*@*.tudelft.nl" on channel #wasteland by Run
+
+While just Daryl@sg*.tn.tudelft.nl results in:
+
+*** Mode change "+b *!Daryl@sg*.tn.tudelft.nl" on channel #wasteland by Run
+
+which what one would expect!
+
+
+----------------------------------------------------------------
+
+Goodluck with compiling,
+
+Run
+
+PS If you encounter any problems, realize it is VERY unlikely that
+   it is .U3, but if you really think so, then first try to compile
+   plain 2.8.19. If you succeed, save the Makefile the include/config.h
+   and the include/setup.h. Unpack .U3, replace those files and recompile.
+   With this I assume you don't put your ircd.conf inside the source
+   directories of course, that would still have the paths set wrong then.
+
+   A smart move is to make patch file once for your Makefile/config.h :
+   First ONLY edit the Makefile and config.h (or copy the them from a
+   working source tree to a empty directory), and then make a diff with:
+   diff -rc irc2.8.19.clean irc2.8.19.my.makefile > Makefile.config.h.patch
+
+   That really speeds up upgrading with later versions.
+   (irc2.8.19.my.makefile only needs to contain
+    irc2.8.19.my.makefile/Makefile
+    irc2.8.19.my.makefile/include/config.h )
+   Of course, keep the include/setup.h seperately.
+
+### KILL for Mmm. Mmmm (stop it lamer (unnecessary flooding of alexbot))
+
+
+=============================================================================
+                               BQUIET
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+Helpful ideas by: Aaron, agifford@sci.dixie.edu, Karll on IRC
+
+
+In order to fight flooding, and as discussed on wastelanders, banning
+someone on a channel will now also stop him from doing anything visible
+on the channel. This allows to let someone see what you think of him
+without even kicking him, he will leave by himself.
+He will still be able to appologise by private msgs of course and then
+he can be de-banned. A ban is this way a short cut for +m+vvvv everyone
+excpet the flooder. Note that even NICK floods are stopped: When you are
+on a channel where you are banned, you are not allowed to change your nick.
+
+=============================================================================
+                               SILENCE 
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+Helpful ideas by: Aaron, agifford@sci.dixie.edu, Karll on IRC
+
+My solution to flooders with clone bots etc :)
+Let the user that GETS flooded decide he doesn't want that and stop
+the flooder right at his own server (the server of the flooder).
+This is a new command, and the clients will need unfortunately a few
+lines in their .ircrc before it can work.
+Moreover, before this works, ALL servers must have .U3.
+
+The lines I use at the moment are:
+
+ALIAS SILENCE QUOTE SILENCE
+ALIAS SILE QUOTE SILENCE
+ON ^RAW_IRC "% SILENCE %" echo *** $*
+
+It turns out that some auto-rejoin on kick lines, like Davemans toolbox,
+disables the use of ON RAW_IRC, or at least makes it work incorrectly.
+You should disable this auto-rejoin line and you could add the one I use
+instead:
+
+ON ^RAW_IRC "% KICK % % *" {
+    IF ([$3]==[$N]) {
+        //QUOTE JOIN $2
+        ECHO $MID(11 5 $STIME($TIME())) * You have been kicked off channel $2 by $LEFT($INDEX(! $0) $0) \($MID(1 256 $4-)\) } {
+        ECHO $MID(11 5 $STIME($TIME())) * $3 has been kicked off channel $2 by $LEFT($INDEX(! $0) $0) \($MID(1 256 $4-)\) }
+}
+
+which are 6 lines, not 8.
+
+The way the silence patch works is as follows:
+
+When you add a silence mask (using the same user friendly mask fixing)
+like:
+
+/SILENCE Tsunami*@
+
+It will echo back to you how it is added:
+
+*** Run!Daryl@sg.tn.tudelft.nl SILENCE +*!Tsunami*@*
+
+Note that there is a '+' infront of the mask now.
+You can also type:
+
+/SILENCE +bot*
+
+*** Run!Daryl@sg.tn.tudelft.nl SILENCE +bot*!*@*
+
+If you want to silence one particular nick, you must add the '+', because
+when you do:
+
+/SILENCE nick
+
+and 'nick' exists, you will get the silence list of nick. Just using
+/SILENCE gives your own silence list:
+
+*** Run bot*!*@*
+*** Run *!Tsunami*@*
+*** End of Silence List
+
+However, check the silence list of someone ELSE make only really sense
+when you already did sent a message to this person. Because a silence
+mask only propagates to the server of the flooder when it is actually
+necessary. For instance: You can add up to 5 silence masks and delete them
+again and it will only be local to your own server. Only when someone
+would message you, matching a mask, the mask propagates to the server of
+the flooder. And stays there till you signoff, or till you delete it.
+If you delete a mask, it follows the same path as the +masks...
+
+As a result of this, +s lusers and opers will see the message:
+
+*** SILENCE : Unknown command (from Lausanne.CH.EU.UnderNet.org)
+
+When someone from *behind* a non .U3 server sends you a message
+(Lausanne is this case). So, you will STILL be flooded ;) UNTIL ALL
+servers are upgraded... (Or must do -s, but at least the net is flooded).
+
+
+To: wastelanders@rush.cc.edu
+From: agifford@sci.dixie.edu (Aaron Gifford)
+Subject: HELP with HELP for SILENCE
+Status: RO
+
+Hey, here's a VERY VERY VERY rough draft of a HELP entry for SILENCE,
+assuming it becomes a new command for ircII and not a replacement for
+IGNORE either via new code, or aliases like:
+    ALIAS SILENCE { QUOTE SILENCE $* }
+
+Anyway, PLEASE PLEASE PLEASE alter, modify, correct, add, hack-up, etc this
+rough draft and send me your alterations.  I just typed this up VERY
+quickly because StGeorge is now running irc2.8.19.U3.1.  The bug I mention
+in the file will hopefully disappear very soon, so that text will have to
+do likewise and vanish.  :)
+
+Here it is, draft #1 HELP for SILENCE:
+
+Usage: SILENCE [<nick>]
+       SILENCE [+|-<pattern>]
+
+  SILENCE allows you to TOTALLY ignore all private messages (PRIVMSG's)
+  and notices (NOTICE's) from any user whose nick!user@host matches
+  the <pattern> parameter.  The characters * and ? can be used
+  as wildcards in the pattern.
+
+  If you wanted to ignore all users from "somewhere.com" you would use:
+    SILENCE +*!*@somewhere.com
+
+  To ignore some with the nickname "Jerk" you would use:
+    SILENCE +Jerk
+  NOTE: The server will complete the pattern, storing it as "Jerk!*@*"
+
+  The only drawback of just SILENCE'ing someone by nickname only is
+  that the user could quickly change nicknames to avoid your pattern.
+
+  To remove a pattern, use a - before the pattern you want to remove.
+  When the command is used without any parameters, the server will list
+  all stored patterns you are currently ignoring with the SILENCE
+  command.
+
+  When used in the first form listed, you will see the SILENCE list for
+  the specified user.  This list is not necessarily complete nor accurate
+  because of how servers share SILENCE information internally.  You can
+  check to see if someone is ignoring you with SILENCE by first sending
+  that user a private message, then using the command to see the user's
+  SILENCE list.
+
+  Currently there is a bug in the servers (hopefully to be fixed soon)
+  that will add the nickname you specify to your SILENCE list when you
+  attempt to see that user's SILENCE list if that user is not currently
+  online.
+
+  Because SILENCE is a part of the IRC server protocol (on the Undernet)
+  it works much more efficiently than IGNORE, but is limited to a very
+  brief list of patterns.  Also, you don't have as may options as you
+  do with IGNORE.  If a user is flooding you, SILENCE is many times
+  more efficient than IGNORE because the offending user's PRIMSG's or
+  NOTICE's (including CTCP) are stopped at the server and never even
+  sent to your client.
+
+See Also:
+  IGNORE
+
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: Re: HELP with HELP for SILENCE
+To: agifford@sci.dixie.edu (Aaron Gifford) (Aaron Gifford)
+Date: Wed, 25 May 94 12:29:37 METDST
+Cc: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+In-Reply-To: <9405250313.AA18446@sci.dixie.edu>; from "Aaron Gifford" at May 24, 94 9:20 pm
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+> Here it is, draft #1 HELP for SILENCE:
+> 
+> Usage: SILENCE [<nick>]
+>        SILENCE [+|-<pattern>]
+> 
+
+As it is now (I do not consider what you mentioned as a bug, I was aware
+of this effect and didn't choose to alter it), it really is:
+
+Usage: SILENCE [+|-]<pattern>
+Or   : SILENCE <nick>
+
+When you leave the '+|-' away A '+' is assumed.
+
+The second possibility allows you to check your own silence lists, or
+allows to check if you are silenced by someone after you did message
+him but didn't get a respond (did ping him for instance).
+Indeed, this could be interpreted as a pattern, when <nick> doesn't
+exists.
+
+>   If you wanted to ignore all users from "somewhere.com" you would use:
+>     SILENCE +*!*@somewhere.com
+
+SILENCE somewhere.com
+
+would do.
+
+>   When used in the first form listed, you will see the SILENCE list for
+>   the specified user.  This list is not necessarily complete nor accurate
+>   because of how servers share SILENCE information internally.  You can
+>   check to see if someone is ignoring you with SILENCE by first sending
+>   that user a private message, then using the command to see the user's
+>   SILENCE list.
+
+Mention that a EVAL CTCP <nick> PING $TIME() is better...
+It would not be necessary to do the silence if the ping returns...
+To determine between huge lag and silence, you have to do the silence
+check after that.
+If you add something like this in the manual, people will automatically
+wait a while after the 'message' (ping), so that the servers have time
+to send the silence mask back. Otherwise they might think they can do
+a quick msg+silence at the same time. Nah... Not too important, unless
+with huge lag + silence combination.
+
+> 
+>   Currently there is a bug in the servers (hopefully to be fixed soon)
+>   that will add the nickname you specify to your SILENCE list when you
+>   attempt to see that user's SILENCE list if that user is not currently
+>   online.
+
+I didn't consider this as too bad...
+But if people want it, I can change it so that you MUST add a '+' to
+add a mask that doesn't contain a '.', '!' or '@'.
+That would lead to 2.8.19.U3.2 and a very tiny patch for the people who
+already compiled .U3
+
+Run
+
+
+=============================================================================
+                       U3 - required additions to .ircrc
+=============================================================================
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: Re: .ircrc codes for the new patches :)
+To: lamberdc@dad.cs.tuns.ca
+Date: Mon, 23 May 94 11:41:31 METDST
+Cc: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+In-Reply-To: <9405222118.AA02415@dad.cs.tuns.ca>; from "Donald "WHIZZARD" Lambert" at May 22, 94 6:18 pm
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+> hiya All
+>       I was wondering if some one could send me a copy of the script/
+>  for the new patches including the ban , topic and client connecting patches.
+> 
+>       And whatever is now out with the new .19 code :)
+> 
+>       thanks 
+> 
+>               -- Donnie
+> 
+>               aka WHIZZARD
+
+The ftp.undernet.org:/pub/undernet/servers/Patches/README file:
+
+These are lines you need to add to your .ircrc file in order
+to use all posibilities .U3 profides you:
+
+To see when a channel was created:
+
+On ^329 * echo *** $1 : created $stime($2)
+
+When your server has the .ban patch use this to see who did a ban and when:
+
+On ^367 * if ([$4] != []) {echo *** $1 \($3 - $stime($4)) $2} {echo *** $1-}
+
+---------------------------
+When ALL servers upgraded to .U3, you can use this command:
+
+ALIAS SILENCE QUOTE SILENCE
+On ^RAW_IRC "% SILENCE %" echo *** $*
+
+Use this as:
+/SILENCE +mask
+
+To add 'mask' to your silence list (will completely stop all private
+messages from people matching 'mask' with their nick!user@host).
+You can VIEW your silence list by typing:
+/SILENCE
+
+If you message someone and he doesn't react (like with ping), then you
+can check if you match a silence mask he added by viewing his silence list
+with:
+/SILENCE nick
+
+A mask can be deleted by using the command:
+/SILENCE -mask
+
+When the some messages you from behind a NON-.U3 server you will not
+receive his message but the line:
+*** Unknown command (SILENCE) (From server.name.undernet.org)
+instead, so you will still be flooded.
+We hope all servers will be upgraded within a few months.
+
+------
+And my ircd.motd from Delft* :
+
+*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%*%
+ N E W : - This server now runs the official released
+           beta version 2.8.19.U3.1.ban
+ For you as users this means that:
+ -More security : .U3 contains the .TSpre8 patch with
+  disallows even ADMINs of servers to hack op on your
+  channel with a nick, most server modes are detected.
+ -The possibility to see the *creationtime* of a channel
+  (used with the TimeStamp (TS) protocol - unique on
+   undernet (disables the possibility of 'net.riding'))
+ -The possibility to stop EVERY kind of channel flooding
+  by *banning* someone : Now a ban stops not only
+  part/join floods, but also message floods and even
+  nick floods!
+ -The possibility to see who did when a certain ban.
+ -The possibility to stop anyone flooding you with
+  any kind of private messages at his *own* server!
+  (This will only work when ALL servers have upgraded)
+To be able to use all of this, ftp to sg.tn.tudelft.nl
+login: ftp ; password : anything ; file: /pub/README
+Put those lines in your .ircrc initialisation file !
+Have fun, Run.
+
+----
+
+Run
+
+=============================================================================
+                       U3.1 -> U3.2    
+=============================================================================
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: *BUG* .U3.1 found !!
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Wed, 25 May 94 16:45:39 METDST
+In-Reply-To: <457.9405250732@ccws-09.brunel.ac.uk>; from "James T Lowe" at May 25, 94 8:32 am
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+> :-> 
+> :-> Hiya..
+> :-> 
+> :->     Here's what I observed tonight:
+> :-> 
+> :-> *** Mmmm (mandar@roosevelt.ecn.uoknor.edu) has joined channel #friendly
+> :-> *** Users on #friendly: @Mmmm 
+> :-> *** Mode change "-o Mmmm" on channel #friendly by Uxbridge.*
+> 
+> Not surprising : 
+> 
+> #friendly  RedRum    H*  cs93jtl@ccws-09.brunel.ac.uk
+> #friendly  Emmy      H   lamphear@cheshire.oxy.edu
+> #friendly  ChemBot   H@  cmrobert@hellcat.ecn.uoknor.edu
+> 
+> 
+> 
+> >From Norman : 
+> 
+> *** ChemBot is cmrobert@hellcat.ecn.uoknor.edu (Charles Michael Roberts)
+> *** on channels: @#ChatZone 
+> *** on irc via server Norman.OK.US.undernet.org
+> *** ChemBot has been idle 10 minutes
+> 
+> 
+> and from Uxbridge : 
+> 
+> ** ChemBot is cmrobert@hellcat.ecn.uoknor.edu (Charles Michael Roberts)
+> *** on channels: @#chatZone @#friendly 
+> *** on irc via server Norman.OK.US.undernet.org
+> 
+> :-> But,
+> :-> 
+> :-> *** Mmmm has left channel #friendly
+> :-> *** Mmmm (mandar@roosevelt.ecn.uoknor.edu) has joined channel #test
+> :-> *** Users on #test: @Mmmm 
+> :-> 
+> :-> works fine..
+> :-> 
+> :-> Is this due to the U lines?  Uworld was in no way involved though :-(
+> :-> 
+> :-> I personally feel that uxbridge's retaining timestamps of old channels - 
+> :-> Run, can ya take a look asap. It can prove most distressing for our users :(
+> :-> 
+> :->                           Thanks!!
+> :-> 
+> :->                                                   Mmmm
+> 
+> 
+
+Weeehhhw, yeah a real bug :/
+
+RedRum and I looked for it for almost 4 hours before it was found...
+
+I will release .U3.2  and a patch for .U3.1-U3.2 asap...
+
+Description of bug:
+
+When someone gets kicked (and doesn't (try to) rejoin), it is flagged
+as a zombie. After a net-break, users are mutual re-joined on both
+sides of the net. It turned out that a zombie is also rejoined after
+a net rejoin.
+
+What happened with ChemBot:
+
+ChemBot was on #friendly via Norman (non TSpre8). It was banned and then
+kicked. It tried to rejoin, but Norman didn't allow that (ban).
+Delft never saw this try, and ChemBot stayed as a zombie on #friendly.
+Then Delft-UxBridge broke and reconnected... Delft did send a JOIN for
+ChemBot to UxBridge, ending up in a nick-desynced state.
+When Mmmm joined #friendly, he was the first on #friendly on all of the
+net except UxBridge... He was opped by Norman, but that is considered
+as a HACK by UxBridge and was bounced (ChemBot was still there *with*
+ops (those flags aren't reset when someone is marked zombie)).
+The second time Mmmm joined, he again got ops from Norman which now
+was accepted by UxBridge because this +o could be a BOUNCE of the de-op
+by UxBridge (Generating a BOUNCE or HACK: notice on UxBridge).
+
+Run
+
+
+
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: Release 2.8.19.U3.2
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Wed, 25 May 94 23:30:57 METDST
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+Hi all,
+
+I released 2.8.19.U3.2
+
+Fixed:
+
+        - Rejoining of zombies after net break :/  (ChemBot case)
+        - Silence command now give: No such nick, when doing /silence nick
+        - I fixed the way a kick is handle, because in a last minute
+          thought I realized MURC would get trouble otherwise, see below.
+
+As usual you can get it from ftp.undernet.org:/pub/undernet/servers
+
+Patches/irc2.8.19.U3.1-2.patch     : If you already had .U3.1
+
+irc2.8.19.U3.2.tar.gz              : If start from scratch (DO SO!!!)
+
+For those who use the irc2.8.19.U3.1-2.patch ...
+
+------------------------------------------
+*** EDIT include/patchlevel.h !!!!!!!! ***
+------------------------------------------
+
+This patch will change your version to irc2.8.19.U3.2  so if you run
+ .ban  EDIT it !!!
+
+=========================================================================
+
+The change in KICK handling is as follows:
+
+- A kick received from a local client, or for a local client or
+  from a direction in which the kicked client is located, is
+  simply handled as before: completely removed from channel, no zombie.
+  This means also that there is no client-server protocol change anymore:
+  /who, /whois and /names won't change.
+
+- A kick received for a local client originating from a remote client
+  lets the server sent a PART upstream. Since this results for non TSpre8
+  servers in a remote "You're not on that channel" message, this
+  message is suppressed (would never occur anyway now we are completely
+  synced).
+
+The reason why this was needed is mainly because MURC constantly kicks
+people who have auto-rejoin disabled from different channels. With U3.1
+they would get into problems after ten channels (needed to send extra
+PART's).
+
+Run
+
+--
+-------------------------------------------------------------------------------
+|  carlo@sg.tn.tudelft.nl           |  Run @ IRC                              |
+|                                   |  Admin of Delft.NL.EU.undernet.org      |
+| * Don't expect anything of live,  |  and      Ircserver.et.tudelft.nl       |
+| or you'll miss all the rest of it.|                                         |
+-------------------------------------------------------------------------------
+
+
+
+=============================================================================
+                       U3->U4, ANTI NICK COLLIDE 
+=============================================================================
+Author: Carlo, carlo@sg.tn.tudelft.nl, Run on IRC.
+
+Hi all...
+
+After we dealt with channel msg-, join/part- and nick-floods (.bquiet),
+and with private message flooding (.silence), now in a sort of follow up
+to the anti net.break.ride (.TSpre7) and anti admin.hacks (TSpre8) we are
+about to deal with one of the last vulnerabilities of our net:
+nick-collision bots.
+Called .anc (anti nick collision).
+             -    -    -
+
+Socially spoken it does the following (I hope):
+
+- Only kills the RIGHT person, when a nick collision occurs.
+
+This would mean:
+
+A) If someone tries to harash by connecting to servers that just broke off
+and then take the nick of a person on the other side, both would be
+killed on reconnection. But with the .anc patch on both connecting servers,
+only the net.break rider will be killed.
+
+B) Secondly, when your server (or side) breaks off and you connect to some
+other server on the other side, it happens sometimes that due to lag you get
+killed by a nick collision after reconnection of the net.
+
+A and B differ strongly in the sense that in case A the *new* -the youngest-
+nick must be killed, while in case B the *old* (lagged) nick must be
+killed.
+Technically this means that we have to look at the user@host.name too.
+This gives rise to some incompatible changes, and therefor, this patch
+must be done in two steps: First we deal with the nick-collision bots and
+make the server compatible with both - the old and new protocol. And then
+once all server upgraded, we deal with the last step: the nick collision
+with yourself.
+
+In the future there will be a third possible condition in which we can have
+a nick collision: (long example follows, can be skipped)
+
+C) The net breaks, and reconnects else where, and somehow a race condition
+occurs between the 'SERVER' messages of the servers of one side.
+For example:
+
+Servers:        Part A                  Part B1                 PartB2
+Nicks           a(A),b(B)               a(A),b(B)               a(A),b(B)
+Part A breaks off Part B:
+                <-- :b QUIT             --> :a QUIT
+                <-- SQUIT serversB      --> SQUIT serversA
+Result:         a(A)                    b(B)                    b(B)
+A reconnects to Part B1, but immedeately breaks off again:
+                        -->SERVERs A
+                        -->NICK a
+                        -->:a USER ...
+Break: 
+                                                -->SERVERs A
+                                                -->NICK a
+                                                -->:a USER ...
+                                        --> :a QUIT
+                                        --> SQUIT serversA
+A connects to part B2, note that 'part B1 --> part B2' is lagged and the
+"SERVERs A ... etc" didn't arrive yet on partB2.
+Servers:        Part B1                 Part B2                 Part A
+Nicks:          b(B)                    b(B)                    a(A)
+                        -->SERVERs A
+                        -->NICK a
+                        -->:a USER ...
+                --> :a QUIT
+                --> SQUIT serversA
+                                                --> SERVERs B
+                                                --> NICK b
+                                                --> :b USER ...
+                                                <-- SERVERs A
+                                                <-- NICK a
+                                                <-- :a USER ...
+Result *before* the lagged messages arive on Part B2:
+Nicks:          b(B)                    b(B),a(A)               b(B),a(A)
+                        -->SERVERs A
+                        -->NICK a
+                        -->:a USER ...
+                        -->:a QUIT
+                        -->SQUIT serversA
+And when the lagged messages arrive on Part B2, the
+'SERVERs A' get all ignored: "server exists", even more, Part B2 disconnects 
+Part B1... :/. Now we are going to deal with the "server exists" problem
+*once* (attaching a timestamp to SERVER I think), in which case 'SERVERs A'
+would only be ignored by Part B2. Then the 'NICK a' would cause a nick
+collision with 1) Same user@host.name, 2) same server A, and 3) same
+nick-TS ! This means: We need to ignore 'NICK nick' when is has the same 
+TimeStamp and the same user@host. But when the user@host differ, two people 
+signed on at exactly the same time with the same nick and we must kill 
+*both* to avoid a desync.
+----
+
+How to handle a nick collision, general
+---------------------------------------
+
+Up till now when a nick collision occurs, both nicks (when a nick change
+from 'old' to 'new' is involved) are KILLed in ALL directions.. wiped off the
+net thus.
+But even with wiping off the net in mind, it doesn't make sense to kill in
+old direction, it is sufficient to deal with "our side" of the net, because
+every nick collision occurs on two servers, both can deal with their side.
+As an example:
+
+Servers:        A               B
+Nicks:          a(A)            a(B)
+Reconnection:
+                <-- NICK a
+                    NICK a -->
+
+As you see, if A receives the 'NICK a' from B, it only has to deal with
+its own side, because it is certain that B will receive the 'NICK a' from
+A and handle it too as a nick collision (and therefore this 'NICK a' *is*
+already a 'KILL' message).
+
+Thus, when we receive a 'NICK' that gives rise to the need of purging
+a nick on *our* side, we deal with it by doing:
+sendto_serv_butone(cptr,":%s KILL ...
+which sends the KILL to all server connections except the link 'cptr' that
+generated the nick collision.
+Also then we have to destroy the memory usage of the killed client on our
+own server, and disconnect him if it is ours, so we call exit_client().
+
+Summary so far
+--------------
+
+Ok, we discussed when to kill who. Resulting rules are:
+
+We receive a "NICK new" or ":old NICK new" from a server direction, and
+we already have a registered 'new'. Then we have a nick collison and deal
+with it as follows:
+1) If the user@host differ,
+        and our 'new' is younger or equal, KILL our 'new'.
+        and our 'new' is older, ignore the 'NICK new', but kill 'old' on
+                our side if it was a nick change.
+2) If user@host is the same:
+        and our 'new' is older, KILL our 'new'.
+        and our 'new' is younger, ignore the 'NICK new', but kill
+                'old' on our side if it was a nick change.
+        and our 'new' is equal, KILL our 'new',
+                and kill 'old' on our side too if it was a nick change.
+
+Remarks:
+        The last case, where have a ':old NICK new' collission with
+the same user@host and TimeStamp, can't be case C), but it
+is possible that *we* did send a 'NICK new', and the server at
+the other side kills 'old' off... So we have to do it too.
+        With this protocol we *ignore* 'NICK new' message, but of course
+in most cases they will be followed by at least a ':new USER ...' and
+probably
+more like ':new JOIN #...'. This would cause 'Fake direction' errors and
+the current protocol KILLs such a nick in *ALL* direction (???). Now, we
+DON'T want to KILL the nick in the right direction do we? And killing the
+fake direction nick makes no sense: it will be killed automatically due to
+the fact we did send a 'NICK new' in that direction. Thus: we can/have to
+remove the Fake Direction kills.
+        Of course, when we receive a 'NICK new hopcount :TimeStamp', we
+*can't* compare with the user@host, because it takes some time before we
+will receive the 'USER'... We also can't store the nick, because it must
+be unique. To solve this, we need to change the protocol so that 'NICK new'
+contains all information and the USER message will be redundant and removed
+in a later patch. This also reduces net.bursts.
+        
+Attaching a TimeStamp (TS) to nicks
+-----------------------------------
+
+Whenever someone takes a new nick, which is available of course, either by
+changing nick or by signing on, the local server attaches a TimeStamp (TS)
+to the nick. Now there will be sent:
+
+NICK new hopcount TS user host.name server.name :Real name
+or
+:old NICK new :TS
+
+This is 100% compatible with the existing protocol.
+
+When a server receives such a nick from a neighbouring server it copies the
+TS, keeping track of the local change time. (When not all servers have
+upgraded, and no TS is received, the .anc server will fill in the time
+itself - being a slight advantage over keeping it 0. It also will assume 
+that the host.names are equal or not equal resulting a as many kills as 
+needed in the worst case).
+
+
+Examples
+--------
+
+Servers:    A                     B
+Nicks:      a(A),b(B)             b(B),a(A)
+Both change simultaneously to nick 'c', but 'a' slightly faster (at time=1,
+and b at time=2):
+            c(A),b(B)             c(B),a(A)
+                 -> :a NICK c :1
+                 :b NICK c :2 <-
+Then A receives a ':b NICK c :2' where 2 > 1, and KILLs b on its own side.
+B however receives ':a NICK c :1' where 1 < 2, and KILLs c on its own side.
+Result:     c(A)                  c(A)
+
+Due to 'lag', more :c PRIVMSG .. from B to A can follow, resulting in a
+fake direction. 'A' will simply ignore them and not kill c (kills for
+fake direction are nonsense anyway).
+
+In the case that someone signs on, taking the same nick as a nick change
+we have almost the same:
+
+Servers:    A                     B
+Nicks:      a(A)                  a(A)
+'a' changes simultaneously to nick 'c', but slightly faster (at time=1),
+as a new 'c' signs on at B (time=2).
+            c(A)                  a(A),c(B)
+                -> :a NICK c :1
+                  NICK c 1 :2 <-
+Then A receives a 'NICK c 1 :2' where 2 > 1, and ignores it simply.
+B however receives ':a NICK c :1' where 1 < 2, and KILLs c on its own side.
+Result:     c(A)                  c(A)
+
+If the new 'c' was a little bit earlier, we get:
+
+Servers:    A                     B
+Nicks:      a(A)                  a(A)
+'a' changes simultaneously to nick 'c', and slightly slower (at time=2),
+as a new 'c' signs on at B (time=1).
+            c(A)                  a(A),c(B)
+                -> :a NICK c :2
+                  NICK c 1 :1 <-
+Then A receives a 'NICK c 1 :1' where 1 < 2, and KILLs c on its own side.
+B however receives ':a NICK c :2' where 2 > 1, and KILLs a on its own side.
+
+Result:     c(B)                  c(B)
+
+Last case, two people sign on (or during a net reconnection):
+
+Server:     A                     B
+Sign on:    c(A)                  c(B)
+                -> NICK c 1 :1
+                   NICK c 1 :2 <-
+Then A receives 'NICK c 1 :2' where 2 > 1, and ignores it.
+and B receives a 'NICK c 1 :1' where 1 < 2, and KILLs c on its own side.
+Result:     c(A)                  c(A)
+
+Note: the above didn't take equal TS's into account, and I assumed
+user@hosts to be different: the nick collision bot cases.
+
+A last possibility when someone starts hacking... a 'NICK new' twice
+from the same direction, should not be accepted: we kill the earlier one
+always.
+
+Compatibility problems
+----------------------
+
+In the future, we want to also take 'user@host' into account... Therefor,
+we need to start to ignore 'NICK new' and only act upon ':new USER ...'.
+We can only do that if also 'USER contains the hopcount and TimeStamp'...
+If we change the protocol immedeately to say:
+:nick USER user host.name server.name hopcount TimeStamp :Real name
+the 'hopcount' would be treated as realname, and we the rest would be
+lost :(
+
+We can also transfer the info to 'NICK', with:
+
+:server.name NICK nick hopcount user host.name TimeStamp :Real name
+
+and later forget the USER message. Although someone lamer uses
+the C source line " if (sptr == cptr) ..." in m_nick() to determine if
+it was a 'NICK new' or a ':old NICK new' :/ Geesh (unlogical). He should
+have used " if (IsServer(sptr)) ...". You would need three upgrade steps
+or we will have to do with:
+NICK nick hopcount user host.name server.name TimeStamp :Real name
+
+The nice thing about this is, that we can check how many parameters we
+receive and then immedeately use the user@host if it is there... That way
+the .acn will immedeately work once everyone upgraded once, and the second
+step would only get rid of the 'USER' line between servers.
+
+Run
+
+
+=============================================================================
+                                WALLOPS
+=============================================================================
+Usage: /WALLOPS <message>
+
+Sends a message to IRC ops on-line. Remember that users who are /umode +w
+can see wallops as well.
+
+
+=============================================================================
+                                STATS W
+=============================================================================
+Author: Michael Vanloon (michaelv@iastate.edu) - mlv on IRC  
+Help on /stats w :
+
+I've been working on something I think would be quite a useful
+addition to the ircd.  It keeps track of the average number of local
+clients, total clients, and total connections (including servers) over
+various periods of time, currently over the last minute, hour, day and
+week.  It is invoked by "/stats w server.name".  You may try it
+yourself by "/stats w *.iastate.edu".  A sample from
+ircserver.iastate.edu looks like this:
+
+*** Minute    Hour      Day       Week      Userload for:
+***  44.91     39.4      33        33       iastate.edu clients
+*** 114.40    103.2      69        65       total clients
+*** 120.40    109.0      73        70       total connections
+*** * End of /STATS report
+
+I'm debating changing it to show average connections over the last
+minute, hour, day, prev. day, and prev. day, as I think the data
+doesn't change enough after that to really be useful to justify
+keeping it over an entire week.
+
+On smaller, less used servers, it should add a negligible amount to
+the resident memory consumed by the ircd.  On a large hub such as the
+*.bu.edu servers, penfold, or ircserver.iastate.edu, it might add as
+much as 300k to the amount of memory the ircd attempts to keep
+resident.  The amount is determined solely by the number of
+connects/disconnects the server processes over the span of time
+measured.
+
+The code is bulletproof and has undergone *extensive* debugging and
+testing before I announced it here.
+
+The reason I'm posting this is because I would like to know how many
+people think this would be a useful addition to the server.  In
+addition, I'd like feedback on whether you think this should be a
+standard part of the distributed server code.  I think it should, but
+Avalon wants me to post here first and see how others feel about it.
+I'd appreciate your input.
+
+I will be making a patched 2.7.2 server available with this included,
+for those who would like to have this and stability too.  I'll also be
+hooking it into 2.8.x soon, and giving it back to Av to include in the
+standard 2.8 distribution as it matures, if he sees fit to do so.
+
+Thanks for your time...
+
+                                --Michael (mlv)
+
+IRC log started Wed Aug 18 21:52
+*** Value of LOG set to ON
+*mlv* it's the usage of your server
+*mlv* average number of users on your server over the last minute, hour, day, yesterday, and the day before
+*mlv* local clients, total clients, and total connections (clients + servers)
+-ircserver.iastate.edu- Minute   Hour  Day  Yest.  YYest.  Userload for:
+-ircserver.iastate.edu-  23.00   23.0   16    17      11   iastate.edu clients
+-ircserver.iastate.edu-  52.00   52.8   37    35      23   total clients
+-ircserver.iastate.edu-  61.00   61.7   45    42      21   total connections
+-> *mlv* hmm...so iastate had 23 local clients in the last minute?
+*mlv* right... in the last minute the average number of local users on our server was 23
+*mlv* 23.45 actually
+-> *mlv* okie...gotcha... thanks :)   one other thing
+*mlv* there were an average of 23.1 local users on here over the last hour
+*mlv* shoot
+-> *mlv* is it possible to specify multiple domains?
+-> *mlv* for e.g.  uoknor.edu  and  okstate.edu    cos those will be local to midway
+*mlv* it could be coded in, but 1) my code doesn't support it out of the box, and 2) that would add more state info which would increase the memory usage a bit
+-> *mlv* hmm...
+*mlv* it's purely informational... i wouldn't worry about it, really that much
+-> *mlv* okay...also, the Makefile on the ftp site seems hosed.....there's junk at the end...I tried both the .Z and the .gz
+*mlv* i'm thinking about making it log by connection class... but i'll have to use a more efficient statistical algorithm (less precise) if i do that
+*mlv* that way you could put all the local domains into certain classes
+*mlv* oh yeah... it's harmless, just weird
+-> *mlv* that'll work :)
+-> *mlv* well...thanks for your help....will have a look at the stats w patch when you're finished with it :)
+IRC Log ended *** Wed Aug 18 22:22
+
+
+=============================================================================
+                        BAN/TOPIC/SIGNON INFO
+=============================================================================
+Author: Paul Foley (pfoley@kauri.vuw.ac.nz)  SIO on IRC
+
+Help on Ban/Topic/Signon :
+
+Since these patches allow the server to maintain additional information, the
+server replies have been changes for the /mode #channel +b (#367), /whois
+(#317) and an additional reply #333 has been added for topic info. The time
+is returned as a long integer in UTC format in all cases. Since the existing
+clients will ignore this additional information, you will need to either
+patch the client, or in case you're using ircII, use the foll. /on statements
+to take benefit of these patches :
+
+on ^367 * if ([$4] != []) {echo *** $1 \($3 - $stime($4)) $2} {echo *** $1-}
+on ^333 * echo *** Topic for $1 set by $2 on $stime($3)
+on ^317 * if (index(012345679 $3) != -1) {echo *** $1 has been idle for $2 seconds.  Signon at $stime($3)} {echo *** $1 has been idle for $2 seconds.}
+
+
+Once you have done this, you can see info as follows:
+/mode #wasteland +b
+*** #wasteland (Mmmm - Thu Aug 19 04:44:24 1993) test!*@*
+
+/topic #wasteland
+*** Topic for #wasteland: We all love Axl Rose!
+*** Topic for #wasteland set by rbarnes on Thu Aug 19 04:26:56 1993
+
+/whois Mmmm
+*** Mmmm is mandar@essex.ecn.uoknor.edu (Mmmm,I get high with a little help
++from my friends)
+*** on channels: @#wasteland
+*** on irc via server essex.ecn.uoknor.edu (MIDWEST HUB..HELPS YOU GET THERE
++SOONER)
+*** Mmmm is an IRC Operator
+*** Mmmm has been idle for 454 seconds.  Signon at Wed Aug 18 23:47:19 1993
+
+
+=============================================================================
+                        CLIENT NOTIFY
+=============================================================================
+Authors: Patrick Ashmore (pda@engr.engr.uark.edu) - Twilight1 on IRC
+         Mandar Mirashi  (mmmirash@mailhost.ecn.uoknor.edu) - Mmmm on IRC
+         Tony Vencill    (vencill@iastate.edu) - Tony/Tonto on IRC
+
+Help on Client Notify:
+
+This patch allows all opers on your server to see clients connecting to your
+server and disconnecting from it (with the reason why they disconnected). 
+This can help you identify troublesome clients, or redirect remote clients
+to closer servers, or troubleshoot the reason why a client disconnected.
+
+A sample output:
+
+*** Notice -- Client connecting : Karll (agifford@sci.dixie.edu).
+
+*** Notice -- Client exiting : Karll (agifford@sci.dixie.edu) [Bad link?].
+
+PS: if you wish to selectively decide when you wish to see these connection
+notices, use the foll. script
+
+on ^server_notice "% % NOTICE -- CLIENT*" if (hideit != 1) {echo *** $2-}
+alias show @ hideit = 0;echo *** You can now see clients connecting/exiting
+alias hide @ hideit = 1;echo *** You will no longer see clients connecting/exiting 
+
+If you then wish to not see client connects/exits when you are opered, simply
+type /hide. If you wish to see them again, type /show.
+
+=============================================================================
+                        TRACE TIMES
+=============================================================================
+Author: Tony Vencill    (vencill@iastate.edu) - Tony/Tonto on IRC
+
+Help on Trace Time:
+
+  This useful patch lets you identify the times since your server last
+heard from any connected servers or clients. This time is displayed in
+seconds, appended to each line of your /trace output. It can be very
+helpful in identifying which servers are going to drop off or which
+clients may ping timeout from your server.
+
+A sample output:
+
+/trace essex*
+*** Serv [30] ==> 10S 8C cancun.caltech.edu *!*@essex.ecn.uoknor.edu 73
+*** Serv [30] ==> 9S 6C imageek.york.cuny.edu *!*@essex.ecn.uoknor.edu 27
+*** Serv [0] ==> 1S 0C inga1.acc.stolaf.edu[130.71.192.16]
++*!*@essex.ecn.uoknor.edu 58
+*** Serv [0] ==> 1S 0C shadow.acc.iit.edu *!*@essex.ecn.uoknor.edu 97
+*** Serv [0] ==> 1S 2C curie.ualr.edu Mmmm!mmmirash@essex.ecn.uoknor.edu 98
+*** Serv [0] ==> 1S 1C piaget.phys.ksu.edu *!*@essex.ecn.uoknor.edu 117
+*** Oper [0] ==> Mmmm[essex.ecn.uoknor.edu] 0
+*** Serv [50] ==> 1S 0C pv1629.vincent.iastate.edu *!*@essex.ecn.uoknor.edu 7
+*** Class 0 Entries linked: 6
+*** Class 50 Entries linked: 1
+*** Class 30 Entries linked: 2
+
+
+=============================================================================
+                       K- line comments
+=============================================================================
+Author: Mandar Mirashi (mmmirash@mailhost.ecn.uoknor.edu) - Mmmm on IRC
+
+This extremely useful patch allows you to specify either a comment or an
+interval in the 2nd field of the K line (instead of the previous format
+of just a restricted interval). The "comment" can even be configured to
+be a *file* name which can then be displayed to the client rejected via
+the K line. All existing K lines will work as they are. This patch is
+an *enhancement* to the K-lines.
+
+e.g. (of a comment field)
+
+K:*.sdsu.edu:Flooding.is.not.cool.lamer:masc0482
+
+As far as possible, do not use a white space in the comment field, because
+this breaks ircII's /stats k handling. You can use the period (.) or the
+underscore instead (_).
+
+e.g (of a file to be output to a rejected client 
+     -   #define COMMENT_IS_FILE  in config.h)
+
+K:*.netcom.com:/ecn/staff0/irc/servers/vinson/sorry.txt:*
+
+
+=============================================================================
+                               OPER FAIL
+=============================================================================
+Authors: Michael Vanloon (michaelv@iastate.edu) - mlv on IRC  
+         Jon C Green (jcgreen@iastate.edu) - Jon2 on IRC
+        Bryan Collins (b@ctpm.org) - bwy on IRC
+
+This patch notifies you if someone tries to gain oper on your server and
+fails. The notice goes out only to the operators on the server.
+
+*** Notice -- Failed OPER attempt by M (mmmirash@lincoln.ecn.uoknor.edu)
+[crackit]
+
+
+=============================================================================
+                               MIXED CASE
+=============================================================================
+Authors: Michael Vanloon (michaelv@iastate.edu) - mlv on IRC
+         Jon C Green (jcgreen@iastate.edu) - Jon2 on IRC
+
+"Here's a patch mlv and I wrote that prevents clients with mixed-case usernames
+from connecting.  I don't know of many sites that allow mixed-case, so it
+is effective for stopping many clonebot attacks and also stops many
+would-be username hackers."  - Jon2
+
+This has been slightly modified by Mmmm to give an option of ignoring the
+case of the first character if desired (useful for those PC users who
+intuitevely enter their first name with the first letter capitalised).
+
+e.g.
+*** Notice -- Invalid username: buankBOT[saucer.cc.umr.edu]
+
+                               
+=============================================================================
+                               NOTE
+=============================================================================
+
+Usage:
+  \ 2NOTE\ 2 USER [&passwd] [+-flags] [+-maxtime] <nick!username@host> <msg>
+-   or  SEND|SPY|FIND|WAITFOR|NEWS <same as USER args.>
+*   or  SEND|SPY|FIND|WAITFOR|WALL|WALLOPS|DENY|NEWS|KEY <see USER args.>
+  \ 2NOTE\ 2 LS|COUNT|RM|LOG [&pwd][+-flags][#ID] <nick!user@host> [date]
+  \ 2NOTE\ 2 FLAG [&passwd] [+-flags] [#ID] <nick!username@host> <+-flags>
+*  \ 2NOTE\ 2 SENT [NAME|COUNT|USERS] <f.nick!f.name@host> <date> [RM]
+-  \ 2NOTE\ 2 STATS [MSM|MSW|MUM|MUW|MST|MSF|USED]
+-  \ 2NOTE\ 2 SENT [NAME|COUNT]
+*  \ 2NOTE\ 2 STATS [MSM|MSW|MUM|MUW|MST|MSF|USED|RESET] [value]
+*  \ 2NOTE\ 2 SAVE
+
+  The Note system have two main functions:
+  1. Let you send one line messages to irc users which 
+     they will get when they next sign on to irc.
+     Example: NOTE SEND <nick> Hi, this is a note to you.
+  2. Let you spy on people, to see when they sign on or off,
+     change nick name or join channels.
+     Example: NOTE SPY +100 <nick>  (spy on nick for 100 days)
+
+  You may fill in none or any of the arguments listed above, including
+  * or ? at any place, as nick@*.edu, !username, ni?k!username etc...
+  Other usefull features may be NOTE WAIT <nick>, making nick and
+  you get a message when you both are on at the same time.
+  Note was developed 1990 by jarle@stud.cs.uit.no (Wizible on IRC).
+
+
+*Usage: NOTE [<server>] ANTIWALL
+*  Switch off b flag for wall's which you have received on specified
+*  server. The person who queued the wall would be notified about
+*  the antiwall, and who requested this.
+
+
+Usage: NOTE COUNT [&<passwd>] [+|-flags] [#<ID>] <nick!username@host>
+  Displays the number of messages sent from your nick and username. See
+  HELP LS for more info. See HELP FLAG for more info about flag setting.
+
+
+*Usage: NOTE DENY [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+*              <nick!user@host> <msg>
+*  DENY is an alias for USER +RZ (default max 1 day)
+*  This command makes it impossible for any matching recipient to
+*  queue any Note requests until timeout.
+
+
+Usage: NOTE FIND [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> <msg>
+  FIND is an alias for USER +FLR (default max 1 day)
+  This command makes the server search for any matching recipient, and
+  send a note message back if this is found. If <msg> field is used, this 
+  should specify the realname of the person to be searched for. Examples:
+    FIND -4 foo*!username@host
+    FIND @host Internet*
+    FIND nicky Annie*       
+    FIND +7 * Annie*
+
+
+Usage: NOTE FLAG [&<passwd>] [+|-<flags>] [#<ID>]
+               <nick!username@host> <+|-flags>
+  You can add or delete as many flags as you wish with +/-<flag>.
+  + switch the flag on, and - switch it off. Example: -S+RL
+  Following flags with its default set specified first are available:
+    -S > News flag for subscribing.
+    -M > Request is removed after you sign off.
+    -Q > Ignore request if recipient's first nick is equal to username.
+    -I > Ignore request if recipient is not on same server as request.
+    -W > Ignore request if recipient is not an operator.
+    -Y > Ignore request if sender is not on IRC.
+    -N > Let server send a note to you if message is delivered.
+    -D > Same as N, except you only get a message (no queued note to you).
+    -R > Repeat processing the request until timeout.
+    -F > Let server send note info for matching recipient(s). Any message
+         part specify what to match with the realname of the recipient. 
+    -L > Same as F, except you only get a message (no queued note to you).
+    -C > Make sender's nicks be valid in all cases username@host is valid.
+    -V > Make sender's "nick*" be valid in all cases username@host is valid.
+    -X > Let server display if recipient signs on/off IRC or change
+         nickname. Any message specified is returned to sender.
+    -A > Show what server matching user is on using X flag.
+    -J > Show what channel matching user is on using X flag.
+    -U > Do not display nick-change using X flag.
+    -E > Ignore request if nick, name and host matches the message text
+         starting with any number of this format: 'nick!name@host nick!... '
+*    -B > Send a message to every account who match the nick!user@host 
+*         This creates a received list with flag H set. (see LS +h)
+*    -T > Send a message not all nicks on same accounts too using B flag.
+*    -K > Give keys to unlock privileged flags by setting that flags on.
+*         The recipient does also get privileges to queue unlimited 
+*         numer of requests, list privileged flags and see all stats.
+*    -Z > Make it impossible for recipient to queue anything at all.
+  Other flags which are only displayed but can't be set by user:
+    -O > Request is queued by an operator.
+    -G > Notice message is generated by server.
+-    -B > Broadcasting message.
+*    -H > Flag list for who's received Broadcast message (B flag).
+-  Notice: Message is not sent to recipient using F, L, R or X flag.
+-  Using this flags, no message needs to be specified.
+*  Notice: Message is not sent to recip. using F, L, R, X, K, Z or H
+*  flag (except if B flag is set for R). For this flags, no msg. needed.
+
+  Examples:
+    FLAG * +cj     : Switch on c and j flag for all requests.
+    FLAG +x * +c   : Switch on c flag for all req. which have x flag.
+    FLAG nick -c+j : Switch off c flag and which on j flag for nick
+
+
+*Usage: NOTE KEY [&<passwd>] [+|-<flags>] [+|-<maxtime>] <nick!user@host>
+*  KEY is an alias for USER +KR (default max 1 day)
+*  This command is for allowing no-opers to use oper-options by specifying
+*  the flag to unlock. Be careful with this option!
+*  Example: KEY +365 +s * would make it possible for everybody to use s flag.
+
+
+Usage: NOTE LOG [&<passwd>] [+|-<flags>] [#<ID>] <nick!username@host>
+  Displays how long time since matching person was on IRC. This works 
+  only after use of NOTE SPY. The log is protected to be seen for other
+  users than the person who queued the SPY request. To get short
+  output, do not specify any arguments. Example:
+    LOG      : Print short log of all
+    LOG *    : Print long log including real names of all
+    LOG nick : Print long log for user nick.
+
+
+Usage: NOTE LS [&<passwd>] [+|-<flags>] [#<ID>]
+               <nick!username@host> [<date>]
+  Displays requests you have queued. No arguments would show you
+  all requests without the message field.
+  Use flags for matching all messages which have the specified flags set
+  on or off. See HELP NOTE FLAG for more info about flag settings. Time 
+  can be specified on the form day.month.year or only day, or day/month, 
+  and separated with one of the three '.,/' characters. You can also 
+  specify -n for n days ago. Examples: 1.jan-90, 1/1.90, 3, 3/5, 3.may.
+  If only '-' and no number is specified max time is set to all days.
+  The time specified is always the local time on your system. Example:
+    LS !user    would show you all requests to username@*
+    LS +x       would show all your SPY requests.
+    LS #300     would show you only request #300.
+
+
+Usage: NOTE NEWS [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <group!username@host>
+  NEWS with no message is an alias for USER +RS (default max 60 days)
+  This command is for subscribing on a specified newsgroup from any
+  user(s) or host(s). Wildcards may be used anywhere. Example:
+    NEWS irc.note       : Subscribe on irc.note
+*    NEWS irc.note@*.no  : Send to group irc.note, but only for
+*                          users at host *.no
+*    NEWS irc.note       : Send to all for group irc.note
+*    NEWS Users@*.edu Hi : Send Hi to all users using note in your
+*                          server located at host *.edu.
+   (Advanced users may use User +rs <...> <filter> where filter is a 
+   string which must matches with field in received news message)
+-  Only opers can send news as default.
+*  To send news add message and use same format as subscribing, except 
+*  that username field must matches with subscribed group as alt.irc!*.irc - 
+*  everybody subscribing on a*.irc or *.irc or alt.irc... would get the news.
+*  A speciall case is the group Users which everybody using note in the server
+*  are member of.
+
+
+Usage: NOTE RM [&<passwd>] [+|-<flags>] [#<ID>] <nick!username@host>
+  Deletes any messages sent from your nick and username which matches
+  with nick and username@host. Use flags for matching all messages which
+  have the specified flags set on or off. See HELP FLAG for more info
+  about flag settings, and HELP LS for info about time.
+
+
+*Usage: NOTE SAVE
+*  SAVE saves all messages with the save flag set. Notice that the
+*  messages are automatically saved (see HELP STATS). Each time server is
+*  restarted, the save file is read and messages are restored. If no users
+*  are connected to this server when saving, the ID number for each
+*  message is renumbered.
+
+
+Usage: NOTE SEND [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> <msg>
+  SEND is an alias for USER +D (default max 60 days)
+  This command is for sending a message to recipient, and let the server
+  send a note + a notice to sender if this is on IRC - if message is sent.
+    SEND foobar Hello, this is a test.
+    SEND +7 !username@*.edu Hello again!
+
+
+-Usage: NOTE SENT [NAME|COUNT]
+*Usage: NOTE SENT [NAME|COUNT|USERS] <f.nick!f.name@host> <date> [RM]
+  Displays host and time for messages which are queued without specifying
+  any password. If no option is specified SENT displays host/time for
+  messages sent from your nick and username.
+  NAME displays host/time for messages sent from your username
+  COUNT displays number of messages sent from your username
+*  USERS Displays the number of messages in [], and names for all users
+*  who have queued any message which matches with spec. nick/name/host.
+*  RM means that the server removes the messages from the specified user.
+
+
+*Usage: NOTE SERVICE <nick> <note command>
+*  Useful in robots. Note will take the requests as if from <nick>
+
+
+Usage: NOTE SPY [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> [msg]
+  SPY is an alias for USER +RX (default 1 max day)
+  SPY makes the server tell you if any matching recipient sign(s)
+  on/off IRC or change nick name. No message needs to be specified.
+  However, if a message is specified this is returned to sender including
+  with the message about recipient. Message could for example be one or
+  more Ctrl-G characters to activate the bell on senders machine.
+  As an alternative for using C flag, <msg> field could start with
+  any number of nicks on this format: %nick1 %nick2... %nickn, with
+  no space between % and the nick name you use. Spy messages would be
+  valid for any of the nicks specified.
+  SPY with no argument would tell you what users you have spy on who are 
+  currently on IRC. The system logs last time the last matching person was 
+  on IRC for each SPY request is queued in the server. See NOTE LOG for this.
+  You may use flag +A to see what server matching user is on, 
+  and/or +J flag to see what channel. (Read HELP NOTE USER for more). Example:
+    SPY foobar!username@host <ctrl-G>
+    SPY +10 foobar
+    SPY +aj &secret * <ctrl-G>
+    SPY +365 +e !user nick!*@* <ctrl-G>
+    SPY % +7 foo!user
+    SPY +5 nicky %mynick %meenick
+
+
+-Usage: NOTE STATS [MSM|MSW|MUM|MUW|MST|MSF|USED]
+*Usage: NOTE STATS [MSM|MSW|MUM|MUW|MST|MSF|USED|RESET] [value]
+  STATS with no option displays the values of the following variables:
+    MSM: Max number of server messages.
+    MSW: Max number of server messages with username-wildcards.
+    MUM: Max number of user messages.
+    MUW: Max number of user messages with username-wildcards.
+    MST: Max server time.
+    MSF: Note save frequency (checks for save only when an user register)
+  Notice that 'dynamic' mark after MSM means that if there are more
+  messages in the server than MSM, the current number of messages are
+  displayed instead of MSM.
+  Only one of this variables are displayed if specified.
+*  You can change any of the stats by specifying new value after it.
+*  RESET sets the stats to the same values which is set when starting the
+*  server daemon if no note file exist. Notice that this stats are saved
+*  in same file as the other messages.
+
+
+Usage: NOTE USER [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> <msg>
+  With USER you can queue a message in the server, and when the recipient
+  signs on/off IRC, change nick or join any channel, note checks for
+  valid messages. This works even if the sender is not on IRC. See HELP
+  FLAGS for more info. 
+  Password can be up to ten characters long. You may specify password 
+  using the &, % or $ character. & is equal to to $, except working much
+  better cause client use $ for other things...
+  The % character works like &, except it makes the queuing silent. It
+  makess also sense to use this without any following password.
+  If any request queued is equal to any previous except time and maxtime,
+  only maxtime is changed as specified. You then get "Joined" instead of
+  "Queued". 
+  HELP FLAGS for info about flag settings. Username can be specified
+  without @host. Do not use wildcards in username if you know what it
+  is, even if it's possible. Max time before the server automatically
+  remove the message from the queue, is specified with hours with a
+  '-' character first, or days if a '+' character is specified, as
+  -5 hours, or +10 days. Default maxtime is 7 days.
+  Note: The received message is *directly* displayed on the screen,
+  without the need for a read or remove request.
+    NOTE USER &secret +WN +10 Wizible!jarlek@ifi.uio.no Howdy!
+  is an example of a message sent only to the specified recipient if
+  this person is an operator, and after receiving the message, the server
+  sends a note message back to sender to inform about the delivery.
+    NOTE USER +XR -5 Anybody <ctrl-G>
+  is an example which makes the server to tell when Anybody signs
+  on/off irc, change nick etc. This process repeats for 5 hours.
+    NOTE USER +FL @*.edu *account*
+  is an example which makes the server send a message back if any real-
+  name of any user matches *account*. Message is sent back as note from
+  server, or directly as a notice if sender is on IRC at this time.
+
+
+Usage: NOTE WAITFOR [&<pwd>] [+|-<flags>] [+|-<maxtime>]
+               <nick!username@host> [<msg>]
+  WAITFOR is an alias for USER +YD (default max 1 day)
+  Default message is [Waiting]
+  This command is for telling the recipient if this appears on IRC that
+  you are waiting for him/her and notice that this got that message. Example:
+    WAITFOR foobar
+    WAITFOR -2 foobar!username@*
+    WAITFOR foobar Waiting for you until pm3:00..
+
+
+*Usage: NOTE WALL [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+*                      <nick!user@host> <msg>
+*  WALL is an alias for USER +BR (default max 1 day)
+*  This command is for sending a message once to every matching user
+*  on IRC. Be careful using this command. WALL creates a list of 
+*  persons received the message (and should not have it once more time)
+*  with H flag set. This list can be displayed using ls +h from the
+*  nick and username@host which the WALL request is queued from.
+*  Removing the headers (H) before WALL request is removed would cause
+*  the message to be sent once more to what users specified in list.
+*  WALL +7 @*.edu Do not do this! - Makes it clear for all users using 
+*  IRC on host @*.edu the next 7 days how stupid it is to send such WALL's ;) 
+
+
+*Usage: NOTE WALLOPS [&<passwd>] [+|-<flags>] [+|-<maxtime>]
+*              <nick!user@host> <msg>
+*  WALLOPS is an alias for USER +BRW (default max 1 day)
+*  This command is same as WALL, except only opers could receive it.
+=============================================================================
diff --git a/doc/INSTALL b/doc/INSTALL
new file mode 100644 (file)
index 0000000..67fdf71
--- /dev/null
@@ -0,0 +1,963 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/INSTALL
+ *   Copyright (C) 1990,1991,1992, Jeff Trim, Mike Bolotski,
+ *   Jarkko Oikarinen and Darren Reed.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+
+            Installing IRC - The Internet Relay Chat Program
+
+
+Overview of this document:
+
+  1) The config.h file
+  2) Editing the Makefile
+  3) Compiling IRC
+  4) The ircd.conf file
+
+
+1) Edit the "config.h" file and make changes to the various #DEFINE's:
+   a) Copy the config.h.dist file to config.h before editing.
+  
+   b) Define what type of UNIX your machine uses.
+
+      Pick the machine type which best describes your machine and change
+      the #undef to #define (if needed).  Some flavours of Unix require no
+      #define and in such cases all others should be #undef'd.
+
+   c) DEBUGMODE
+
+       Define DEBUGMODE if you want to see the ircd debugging information
+      as the daemon is running. Normally this function will be undefined
+      as ircd produces a considerable amount of output.  DEBUGMODE must be
+      defined for either of -t or -x command line options to work.
+      
+   d) DPATH, SPATH, CPATH, MPATH, LPATH, PPATH
+
+        DPATH is provided so that the other pathnames (SPATH, CPATH, etc)
+      may be provided in just filename form.  When the server starts, it
+      chdir's to DPATH before chroot or any other file operation, making
+      it the "current directory" for the server.  This is where core files
+      will go if it core dumps.
+
+       Define SPATH to be the directory path to ircd.  This is usually
+      /usr/local/bin/ircd, unless you don't have installation permission
+      there. 
+
+      Define CPATH to be the directory path to the "irc.conf" file.
+      This path is usually /usr/local/lib/irc.conf. The format of this file 
+      will be discussed later.
+
+      The LPATH #define should be set to "/dev/null" unless you plan to 
+      debug the program.  Note that the logfile grows very quickly.
+
+      Define MPATH to be the path to the 'motd' (message of the day) file
+      for the server.  Keep in mind this is displayed whenever anyone
+      signs on to your server.
+
+      The PPATH is optional, but if defined, should point to a file which
+      either doesn't exist (but is creatable) or a previously used PPATH
+      file.  It is used for storing the server's PID so a ps(1) isn't
+      necessary.
+
+   e) CHROOTDIR
+
+       To use the CHROOTDIR feature, make sure it is #define'd and that
+      the server is being run as root.  The server will chroot to the
+      directory name provded by DPATH.
+
+   f) ENABLE_SUMMON, ENABLE_USERS
+
+       For security conscious server admins, they may wish to leave
+      ENABLE_USERS undefined, disabling the USERS command which can be used
+      to glean information the same as finger can.  ENABLE_SUMMON toggles
+      whether the server will attempt to summon local users to irc by
+      writing a message similar to that from talk(1) to a user's tty.
+
+   g) SHOW_INVISIBLE_LUSERS, NO_DEFAULT_INVISIBLE
+
+       On large IRC networks, the number of invisible users is likely to
+      be large and reporting that number cause no pain.  To aid and effect
+      this, SHOW_INVISIBLE_LUSERS is provided to cause the LUSERS command
+      to report the number of invisible users to all people and not just
+      operators.  The NO_DEFAULT_INVISIBLE define is used to toggle whether
+      clients are automatically made invisible when they register.
+
+   h) OPER_KILL, OPER_REHASH, OPER_RESTART, LOCAL_KILL_ONLY
+
+       The three operator only commands, KILL, REHASH and RESTART, may all
+      be disabled to ensure that an operator who does not have the correct
+      privilidges does not have the power to cause untoward things to occur.
+      To further curb the actions of guest operators, LOCAL_KILL_ONLY can
+      be defined to only allow locally connected clients to be KILLed.
+
+   i) The rest of the user changable #define's should be pretty much self
+      explanatory in the config.h file.  It is *NOT* recommended that any
+      of the file undef the line with "STOP STOP" in it be changed.
+
+3) Configure and compile the code.
+
+      Edit the root Makefile for the server, uncomment/comment the correct
+   CFLAGS/IRCDLIBS lines as appropriate for your system.
+      Change DESTDIR to be the same as the path for DPATH in config.h.
+   Type "make". This will compile the server, the client, and the services.
+   At the end of this step, the server directory will contain 'ircd',
+   and the client directory will contain 'irc'.  To get the server installed,
+   type "make install" which will build a default m4 file for preprocessing,
+   copy example.conf and put the server all in DESTDIR.  The irc client and
+   a copy of the server will also be placed in BINDIR and the modes set
+   accordingly.
+
+4) The ircd.conf file.
+
+   After installing the ircd and irc programs, edit the irc.conf file
+   as per the instructions in this section and  install it in the 
+   location you specified in the config.h file.  There is a sample
+   conf file called example.conf in the /doc directory.
+
+   Appendix A describes the differences between IP addresses and host
+   names.  If you are unfamiliar with this, you should probably scan 
+   through it before proceeding.
+
+   The irc.conf file contains various records that specify configuration
+   options.  The record types are as follows:
+   
+   1.  Server connections      (C,N)
+   2.  Machine information     (M)
+   3.  Client connections      (I)
+   4.  Default local server    (U)
+   5.  Operator priviliges     (O)
+   6.  Administrative info     (A)
+   7.  Excluded accounts       (K)
+   8.  Excluded machines        (Q)
+   9.  Connection Classes       (Y)
+  10.  Leaf connections         (L)
+  11.  Service connections      (S)
+  12.  Port connections                (P)
+  13.  Hub connections         (H)
+
+
+   1. SERVER CONNECTIONS:  How to connect to other servers
+                          How other servers can connect to you
+
+   WARNING:
+     The hostnames used as examples are really only examples and
+     not meant to be used (simply because they don't work) in real life.
+
+   Now you must decide WHICH hosts you want to connect to and WHAT ORDER you
+   want to connect to them in.  For my example let us assume I am on the
+   machine "rieska.oulu.fi" and I want to connect to irc daemons on 3 other
+   machines:
+
+         "garfield.mit.edu"        - Tertiary Connection
+         "irc.nada.kth.se"         - Secondary Connection
+         "nic.funet.fi"            - Primary Connection
+
+   And I prefer to connect to them in that order, meaning I first want to
+   try connecting to "nic.funet.fi", then to "irc.nada.kth.edu", and
+   finally to "garfield.mit.edu".  So if "nic.funet.fi" is down or
+   unreachable, the program will try to connect to "irc.nada.kth.se".
+   If irc.nada.kth.se is down it will try to connect to garfield and so forth.
+   PLEASE limit the number of hosts you will attempt to connect to down to 3.
+   This is because of two main reasons:
+     a) to save your server from causing extra load and delays
+        to users
+     b) to save internet from extra network traffic
+        (remember the old rwho program with traffic problems when
+        the number of machines increased).
+
+   The format for the CONNECT entry in the "irc.conf" is:
+
+       C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET Host PORT>
+Field: 1        2              3                4               5
+
+   for example:
+   
+    C:nic.funet.fi:passwd:nic.funet.fi:6667 
+
+          - or -
+
+    C:128.214.6.100:passwd:nic.funet.fi:6667
+
+          - or -
+
+    C:root@nic.funet.fi:passwd:nic.funet.fi:6667
+
+
+    Explanation:
+
+    Each field is separated with a ":" charcter:
+
+    Field 1: Field 1 tells the IRC program which option is being configured.
+             "C" corresponds to a server Connect option.
+
+    Field 2: Specifies the host name or IP address of the machine to connect
+            to.  If "user@" prefixes the actual hostname or IP address
+            the server will require that the remote username returned by
+            the ident server be the same as the one given before the "@".
+
+    Field 3: The password of the other host.  A password must always be
+            present for the line to be recognized.
+
+    Field 4: The full hostname of the target machine. This is the name that 
+            the TARGET server will identify itself with when you connect 
+            to it.  If you were connecting to nic.funet.fi you would receive
+            "nic.funet.fi" and that is what you should place in 
+            this field.
+  
+    Field 5: The INTERNET Port that you want to connect to on the TARGET 
+            machine. Most of the time this will be set to "6667".  
+             If this field is left blank, then no connections will 
+             be attempted to the TARGET host, and your host will accept
+             connections FROM the TARGET host instead.
+
+   Some examples:
+
+            C:nic.funet.fi::nic.funet.fi:6667
+            This reads: Connect to host "nic.funet.fi", with no password
+            and expect this server to identify itself to you as
+            "nic.funet.fi". Your machine will connect to this host to
+            PORT 6667.
+
+            C:18.72.0.252:Jeff:garfield.mit.edu:6667
+
+            This reads: Connect to a host at address "18.72.0.252", using a
+            password of "Jeff".  The TARGET server should identify
+            itself as "garfield.mit.edu".  You will connect to Internet
+            Port 6667 on this host.
+
+            C:irc.nada.kth.se::irc.nada.kth.se
+
+            This reads: do not attempt to connect to "irc.nada.kth.se",
+                       but if "irc.nada.kth.se" requests a connection,
+                       allow it to connect.
+
+   Now back to our original problem, we wanted OUR server CONNECT to 3
+   hosts,  "nic.funet.fi", "irc.nada.kth.se" and "garfield.mit.edu" in
+   that order.  So as we enter these entries into the file they must be
+   done in REVERSE order of how we could want to connect to them.
+
+   Here's how it would look if we connected "nic.funet.fi" first:
+
+       C:garfield.mit.edu::garfield.mit.edu:6667
+       C:irc.nada.kth.se::irc.nada.kth.se:6667
+       C:nic.funet.fi::nic.funet.fi:6667
+
+   Ircd will attempt to connect to nic.funet.fi first, then to irc.nada
+   and finally to garfield.
+
+   Reciprocal entries:
+
+   Each "C" entry requires a corresponding 'N' entry that specifies
+   connection priviliges to other hosts.  The 'N' entry contains
+   the password, if any, that you require other hosts to have before
+   they can connect to you.  These entries are of the same format as
+   the "C" entries.
+    
+   Let us assume that "garfield.mit.edu" connects to your server
+   and you want to place password authorization authorization on garfield.
+   The "N" entry would be:
+   
+          N:garfield.mit.edu:golden:garfield.mit.edu
+  
+   This line says: expect a connection from host "garfield.mit.edu",
+   and expect a login password of "golden" 
+   and expect the host to identify itself as "garfield.mit.edu".
+     
+         N:18.72.0.252::garfield.mit.edu
+
+   This line says: expect a Connection from host "18.72.0.252", and 
+   don't expect login password.  The connecting host should identify itself
+   as "garfield.mit.edu". 
+
+  
+   Wildcards domains: 
+       To reduce the great amount of servers in IRCnet wildcard
+       DOMAINS were introduced in 2.6. To explain the usage of
+       wildcard domains we take an example of such:
+               *.de  - a domain name matching all machines
+                        in Germany.
+        Wildcard domains are useful in that ALL SERVERS in Germany
+        (or any other domain area) can be shown as one to the
+       rest of the world. Imagine 100 servers in Germany, it
+       would be incredible waste of netwotk bandwidth to broadcast
+       all of them to all servers around the world.
+
+       So wildcard domains are a great help, but how to use them ?
+       They can be defined in the N-line for a given connection,
+       in place of port number you write a magic number called
+       wildcard count.
+
+       Wildcard count tells you HOW MANY PARTS of your server's name
+       should be replaced by a wildcard. For example, your server's
+       name is "tolsun.oulu.fi" and you want to represent it as
+       "*.oulu.fi" to "nic.funet.fi". In this case the wildcard count
+       is 1, because only one word (tolsun) is replaced by a wildcard.
+       If the wildcard count would be 2, then the wildcard domain would
+       be "*.fi". Note that with wildcard name "*.fi" you could NOT
+       connect to "nic.funet.fi", because that would result in a server
+       name COLLISION (*.fi matches nic.funet.fi).
+
+       I advice you to not to use wildcard servers before you know
+       for sure how they are used, they are mostly beneficial for
+       backbones of countries and other large areas with common domain.
+
+
+   2. MACHINE INFORMATION
+                            
+   IRC needs to know a few things about your UNIX site, and the "M" command
+   specifies this information for IRC.  The fomat of this command is:
+
+           M:<YOUR Host NAME>:xxx:<Geographic Location>:<Internet Port>
+   Field:  1         2         3           4                 5
+
+   Explanation:
+
+      Field 1: "M" specifies a Machine description line
+
+      Field 2: The name of YOUR host adding any Internet DOMAINNAME that 
+               might also be present.  
+
+      Field 3: -- NOT USED --: Set to Value NULL (No spaces at ALL!).
+    
+      Field 4: Geographic Location is used to say WHERE YOUR SEVRER is,
+               and gives people in other parts of the world a good
+               idea of where you are!  If your server is in the USA, it is
+               usually best to say: <CITY> <STATE>, USA.  Like for Denver
+               I say: "Denver Colorado, USA".  Finnish sites (like
+               tolsun.oulu.fi generally say something like "Oulu, Finland".
+      Field 5: The Internet port your server will use.  Should be set to
+              the same value as in the config.h file.
+
+
+      Example:
+                M:tolsun.oulu.fi::Oulu, Finland:6667
+
+                This line reads: My Host's name is "tolsun.oulu.fi" and
+                my site is located in "Oulu, Finland".  My ircd will use
+               Internet Port 6667.
+
+
+                M:orion.cair.du.edu::Denver Colorado, USA:6667
+
+                This line reads: My Hosts name is "orion.cair.du.edu"
+                and my site is located in "Denver Colorado, USA".
+               I have defined Internet Port number "6667" to be used
+                as my IRCD Socket Port.
+
+
+   3. CLIENT CONNECTIONS -   How to let clients connect to your IRCD.
+
+   A client is a program that connects to the ircd daemon (ircd).  Currently
+   there are clients written in C and in GNU Emacs Lisp.  The "irc"
+   program is the C client.  Each person that talks via IRC is running
+   their own client.
+
+   The irc.conf files contains entries that specify which clients are allowed
+   to connect to your irc daemon.  Obviously you want to allow your cwn
+   machine's clients to connect.  You may want to allow clients from 
+   other sites to connect.  These remote clients will use your server
+   as a connection point.  All messages sent by these clients will pass
+   through your machine.
+
+   The format of this entry in the conf file is:
+
+          I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Internet Port>
+    Field:1         2               3             4                5
+
+
+      For example, if you were installing IRC on tolsun.oulu.fi and you wanted
+      to allow examples sake let us assume you were making this file for
+      tolsun and you wanted to let your own clients to connect to your
+      server, you would add this entry to the file:
+
+      I:128.214.5.6::tolsun.oulu.fi
+      or
+      I:tolsun.oulu.fi::tolsun.oulu.fi
+
+      If you wanted to let remote clients connect, you could add the
+      following lines:
+
+      I:*.du.edu::*.du.edu
+
+      Allow any clients from machines whose names end in "du.edu" to connect
+      with no password.
+
+      I:128.214.6.100::nic.funet.fi
+
+      Allow clients from a machine with that IP number and the name 
+      nic.funet.fi to connect.
+
+      I:*.tut.fi:secret:*.tut.fi
+
+      Allow clients from machines matching *.tut.fi to connect
+      with the password 'secret'.
+
+      I:*::*
+
+      Allow anyone from anywhere to connect your server.
+      This is the easiest way, but it also allows people to for example
+      dump files to your server, or connect 1000 (or how many open
+      sockets per process your OS allows) clients to your machine
+      and take your network ports. Of course the same things can be
+      done by simply telnetting to your machine's SMTP port (for example).
+
+   NEW!!!
+      As of the 2.7.2d version of the server, the server is able to accept
+      connections on multiple ports. I-lines are required for each P-line
+      to allow connections to be accepted. For unix sockets, this means
+      either adding I:/path/port::/path/port or some variation (wildcards
+      are recognised here). For internet ports, there must be an I-line
+      which allows the host access as normal, but the port field of the
+      I-line must match that of the port of the socket accepting the
+      connectiion. A port number of 0 is a wildcard (matches all ports).
+
+   4. DEFAULT HOSTS (for local clients)
+
+      This defines the default connection for the irc client.  If you are
+      running an ircd server on the same machine, you will want to define
+      this command to connect to your own host.  If your site is not running
+      a server then this command should contain the TARGET host's connection
+      information and password (if any).  The format for this command is:
+
+         U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port>
+  Field: 1         2              3                4            5
+   
+
+      For example:
+
+           U:tolsun.oulu.fi::tolsun.oulu.fi:6667
+           U:128.214.5.6::tolsun.oulu.fi:6667
+           U:tolsun.oulu.fi::tolsun.oulu.fi
+
+      If the port number is omitted, irc will default to using 6667.
+
+  5. OPERATOR Privileges:  How to become the IRC administrator on your site
+
+   To become an IRC Administrator, IRC must know who is authorized to become
+   an operator and what their "Nickname" and "Password" is.  To add this
+   information, EDIT your "irc.conf" file and add the following command
+   line to it:
+
+          O:<TARGET Host NAME>:<password>:<nickname>:<port>:<class>
+  Field:  1          2             3          4        5       6
+
+  Explanation:
+     Field 1: Speficies Operator record. If you use capital letter ('O')
+              in it, it specifies a global operator. Small letter ('o')
+              specifies a local operator. Local operator has basically the
+              same rights except global operator with some restrictions.
+     Field 2: Tells IRC which host you have the privileges FROM.  This
+              means that you should be logged into this host when you
+              ask for the priviliges.  If you specify "tolsun.oulu.fi"
+              then IRC will expect your CLIENT to be connected at 
+              "tolsun.oulu.fi" - when you ask for OPERATOR privileges
+              from "tolsun.oulu.fi".  You cannot be logged in at any
+              other host and be able to use your OPERATOR privileges
+              at tolsun, only when you are connected at TOLSUN will this
+              work - this is a safeguard against unauthorized sites.
+
+
+     Field 3: If your AUTHORIZATION Password - this is the password that 
+              let's IRC know you are who you say you are!  Never tell anyone
+              your password and always keep the "irc.conf" file protected
+              from all of the other users.
+     Field 4: The Nickname you usually go by - but you can make this what
+              you want.  It is better to make this a NICKNAME that no one
+              else knows, but anything will do.  I usually use my own
+              loginname.
+
+     Field 5: Unused.
+
+     Field 6: The class field should refer to an existing class (preferably
+             having a lower number than that for the relevant I-line) and
+             determines the maximum number of simultaneous uses of the
+             O-line allowable through the max. links field in the Y-line.
+
+  Example:
+              O:orion.cair.du.edu:pyunxc:Jeff
+
+              There is an OPERATOR at "orion.cair.du.edu" that can get
+              Operator priviliges if he specifies a password of "pyunxc"
+              and uses a NICKNAME of "Jeff".
+
+
+
+  6. ADMINISTRATIVE INFORMATION
+
+  The "A" command is used for administrative information about a site.
+  The e-mail address of the person running the server should be included
+  here in case problems arise.
+
+  
+            A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other> 
+  Field:    1        2                    3                         4
+
+  Explanation:
+
+       Field 1: "A" specifies an Admin record.
+
+
+       Field 2: Use this field to say tell your FULL NAME and where in the 
+                world your machine is.  Be sure to add your City, 
+               State/Province and Country.
+
+
+       Field 3: Use this field to specify your Electronic Mailing Address
+                preferably your Internet Mailing Address.  If you have
+                a UUCP or ARAPnet address - please add that as well.  Be
+                sure to add any extra DOMAIN information that is needed,
+                for example "mail jtrim@orion" probably won't work as a 
+                mail address to me if you happen to be in Alaska.  But 
+                "mail jtrim@orion.cair.du.edu" would work because you 
+                know that "orion" is part of the DOMAIN "cair.du.edu". 
+                So be sure to add your DOMAINNAMES to your mailing addresses.
+
+       Field 4: Is really an OTHER field - you can add what you want here,
+                
+
+  Examples (the line is just one line in the confuration file, here it
+            is cut into two lines to make it clearer to read):
+
+A:Jeff Trim -  Denver Colorado, USA:INET jtrim@orion.cair.du.edu UUCP {hao,
+isis}!udenva!jtrim:Terve! Heippa!  Have you said hello in Finnish today?;)
+
+  Would look like this when printed out with the /admin command:
+
+      Jeff Trim -  Denver Colorado, USA
+      INET jtrim@orion.cair.du.edu   UUCP {hao,isis}!udenva!jtrim
+      Terve! Hei! Heippa!  Have you said hello in Finnish today? ;)
+  Note that the A record cannot be split across multiple lines; it will 
+  typically be longer than 80 characters and will therefore wrap around
+  the screen.
+
+
+  7. REMOVING A USER FROM IRC  Remove an errant user from IRC on your site.
+
+  Obviously it is hoped that you wouldn't have to use this command.
+  Unfortunately sometimes a user can become unmanageable and this is your
+  only recourse - the KILL USER command.  THIS COMMAND ONLY AFFECTS YOUR
+  SERVER - If this user can connect to another SERVER somewhere else in
+  the IRC-Network then you would have to talk to the administrator on that
+  site to disable his access from that IRCD Server as well.
+
+  The format of this command is:
+
+         K:<Host Name>:<time interval(s)>:<User>
+  Field: 1     2               3            4
+
+  Explanation:
+
+       Field 1:  "K" tells the IRCD that you are making a KILL USER command
+                 entry.
+
+       Field 2:  In this field you specify the Hostname that the user is 
+                 connecting from.  If you wanted to REMOVE connects
+                 to IRC from "orion.cair.du.edu" then you would want to enter
+                 "orion.cair.du.edu".  If you want to REMOVE ALL HOSTS
+                 access you can use '*' (Wild Card notation) and no matter
+                 what host the USERNAME (specified in Field 4) connects from
+                 s/he will be denied access. Removing all hosts isn't
+                 very smart thing to do though, why would you run an ircd
+                 if you allow nobody to connect to it anyways ?
+
+       Field 3:  Either leave this field empty (no spaces), then then lines
+                is active continuously for the specified user/host machine.
+                You may also specify intervals during the line should be
+                active, see examples above.
+    
+       Field 4:  The USERNAME of the user you want removed from IRC.  For
+                 example 'root'.
+
+   
+   Some Examples:
+                   K:orion.cair.du.edu::jtrim
+               If user 'jtrim' connects to IRC from host "orion.cair.du.edu"
+               then IMMEDIATELY REMOVE HIM from my IRCD.
+
+                   K:*.cair.du.edu::root
+
+               If user 'root' connects to IRC from any host that has the 
+               suffix "cair.du.edu" - then IMMEDIATELY REMOVE THEM from
+               my IRCD.
+
+                   K:*::vijay
+
+               This line reads "I don't care WHAT HOST user 'vijay' is on,
+               I will NEVER allow username 'vijay' to login to my IRCD.
+
+                  K:*.oulu.fi:0800-1200,1400-1900:*
+
+              This disallows all users from hosts with enddomain 'oulu.fi'
+              access to your server between 8 and 12am, 2 and 7pm.
+              Users get kicked off if they're already signed on when the
+              line becomes active (they'll get a warning 5 minutes ago).
+
+  8. Disallowing SERVERS in your irc net.
+
+   In some cases people run into difficulties in net administration.
+   For one reason or another you do not want a certain server to be
+   in your net (for example because of the security holes it opens
+   for every server if it's not secured carefully). In that case
+   you should use Q-lines in your server. When you specify a server
+   name in Q-line, everytime some server link tries to introduce you
+   a server (remember, all server names are broadcast around the net),
+   that name is checked if it matches the Q-lines in your server.
+   If it matches, then your server disconnects the link. Note that
+   just placing Q-lines to your server probably results in your server
+   being left alone, unless other servers have agreed to have the
+   same Q-line in their ircd configuration files as well.
+
+   Example:
+                Q::of the security holes:foo.bar.baz
+
+   This command excludes a server named "foo.bar.baz", the reason
+   is given to be security holes (you should give a reason, it is
+   polite). The first field is unused, so leave it empty.
+
+ 9. Connection Classes.
+
+   To enable more efficient use of MAXIMUM_LINKS, connection classes
+   were implemented. To give a connection a class, add another field
+   (a sixth) to the C/N lines for a particular server.
+   Each line for a server should have the same number as the sixth
+   field.  If it is absent, the server deaults it to 0, using the
+   defaults from the config.h file.  To define a connection class,
+   you need to include a Y: line in the irc.conf file.  This enables
+   you to define the ping frequency, connection frequency and maximum
+   number of links that class should have.  Currently, the Y: line MUST
+   appear in the irc.conf file BEFORE it is used in any other way.
+
+   The format for the line is:
+
+       Y:<CLASS>:<PING FREQUENCY>:<CONNECT FREQUENCY>:<MAX LINKS>:<SENDQ>
+Field: 1    2                3                4                5     6
+
+   Field 2:  This is the class number which gains the following attributes
+   and should match that which is on the end of the C/N line.
+
+   Field 3:  This field defines how long the server will let the connection
+   remain "silent" before sending a PING message to make sure it is still
+   alive.  Unless you are sure of what you are doing, use the default value
+   which is in your config.h file.
+
+   Field 4:  By changing this number, you change how often your server
+   checks to see if it can connect to this server.  If you want to check
+   very occasionally, use a large value, but if it is an important
+   connection, you might want a smaller value so that you connect to it
+   as soon as possible.
+
+   Field 5:  This field defines the maximum number of links this class
+   will allow from automatic connections.  Using /CONNECT overrides this
+   feature.
+
+   Field 6:  This field defines the 'sendq' value for this class.  If this
+   field is not present, the default (from config.h) is assigned.
+
+   NOTE: leaving any of the fields out means their value is 0 (ZERO)!!
+
+   example:
+
+   Y:23:120:300:5
+
+   define class 23 to allow 5 auto-connections, which are checked every
+   300 seconds.  The connection is allowed to remain silent for 120
+   seconds before a PING is sent.  NOTE: fields 3 & 4 are in seconds.
+
+   You may also give I lines a class (again the sixth field to define
+   which class).  This is only usefull (currently) for redefining the
+   ping frequency.  It can also be useful as a diagnostic to see how
+   much each I line is used when combined with the TRACE output.
+
+   Another feature of connection class is the ability to do automatic
+   routing by using the class as a 'priority'.  If you are connected
+   to a server which has a class lower than one of the servers that is
+   'behind' it, the server will disconnect the lower class one and
+   schedule a 'new' connection for the higher class server.
+
+ 10. Leaf Connections.
+
+   To stop servers which should only act as leaves from hubs becoming
+   hubs accidently, the L line was introduced so that hubs can be aware
+   of which servers should and shouldnt be treated as leaves. A leaf
+   server is supposed to remain a node for the entirity of its life
+   whilst connected to the IRC server network.  It is quite easy, however
+   for a leaf server to be incorrectly setup and create problems by
+   becoming a node of 2 or more servers, ending its life as a leaf. The
+   L line enables the administrator of an IRC 'Hub server' to 'stop' a
+   server which is meant to act as a leaf trying to make itself a hub.
+   If, for example, the leaf server connects to another server which doesnt
+   have an L-line for it, the one which does will drop the connection, once
+   again making the server a leaf.
+
+       L:<SERVER MASK>:*:<SERVER NAME>:<MAX DEPTH>
+Field: 1       2       3       4            5
+
+   Field 2 is a mask of which servers the leaf-like attributes are used on
+   when the server receives SERVER messages.  The wildcards * and ? may be
+   used within this field for matching purposes.  If this field is empty,
+   it acts the same as if it were a single * (ie matches everything).
+
+   Field 4 is the the server connectted to you that for which you want to
+   enforce leaf-like attributes upon.
+
+   Field 5 is the maximum depth allowed on that leaf and if not specified,
+   a value of 1 is assumed.  The depth is checked each time a SERVER message
+   is received by the server, the hops to the server being the field checked
+   against this max depth and if greater, the connection to the server that
+   made its leaf too deep has its connection dropped.
+   For the L-line to come into effect, both fields, 2 and 4, must match up
+   with the new server being introduced and the server which is responsible
+   for introducing this new server.
+
+ 11. Service Connections (Not yet implemented)
+
+  Introduction.
+   The Service is a special kind of IRC client. It does not have the full
+   abilities of a normal user but can behave in a more active manner than
+   a normal client. Services as they stand now are not fully implemented.
+   The following line can be added to your ircd.conf file to enable a
+   service:
+  
+          S:<TARGET Host Mask>:<password>:<service_name>
+  Field:  1          2             3          4
+
+  Explanation:
+
+    Field 2:
+       The host mask should be set to match the hosts(s) from which the
+       service will be connecting from. This may be either an IP# or full
+       name (prefered).
+
+   Field 3:
+       This is the password which must be passed in the SERVICE command.
+   Field 4:
+       The 'service name' is only used for the purpose of finding the
+       right S-line from the ircd.conf file for password matching. The
+       actual service name used is that set by NICK commands prior to
+       SERVICE being sent.
+
+   To connect a service to your server, you must first create an S-line
+   entry in your ircd.conf file and get your server to read this in (ie
+   rehash or reboot). Once your server has updated itself, you can then
+   attempt to register your connection as a service.
+   Registering as a service is similar to registering as a normal user
+   except that you must send NICK first and then SERVICE. The service
+   command should look something like this:
+
+       SERVICE secretpassword referencename :Service information
+
+   A successfull registering of a service at the server will result in
+   a RPL_YOURESERVICE (383) being sent back to you. Any other reply as
+   a result of sending service indicates an error has occured.
+
+   A service is not a very useful sort of client, it cannot join channels
+   or issue certain commands although most are available to it. Services,
+   however, are not affected by flood control. It is therefore wise to
+   oversee the use of S-lines with some care.
+
+ 12. Port Connections
+
+  Introduction.
+   The port line adds flexibility to the server's ability to accept
+   connections. By use of this line in the ircd.conf file, it is easy
+   to setup both Unix Domain ports for the server to accept connections
+   on as well as extra internet ports.
+
+       P:<Internet IP# Mask>:<*>:<*>:<PORT>
+Field: 1        2             3   4     5
+
+or
+
+       P:<Directory>:<*>:<*>:<PORT>
+Field: 1        2             3   4     5
+
+  Explanation
+   Internet Ports
+    Field 1
+       The internet IP mask defines where connections may come from and
+       be accepted. The IP mask uses either *'s or 0's as wildcards. The
+       following two lines are the same:
+
+               P:128.2.*:::6664
+               P:128.2.0.0:::6664
+
+       The incoming isnt matched against the mask, rather the ip# string
+       is decoded and compared segment by segment. Thus
+               P:128.2*.1.2:::6664
+       will not match 128.20.1.2.
+
+     Field 5
+       The port number field tells the server which port number it should
+       listen on for incoming connections.
+
+    Unix Socket Ports.
+     Field 1
+       The path set in field 1 should be the directory name in which to
+       create the unix socket for later listening to. The server will
+       attempt to create the directory before creating the unix socket.
+
+     Field 5
+       The port field when used in combination with a pathname in a P-line
+       is the filename created in the directory set in Field 1.
+
+     Example:
+               P:/tmp/.ircd:::6667
+
+       Creates a unix socket in the /tmp/.ircd directory called "6667".
+       The unix socket (file) must be a numerical.
+
+13.  Hub Connections
+
+      In direct contrast to L-lines, the server also implements H-lines to
+   determine which servers may act as a hub and what they may 'hub for'.
+   If a server is only going to supply its own name (ie act as a solitary
+   leaf) then no H-line is required for, else a H-line must be added as
+   follows:
+
+       H:<SERVER MASK>:*:<SERVER NAME>
+Field: 1       2       3       4
+
+   Explanation:
+    Field 2
+      All servers that are allowed via this H-line must match the mask
+      given in this field.
+
+    Field 4
+      This field is used to match exactly against a server name, wildcards
+      being treated as literal characters.
+
+   Examples:
+
+               H:*.edu:*:*.bu.edu
+
+       Allows a server named "*.bu.edu" to introduce only servers that
+       match the "*.edu" name mask.
+
+               H:*:*:eff.org
+
+       Allow "eff.org" to introduce (and act as a hub for) any server.
+
+   Note:  It is possible to have and use multiple H-lines (or L-lines) for
+         the one server.  eg:
+
+               H:*.edu:*:*.bu.edu
+               H:*.au:*:*.bu.edu
+
+          is allowed as is
+
+               L:*.edu:*:*.au
+               L:*.com:*:*.au
+
+
+Appendix A: Difference between IP addresses and hostnames
+
+
+   There are 2 different types of INTERNET addresses, NAME addresses and
+   NUMERIC addresses.  NAME addresses look like ENGLISH words (and indeed
+   they are ENGLISH words that refer to a given host).  A NAME address looks
+   like "tolsun.oulu.fi" - and that particular address refers to the machine 
+   named TOLSUN in Finland.  It is a UNIQUE address because no other machine
+   in the world has its NAME address the same as "tolsun.oulu.fi".  Anytime
+   you say "telnet tolsun.oulu.fi" - you would always connect to TOLSUN in
+   Finland.  NUMERIC addresses refer to those addresses that are made up of
+   NUMBERS for example "128.214.5.6" is the NUMERIC address for TOLSUN.  This
+   address is also UNIQUE in that no other machine in the world will be use 
+   those NUMERIC numbers.  The NUMERIC address is usually more reliable than
+   the NAME address because not all sites can recognize and translate the
+   NAME address into it's numeric counterpart.  NUMERIC always seems to work
+   best, but use a NAME address when you can because it is easier to tell
+   what host you are connected to.
+
+
+   Every Unix machine has a file called "/etc/hosts" on it.  This file 
+   contains NAME and NUMERIC addresses.  When you supply IRC with a NAME 
+   address it will at first try to find it in /etc/hosts, and then (if it's 
+   really smart), use the local Domain Name Server (DNS) to find the NUMERIC
+   address for the host you want to connect to.  Thus if you plan to use NAME
+   addresses keep in mind that on SOME sites the entry for the TARGET machine
+   must be found in /etc/hosts or the NAME address will fail.  A typical 
+   entry in /etc/hosts looks like this:
+
+   130.253.1.15    orion.cair.du.edu orion.du.edu orion    # BSD 4.3
+
+   This particular example is the Host ORION at the University of Denver. 
+   Notice that on the far left is the NUMERIC Address for orion.  The
+   next few ENGLISH words are the NAME addresses that can be used for orion,
+   "orion.cair.du.edu", "orion.du.edu", "orion".  ALL of these NAME addresses
+   will return the NUMERIC address "130.253.1.15" which IRC will use to
+   connect to the TARGET UNIX. (when I say TARGET UNIX I am refering to the
+   UNIX you want to connect to for IRC). Any futher questions about
+   /etc/hosts should be directed to "man hosts".
+
+
+Appendix B: Enabling Summon Messages
+
+   +-----------------------------------------------------------------------+
+   |            E N A B L I N G    / S U M M O N    M E S S A G E S        |
+   +-----------------------------------------------------------------------+
+
+   *NOTE* You must have ROOT or special access to the GROUP tty ('/dev')
+   to do this. If you want to allow users around the world to summon
+   users at your site to irc, then you should make sure that summon works.
+
+   The "IRCD" program needs access to the GROUP of '/dev'.   This
+   directory is where user TTY's are stored (as UNIX treats each Terminal
+   as a FILE!)   IRCD needs GROUP ACCESS to /dev so that users can be
+   SUMMONED to the program by others users that are *in* the program.
+   This allows people from other Universities around the world to SUMMON
+   your users to IRC so that they can chat with them.  Berkeley, SUN, HP-UX
+   and most of the newer versions of UNIX check to see if a USER is
+   accepting MESSAGES via the GROUP access rights on their TTY listing
+   in the /dev directory. For example an entry in '/dev' looks like this:
+
+  (Unix Path on BSD 4.3 UNIX is:  /dev/ttyp0)
+
+        crw------- 1 jtrim     20,     0 Apr 29 10:35 ttyp0
+
+   You will note that 'jtrim' OWNS this terminal and can READ/WRITE to this
+   terminal as well (which makes sense because I am ENTERING DATA and
+   RECEIVEING DATA back from the UNIX).  I logged into this particular
+   UNIX on "April 29th" at "10:35am" and my TTY is "ttyp0".  But further
+   of *note* is that I do not have my MESSAGES ON! (mesg n)  -- This is
+   how my terminal would look with MESSAGES ON (mesg y):
+
+        crw--w---- 1 jtrim     20,     0 Apr 29 10:35 ttyp0
+
+   With my MESSAGES ON (mesg y) I can receive TALK(1) requests, use the 
+   UNIX WRITE(1) command and other commands that allow users to talk
+   to one another.  In IRC this would also allow me to get IRC /SUMMON
+   messages.  To set up the "IRCD" program to work with /SUMMON type
+   the following:  (using ROOT or an account that has access to '/dev').
+
+       % chgrp tty ircd
+       % chmod 6111 ircd 
+
+   The above commands read: "Give IRCD access to GROUP tty (which is /dev)
+   and then when ANYONE runs the IRCD allow SETUID and SETGID priviliges
+   so that they can use the /SUMMON command.
diff --git a/doc/Manual b/doc/Manual
new file mode 100644 (file)
index 0000000..429f069
--- /dev/null
@@ -0,0 +1,382 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, doc/MANUAL
+ *   Copyright (C) 1990, Karl Kleinpaste
+ *
+ *   $Id$
+ *
+ *   This program is free software; you can 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.
+ */
+
+                                                Date: 04 Apr 1989
+                                              Author: Karl Kleinpaste
+                                                      karl@cis.ohio-state.edu
+                                                
+                                   Last modification: 15 May 1992
+                                                  by  Mauri Haikola 
+                                                      mjh@stekt.oulu.fi
+
+
+                        INTERNET RELAY CHAT
+                 a real-time conversational system
+
+
+* 1: Irc - replacement for talk(1)
+
+Irc is a functional replacement for and improvement to talk(1).  Talk
+is an old, primitive, atrocious, minimalist sort of keyboard/screen
+conversation tool, using a grotesque, machine-dependent protocol.
+Irc does everything talk does, but with a better protocol, allowing
+more than 2 users to talk at once, with access across the aggregate
+Internet, and providing a whole raft of other useful features.
+
+* 2: Entering Internet Relay Chat
+
+There are two ways to enter Internet Relay Chat. If you are using the
+emacs lisp client, you need to load the client into your Emacs session
+and then M-x irc. If you are using the C client (easier for beginners)
+then type (usually) irc. If you wish to be known by a nickname which
+is not one's login name, type `irc chosen-nickname' instead.
+
+* 3: How much can be seen from here
+
+The universe - seriously.
+
+This is most formally called Internet Relay Chat.  Server hosts are
+connected via a tree structure.  The various servers relay control and
+message data among themselves to advertise the existence of other
+servers, users, and the channels and other resources being occupied by
+those users.
+
+* 4: Structure
+
+There is quite a lot of structure to the operation of irc, as
+compared to crufty old talk(1).  Since so little could be done with
+talk(1), it needed little structure.  But to keep track of people
+spread literally around the world (the system was written by Jarkko
+Oikarinen of Finland, usually seen on the system as `Wiz'), the
+structure is useful so that one can speak to exactly those people with
+whom one wishes to speak.
+
+** 4.1: Nicknames
+
+All users of irc are known to the system by a `nickname.'  By
+default, one's nickname is one's login name.  Nickname clashes are not
+allowed; this is enforced by the servers.  If one's intended nickname
+clashes with someone else as one enters chat, one will not be able to
+complete entry to irc until one changes one's nickname to something
+else.
+
+** 4.2: Presence on a channel
+
+Fundamental to the operation of irc is the concept of a channel.  All
+users are `on a channel' while inside irc.  One enters the `null
+channel' first.  One cannot send any messages while not in any
+chatting channel unless one has set up a private conversation in some
+way.  The number of channels is essentially unlimited - whatever will
+fit in a string of some ungodly length, that must start with a # sign.
+
+** 4.3: Main modes of channels
+
+Public
+
+This is the default mode for a channel. When one is on a public
+channel, one can be seen by all other users (if one's own user mode
+permits this).  Anyone can notice users on a public channel and join
+such a channel's conversation.
+
+Private
+
+This means that, although anyone can see that one is using chat, no
+one can tell what channel one is using unless one is already on that
+channel with oneself.  Since the number of potential channels is in
+the billions, this is quite some security - all one gives away is the
+acknowledgement that one is using chat.
+
+Secret
+
+While one is on a secret channel, no one who is not on one's channel
+with oneself can even see that one is there.  One's name does not show
+up in a list of active users.  The only indication of one's presence
+is that, when entering chat, all new users are told that there are "N
+users on P servers."  If one checks on all users and finds less than N
+of them, one knows that others are hiding on secret channels.  But a
+secret channel user still cannot be found except by brute-force
+checking through all channels, a hopeless proposition in the face of
+the huge number of possible channel names. Security through obscurity
+finally means something.
+
+Changing the mode
+
+The mode of a channel (private, secret, invite-only, moderated,
+topic-limited, person-number-limited, no-messages-to-channel, ban
+someone from channel) is set by the channel operator, who is the
+first person to join a channel, or someone who has had channel
+operatorship bestowed on them by another channel operator. 
+
+
+*** 4.4: Conversations not using channels
+
+It is possible to conduct conversations with others without using the
+formalized channel structure.  Doing so requires that two people set
+themselves up for private conversation using special commands; see
+User Commands below.
+
+* 5: Screen/keyboard structure
+
+Chat is a full-screen utility.  It takes over the screen, with the
+bulk of activity happening in the top N-2 lines, a modeline (vaguely
+emacs-like) on the next to last line, and one's input being entered on
+the last line.  A very good version of client is the IRC-II client,
+avaliable on anonymous ftp from various sites around the world.
+
+** 5.1: Keyboard input
+
+When typing commands at irc, one has a minimalist line-editing
+facility in an emacs style.  That is, ^A moves the cursor to the
+beginning of the line, ^E goes to the end, ^D deletes the character
+under the cursor, ^K kills from the cursor to the end, and so on.  
+
+** 5.2: Screen activity
+
+Almost everything happens in the upper bulk of the screen.  This
+includes both messages from other users, as well as the output of the
+control commands.
+
+Normal messages from other users appear with the originating nickname
+in <angle brackets>.  Private messages arrive with the originating
+nickname in *asterisks*.  Messages which one sends to everyone appear
+with a preceding "> " whereas messages which one sends privately to
+one other user appear with "-> *nickname*."
+
+Other output (e.g., /who commands, invitations from other users to
+join channels, and so forth) appears interspersed with other activity
+on the screen.
+
+* 6: Command structure
+
+Ordinary text typed at irc is sent as one's messages to everyone else
+on the same channel, modulo personal choices for private messages and
+the like.  Commands to irc itself all begin with a command character,
+which is initially `/' but may be changed to any other character
+desired.
+
+Commands may in general be abbreviated to a unique prefix.
+
+** 6.1: Leaving irc
+
+The way to get out of irc is to enter the /signoff command.  "/si" is
+sufficient.  Also equivalent are "/exit," "/bye," and "/quit." A
+signoff command may include a comment which will be seen by everyone
+on the current channel of the person who left.
+
+** 6.2: Getting help
+
+Type "/help."  Follow the instructions.
+
+** 6.3: User commands
+
+The most important commands supported by irc are:
+
+      help   signoff       who     whois
+      list     topic      join   channel
+     links       msg    invite    ignore
+     users     stats      nick      away
+      info     clear     query     cmdch
+      date      mode
+
+*** 6.3.1: help
+
+Information on how to use the rest of the system is available via
+/help.  The modeline says so as well.
+
+*** 6.3.2: signoff {comment}
+
+/signoff exits chat. Optional comment may be included; see above.
+
+*** 6.3.3: who
+
+/who returns information on who is using chat.  /who without arguments
+prints info on all users that can be seen.  Users of public channels
+show up with their channel identified.  Users of private channels
+appear, but they are specified as being on a private, unspecified
+channel.  Users of secret channels and users whose user mode is +i
+(invisible) do not appear at all.
+
+Giving a channel name as an argument to /who returns only those users of the
+specified channel.  This still doesn't show users of secret channel or
+invisible users one is actually on the same channel with them. Users
+of private channels are shown, if an exact channel name is given.
+
+*** 6.3.4: whois
+
+This returns information about individual users.  Say "/whois
+nickname" to get information on the login name and host from which the
+nicknamed user comes.
+
+*** 6.3.5: topic
+
+Channels can be given off-the-cuff "topics."  Saying "/topic some
+string of text" will associate that topic with the current channel.
+
+*** 6.3.6: list
+
+/list will give lists of active channels, the number of users of each,
+and the topics therewith associated.  Again, secret channels do not
+appear and private channels only appear as Prv.
+
+*** 6.3.7: join & channel
+
+/join or /channel are the means to enter a channel.  Give the channel
+name as an argument.  If this is a secret or hidden channel, /who
+commands will show oneself and any other users of one's channel.
+
+One's arrival on a channel is announced to the rest of the users
+already on that channel.  Silent, anonymous "lurking" is not
+supported.
+
+*** 6.3.8: links
+
+/links lists the currently-active set of chat servers.  Beware: this
+list can be quite long, and will undoubtedly get longer as chat gains
+wider use.  As of 15 May, 1992, about 130 servers is typical.
+
+*** 6.3.9: msg
+
+A single message can be sent privately to a certain user with /msg.
+Type /msg nickname and the text to be sent.  It will be sent privately
+to the indicated nickname.
+
+*** 6.3.10: invite
+
+If there is a user online to whom one wishes to speak, one may invite
+that user to join oneself on a certain channel.  One types "/invite
+nickname" with an optional channel number.  The receiving user gets a
+one-line message indicating the sender and the invitation.  The
+receiving user is free to ignore the invitation, of course.
+
+*** 6.3.11: ignore
+
+If one wants to ignore messages sent by some other user or users, it
+may be done with /ignore command. One can ignore someone by their
+nickname, or by their user@host data. Wildcards may be used. 
+
+*** 6.3.12: users
+
+/users will return a list of the users logged into one's system.  With
+an optional hostname identifying a chat server host, the users logged
+into that system will be listed.
+
+*** 6.3.13: stats
+
+This command returns counts of various protocol operations of one's
+chat server.  It is neither particularly useful nor interesting to
+users other than operators.
+
+*** 6.3.14: nick
+
+One can change nicknames by issuing "/nick new-nickname."  All users
+on one's channel will be advised of the change.  NOTE: If one enters
+chat with a nickname clash (e.g., one's login name is the same as
+someone else's, and the other user got there first), the system will
+not let one enter until one issues a /nick command with a unique
+nickname.
+
+*** 6.3.15: away
+
+Sometimes, one wishes to remain connected to the chat system, but one
+must be elsewhere for a while.  One can issue an /away command with
+arbitrary text as argument, which will mark oneself as being away.  If
+someone sends an away'd user a private message (via /msg or in a
+private session set up via /query; see below), the sender will get a
+message back from the server indicating the away-ness and the message
+which was set.
+
+*** 6.3.16: info
+
+/info returns information regarding the author and copyright of the
+chat system.
+
+*** 6.3.17: clear
+
+At times, one wishes that one's screen weren't so cluttered.  /clear
+makes it so.
+
+*** 6.3.18: query
+
+This command is used to set up private communications `outside' the
+normal channel system.
+
+When one enters "/query nickname," the indicated nickname is set up as
+the sole recipient of anything which one types thereafter.  Thus, if
+user A executes "/query B" and user B executes "/query A," they have
+set up a private communication between themselves.  Significantly, it
+remains possible for them to stay on their respective channels, which
+need not be the same, and listen to whatever conversation is going on
+around them as well, though they cannot respond to that ambient
+conversation without leaving the private conversation they have set up.
+
+One leaves this private mode by issuing /query without arguments.
+
+*** 6.3.19: cmdch
+
+The `/' character may not be best for some people to use as their
+command character.  It can be changed with "/cmdch <character>."
+
+*** 6.3.20: mode
+
+This command can be used for altering the various modes of a channel
+(see the explanation of channel modes above). /mode command can only
+be issued by channel operators. 
+
+** 6.4: Operator commands
+
+The chat system administrators on each host have additional
+responsibilities and power over the configuration and operation of the
+servers.  The commands to do so are delineated below.
+
+*** 6.4.1: oper
+
+Users who have the potential for operator privileges initially invoke
+those privileges by "/oper nickname password," where nickname is the
+nickname under which operation is intended, and password is the
+password known to the chat system for that nickname.
+
+*** 6.4.2: kill
+
+Obnoxious users had best beware the operator who's fast on the /kill
+command.  "/kill nickname" blows any given nickname completely out of
+the chat system.
+
+Obnoxiousness is not to be tolerated.  But operators should not use
+/kill lightly.
+
+*** 6.4.3: quote
+
+Raw access to the underlying server protocol is possible through the
+user of the /quote command.  "/quote any text at all" is used to send
+direct, unmodified commands to the servers.  This has a wide variety
+of uses, such as deliberately killing a local or remote chat daemon,
+invoking operator privileges for otherwise-operator-priv-forbidden
+users, and related tasks.  It is, again, a very powerful operation,
+and not to be used lightly.
+
+* 7: Questions, problems, troubles?
+
+If you have problems, please contact Christopher Davis (ckd@eff.org) or
+Helen Rose (hrose@eff.org). Known as "ckd" and "Trillian" on irc,
+respectively. You can also ask for help on some of the operator
+channels on irc, for example #twilight_zone and #eu-opers. They will
+be able to assist you in whatever problems you are having with IRC.
+
diff --git a/doc/Operators b/doc/Operators
new file mode 100644 (file)
index 0000000..9b9489e
--- /dev/null
@@ -0,0 +1,241 @@
+Internet Relay Chat Operator Etiquette Guide (May, 1992)
+[ $Id$ ]
+
+Welcome! You've either been selected to be an IRC Operator or you have set
+up your server and thus have taken on the dual task of IRC Server
+Administrator and IRC Operator. Your future days will be filled with hours
+of fun chatting on IRC, and then wondering why everyone you talked to went
+away, because the links had apparently broken. 
+
+Linking:
+========
+
+You will be assigned links from the IRC Routing Coordinators. Please
+use these links and these links ONLY. The links have been designed to
+maximize efficiency and make delays in chatting minimal. You will
+usually be given two links, one to each regional backbone site.
+Connect to the primary site first and then to the secondary site. You
+should not need to connect to any other sites. You will be informed if
+this policy changes.
+
+Kills 
+=====
+
+/kill is a special operator command. You should use it with
+care, and only if absolutely needed. The format is as follows:
+/kill NICKNAME comment. Comment can be a phrase of almost any length
+(within reason) and should be used for specifying the reason of the kill.
+Example: /kill Trillian She's a Ghost
+IRC Ghosts are created after a net split has occured and the net has yet to
+relink. 
+
+/wallops PHRASE This is used to talk to those users who have their
+user mode set to +w. /wallops used to be a way for operators to talk
+about important matters in linking etc., but it has little use
+nowadays. 
+
+/TRACE command /TRACE is useful to know what servers are connected to
+what. Sometimes /trace can be confusing, especially if you are using
+it for the first time.  Here is an example of a trace from
+stekt1.oulu.fi to cdc835.cdc.polimi.it.
+
+/TRACE cdc835.cdc.polimi.it
+
+*** Link stekt1.oulu.fi<2.7.2> ==> cdc835.cdc.polimi.it
+*** Link rieska.oulu.fi<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link nic.funet.fi<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link ircserver.et.tudelft.nl<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link vesuv.unisg.ch<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Link apollo.di.unipi.it<2.7.1>e ==> cdc835.cdc.polimi.it
+*** Oper Class[10] ==> Allanon[cdc835.cdc.polimi.it]  
+*** User Class[11] ==> Lupandy[plus2.usr.dsi.unimi.it]  
+*** Serv Class[3] ==> apollo.di.unipi.it[131.114.4.36] 132S 445C
+*** User Class[11] ==> Punk[pluto.sm.dsi.unimi.it]  
+*** User Class[11] ==> TheEdge[pluto.sm.dsi.unimi.it]  
+*** User Class[10] ==> Mork[cdc835.cdc.polimi.it]  
+*** User Class[11] ==> Lollo[c700-2.sm.dsi.unimi.it]  
+*** User Class[11] ==> Attila[hp2.sm.dsi.unimi.it]  
+*** Class 0  Entries linked 1
+*** Class 11 Entries linked 5
+*** Class 10 Entries linked 2
+*** Class 3  Entries linked 1
+
+From this output you can see that the route goes first to
+rieska.oulu.fi (running version 2.7.1e), then nic.funet.fi,
+ircserver.et.tudelft.nl, vesuv.unisg.ch, and apollo.di.unipi.it, after
+which cdc835 is the next server. Then we see the connections on
+cdc835: One operator (Allanon) and 6 users are on line. The class of
+each connection is given. There is only one server connected to cdc835
+at the moment, and that server is apollo.di.unipi.it (cdc835 is said
+to be a "leaf" server at the moment). The numbers 132S 445C in the end
+of line tell us, that there are 132 servers and 445 clients connected
+to the servers from apollo onwards.  Finally we see a grand total of
+connections in each connection class. 
+
+
+/SQUIT server {comment}
+   /squit isolates a specified server from the next closest server, when
+you look at it along the trace path starting from your server. 
+This is usually used in conjunction with CONNECT (explained later) to
+reroute traffic. This will be described in detail in the section
+"routing", preceding CONNECT.
+
+   Usage (and examples): 
+
+      /squit E
+
+     If the network looks like this initially (and you are on server A)
+
+          A <---> B <---> C <---> D
+                          ^
+                          |
+                          v
+                  G <---> E <---> F <---> ... (rest of the net)
+                          
+
+    Then after issuing the previous /squit the network would look like this:
+
+          A <---> B <---> C <---> D
+                          
+                          
+                  G <---> E <---> F <---> ...
+
+
+    /squit E {comment}
+
+       It usually helps to give a reason why you are sending a
+       SQUIT for a server. This can be accomplished by sending
+       the command "/squit server This link is making the US route
+       through Finland". The SQUIT will then be sent out, and the 
+       server sending the squit will WALLOP sending the comment
+       so all operators can see it. 
+
+/CONNECT server {portnum server2}
+   /connect is used to establish a link between two servers. These
+connections must be authorized by each server's ircd.conf file, but
+any operator can issue a CONNECT between authorized servers. This
+command is most often used in conjunction with SQUIT to reroute
+traffic. 
+   If only one argument is given, this command causes the server you
+are on to attempt to connect to the server specified. For example,
+"/connect B" (in the previous example) would cause your server (A) to
+connect to B. 
+   Suppose you wanted to reconnect server F to server E? You cannot
+contact server F since it is no longer part of your network. However,
+you can tell server E to connect to it. A remote CONNECT can be issued
+to server E. 
+
+   Examples (assume you are on server A):
+
+   /connect B
+
+   If the network initially looks like this:
+
+         A      B <---> ... (rest of network)
+
+   Then afterwards (if the connection succeeds) the network will look
+   like this:
+
+        A <---> B <---> ... 
+
+
+   In the example where you wanted to reconnect server E to F, the
+   following syntax would be appropriate (note: we are assuming that
+   F's irc socket port is 6667, which is the default)
+
+   /connect F 6667 E
+
+   If the network initially looks like this:
+
+         A <---> B <---> C <---> D
+                         ^
+                         |
+                         v
+                 G <---> E      F <---> ... 
+
+   Then after your CONNECT request the network topology will look like this:
+
+         A <---> B <---> C <---> D
+                         ^
+                         |
+                         v
+                 G <---> E <---> F <---> ... 
+
+    Be careful when connecting servers that you know which command to
+    use! If you simply issued "/connect F" from your server, the
+    network would look like this:
+
+
+    ... <---> F <--->  A <---> B <---> C <---> D
+                                       ^
+                                       |
+                                       v
+                               G <---> E 
+
+    which for various reasons (discussed below) might be very
+    undesirable. 
+
+Routing
+=======
+
+   When and how should you do rerouting? This depends on where your
+server is topologically located and whether you route traffic. If you
+are a leaf node (i.e. only connect to one server at a time) then
+chances are you won't need to do any routing at all.  Your ircd.conf
+file should be written to connect to the best possible servers first
+before trying alternates. At the most, you may decide to squit an
+alternate server and connect to your primary if/when it goes back up.
+This only involves local squits, however.
+
+   If you are operating a backbone site, you may find yourself
+rerouting things quite often. If the servers badger.ugcs.caltech.edu
+(Pasadena, CA), irc.mit.edu (Boston, MA), minnie.cc.utexas.edu
+(Austin, TX) and ucsu.colorado.edu (Boulder, CO) were routing traffic
+in the following way:
+
+    ... <---> minnie <---> badger <---> bucsd <---> ucsu <---> ...
+
+It would make sense to either squit ucsu and reconnect it to minnie,
+or disconnect minnie from badger and connect to ucsu, because
+topologically (and geographically) ucsu and minnie are rather close.
+There are occasions when US traffic for some reasons winds up being
+routed through Australia. This is another case where traffic should
+definitely be rerouted. However, there are sometimes occasions when
+routing is going through "backdoor" methods. If you see something
+totally outrageous (like the east coast and the west coast being
+connected by eff.org) please ask for example on channel #twilight_zone
+before you send any squits, because chances are, it's like that for a
+reason.
+
+   Of course, any operator can remotely squit or connect servers, so
+if you see a problem and you're sure you know how to fix it, it's a
+good idea to do so. If the operator of a server which is is being
+routed poorly is online, it's probably best to contact him/her first,
+though.
+
+   Chances are that hub operators will be more familiar with the
+general topology of the network and which servers connect to which
+(which is why most of the manual routing is left to them), so if you
+have any problems, talk to the other operators on operator channels
+(#twilight_zone, #eu-opers etc.) That's what they are there for!
+   Also, be aware that servers will notify all the operators online of
+remote SQUITs and CONNECTs via WALLOPS.
+
+Please let us know if there should be any additions to this guide. Again,
+this is not MANDATORY, this is just a GUIDE. Please conduct yourself as 
+an IRC Operator would...you are looked upon for assistance, both emotional
+and mental. 
+
+Helen Rose             Christopher Davis       Noah Friedman
+<hrose@cs.bu.edu>      <ckd@cs.bu.edu>         <friedman@ai.mit.edu>
+
+January, 1991
+
+
+Updated by
+
+Mauri Haikola
+<mjh@stekt.oulu.fi>
+
+May, 1992
diff --git a/doc/conf.doc b/doc/conf.doc
new file mode 100644 (file)
index 0000000..b5169ea
--- /dev/null
@@ -0,0 +1,1582 @@
+esOriginally by Roddy Vagg -- roddy@dal.net
+modified for UnrealIRCD3.0
+
+--------------------
+
+       1) ............................. Introduction
+       2) ............................. ircd.conf Basics
+       3) ............................. ircd.conf Lines
+        3.1) .......................... M Lines
+        3.2) .......................... A Lines
+        3.3) .......................... Y Lines
+        3.4) .......................... I Lines
+        3.5) .......................... O Lines
+        3.6) .......................... U Lines
+        3.7) .......................... C and N Lines
+        3.8) .......................... K Lines
+        3.9) .......................... q Lines (server form)
+        3.10) ......................... Q Lines (nickname form)
+        3.11) ......................... L Lines
+        3.12) ......................... H Lines
+        3.13) ......................... P Lines
+        3.14) ......................... T Lines
+        3.15) ......................... E Lines
+        3.16) ......................... e Lines
+        3.17) ......................... Summary
+       4) ............................. dccdeny.conf
+        4.1) .......................... deny Lines 
+       5) ............................. chrestrict.conf
+        5.1) .......................... msg Lines
+        5.2) .......................... allow Lines
+       6) ............................. vhost.conf
+        6.1) .......................... vhost Lines
+       7) ............................. unrealircd.conf
+        7.1) .......................... Include Line
+        7.2) .......................... Set KLINE_ADDRESS Line
+        7.3) .......................... Set MODE_X Line
+        7.4) .......................... Set MODE_I Line
+        7.5) .......................... Set TRUEHUB Line
+        7.6) .......................... Set CONFIG_FILE_STOP Line
+        7.7) .......................... Set SHOWOPERS Line
+        7.8) .......................... Set KILLDIFF Line
+        7.9) .......................... Set SHOWOPERMOTD Line
+        7.10) .......................... Set HIDE_ULINES Line
+       8) ............................. network files
+        8.1) .......................... Network Line
+        8.2) .......................... Set ircnetwork Line
+        8.3) .......................... Set defserver Line
+        8.4) .......................... Set SERVICES_NAME Line
+        8.5) .......................... Set oper_host Line
+        8.6) .......................... Set admin_host Line
+        8.7) .......................... Set locop_host Line
+        8.8) .......................... Set sadmin_host Line
+        8.9) .......................... Set netadmin_host Line
+        8.10) ......................... Set coadmin_host Line
+        8.11) ......................... Set techadmin_host Line
+        8.12) ......................... Set hidden_host Line
+        8.13) ......................... Set netdomain Line
+        8.14) ......................... Set helpchan Line
+        8.15) ......................... Set STATS_SERVER Line
+        8.16) ......................... Set HUB Line
+        8.17) ......................... Set iHAN Line
+        8.18) ......................... Set net_quit Line
+
+--------------------
+
+1) Introduction:
+
+  If you are running, or planning on running an IRC server for a network,
+ you will need to setup an ircd.conf, your ircd.conf must meet the
+ requirements of a linked network server which means it must contain all
+ the standard network lines, these will be listed at the bottom of this
+ document. (If you make your own network you may customize them yourself)
+
+--------------------
+
+2) ircd.conf Basics:
+
+  When you compile your server, you must specify the correct paths to
+ where you plan on keeping your ircd.conf, for simplicity it is recomended
+ that you keep it in the same diretory as your ircd binary and other ircd
+ files.
+   note: You need only supply full pathnames for DPATH and SPATH, the
+ other defines will only point to files under these directories so you
+ need not put full path names.
+  For security reasons, your ircd.conf should have permissions set to 600,
+ if other users on your system gain access to view the file they may be
+ able to breach the security of your server and compromise the whole
+ network.
+  When you have made your ircd.conf you may check it with the program
+ `chkconf', this program is supplied with the source code release and will
+ be installed into your ircd directory when you run `make install',
+ `chkconf' will check your ircd.conf for errors so is a usefull tool for
+ beginners to ircd.conf.
+  Your ircd.conf will be made up of a series of lines, each line is used
+ for a different purpose in the running of your server, some lines are
+ mandatory for ircd, so you must enter these lines or your server will not
+ start, these lines are listed below.
+  You may enter comments in your ircd.conf with the use of a hash mark (#)
+ at the beginning of a line, it is recommended that you make full use of
+ this to add comments to everything you put in your ircd.conf so you dont
+ have any problems later.
+   eg: Put a contact email address and the name/nick of the server admin
+       above each C/N line pair.
+  When ircd reads the ircd.conf file, it does it upside down, so lines with
+ higher prefrence should go lower in the file, this will be explained later.
+
+--------------------
+
+3) ircd.conf Lines:
+
+  Each type of line in this section will be given a rating of how needed
+  it is in the running of the server, the ratings are:
+
+     MANDATORY: you absolutely MUST have this line
+     NETWORKED: you must have this line if plan on connecting your server
+                to other servers. (note: you can run ircd stand alone)
+     SUGGESTED: it is highly suggested that you use this line
+      OPTIONAL: it's completely up to you whether to define this or not
+   DISCOURAGED: you really really should not use this line if at all
+                possible.
+
+  Note that "*" in a field indicates an "unused" field.
+
+--------------------
+
+3.1) M Lines: [MANDATORY]
+
+ This line sets your server's name, description, and port number.
+ If you are to be a part of DALnet you will be assigned 2 different
+ DNS entries for your ircd machine, the 1st is for general public use
+ and involves: <servername>.DAL.net
+ The second is for use between servers for identification, these take
+ the form of: <servername>.[<state>].<country>.DAL.net
+ If your server is located in the US or Australia, you will be given
+ a `state' field in your server's real name, otherwise your `state', or
+ `area' will not be included.
+ Most IRC networks default to port 6667 for their client connection's,
+ but DALnet uses port 7000 as its standard, you should compile ircd with
+ port 7000, not 6667, but you may open up port 6667 (it is recomended
+ that you do) with a P line (see later). Your M line's port number
+ should be the same as the number you defined in your config.h at compile
+ time.
+ Syntax:
+M:hostname:IP:Description Of Your Server:7000
+ The 1st field should be the `real' name of your server, not the short
+ name.
+ The 2nd field is the IP the server should bind to - "*" if all interfaces
+     on the server
+ The 3rd field is your server's description, it is up to you what you
+ put in this field, but a short description of its geographic location
+ is recomended.
+ The 4th field is the port number you compiled ircd with. This should be
+ 7000 for DALnet.
+ Example:
+M:disney.irc.net::Walt's IRC Server:7000
+
+--------------------
+
+3.2) A Lines: [MANDATORY]
+
+ This line sets your server's administrative information.
+ Whenever a user types /admin on your server (or /admin <servername>)
+ they will recieve the information you put here.
+ This line has no set information, so you may put arbitrary text if you
+ like, but it is recomended that you at least put your nick and email
+ address so users may contact you if need be.
+
+ Syntax:
+A:A little info about your server:Admin's nick/real name:contact address
+ There is no fixed standard, so you may put whatever you like in each
+ field, but you should put enough information for users to contact someone
+ responsible for the server.
+
+ Example:
+A:Disney's IRC Server:Admin - Walt Disney:walt@RIP.org
+
+--------------------
+
+3.3) Y Lines: [SUGGESTED]
+
+ These lines define connection classes. They allow you to fine-tune
+ your incomming and outgoing connections, both server and client types.
+ These classes are for use with C, N, I and O lines, more on this in later
+ sections. DALnet has a set of Y lines that each server must use for their
+ server connections, these are listed below and again at the bottom of this
+ document. Client connection classes are your responsibility, you must
+ make up your own set of Y lines for client connections based on your own
+ situation (netwise location, machine, etc).
+ Connection classes define a number of parameters for connections, these
+ include:
+  o Ping frequency of a silent connection.
+  o Connect frequency (for server connections only!).
+  o Maximum number of links allowed on the specific connection class.
+  o Maximum sendq allowed for the connection before it is dropped.
+ Your Y line numbers are not arbitraty. For server connection classes, the
+ higher the class number, the higher the priority the connection's are given
+ when auto-connecting, (see C/N lines below).
+ - Ping frequency: When a connection is silent for this period of time
+ the server will send a PING to the connection, if the client/server
+ on the connection does not reply after a set period of time, the
+ connection will be dropped. A value in this field will override the
+ ping frequency defined at compile time in your config.h. For server
+ connection classes, you should have the same ping frequency on both ends
+ of the link, so you should stick with the standard DALnet classes.
+ - Connect frequency: Since clients connect to servers and NOT the other
+ way around, only server connection classes need to have a connect
+ frequency. Client classes should have this field set to 0. When a server
+ listed in the server's ircd.conf (see C/N lines) is missing and belongs
+ on a conenction class that is holding less connections that defined by
+ the max links field, the server will keep on trying to connect to
+ the missing server. The ammount time between connection attempts is what
+ you define in this field.
+  example:
+   server1 and server2 are listed in server0's ircd.conf but the only
+   visible server to server0 is server1, both server1 and server2 are
+   in server0's ircd.conf on the same connection class that allows for `2'
+   links, server0 will go looking for server2 and try to connect to
+   it each `connect frequency' seconds until the server becomes visible
+   again, either by direct connection to server0, or by connection to server1
+ - Maximum number of links: Each Y line should have a restriction on the number
+ of connections allowed on the class. For client connections, when the limit
+ is reached on a particular class, connecting clients trying to connect
+ through this class are rejected. A server connecting on a `full' connection
+ class will be allowed as this number on server connection classes is used for
+ auto-connect purposes. As shown in the above example, when a missing server
+ is listed for a particular connection class, and the class is not `full',
+ your server will try and connect to this server untill it becomes visible
+ again. Servers being connected manually on a `full' connection class via the
+ /connect command will be allowed as long as you compiled with MAXIMUM_LINKS
+ high enough to accomidate all of your server connections. (you must compile
+ as a HUB if you wish to hold more than one server connection, also see H
+ lines later in this document).
+ - Maximum sendq: SendQ defines the `que' of data waiting to be sent to the
+ client/server on the other end of the connection. SendQ's will build up if
+ the client requests more data than the link can handle, say if they issue the
+ /list command on a network with a lot of channels and they are only on a
+ 14.4K link, their sendq on the server will build up as all the data cannot
+ be sent at once, the sendq size will decrease as the data is sent, and
+ increase as more data is requested. Clients will normally sit with a sendq of
+ 0, it is `abnormal' for a sendq to be high for a client for a long period
+ of time. When 2 servers connect, they must send their own data to
+ eachother, this data includes: all the users on the server and already
+ connected servers, channels, user modes, channel modes, topics (DALnet only)
+ etc. When there are many clients on a particular side of the connection, a
+ sendq will build up, especially if the link is slow, or already congested
+ (example: the link from Australia to the US). When the sendq built up reaches
+ the max sendq defined in the connection class for the particular
+ client/server, the connection will be dropped. If max sendq's are
+ particularly high, it will allow clients/server to take up excess memory on
+ the ircd machine so a limit should be placed, especially on client connection
+ classes. (IMPORTANT!) If any value of max sendq defined in a connection
+ class exceeds the value defined at compile time in your config.h, the sendq
+ value will default back to the compile time sendq. If your sendq field in
+ a Y line is empty, the class will use the default defined in your config.h
+ SendQ's for all connections on your server can be viewed with the
+  /stats l <servername>
+ command, this will show information for all your server's current links.
+ You should have a set of standard server connection classes, at least one
+ client connection class, and an Operator class. (see relevant parts of this
+ document for notes on each of these)
+
+ Syntax:
+Y:Class #:Ping frequency:Connect frequency:Max links:Max sendq
+
+ Examples:
+Y:1:90:0:20:10000
+ In this case, connect-frequency is 0 indicating that this is a client
+ class (servers never connect to clients, it is the other way around).
+ Clients may only idle for 90 seconds before being pinged by the server.
+ The number of clients allowed to use this class is 20.
+ Clients may only build up a sendq on the server of 10000 bits.
+
+ These are the standard server Y lines used on DALnet:
+
+# Connecting a hub to a hub
+Y:20:10:300:1:3000000
+# Connecting a US hub to a US leaf
+Y:30:45:0:0:2000000
+# Connecting a US leaf to a US hub
+Y:35:45:20:1:2000000
+# Connecting a US hub to an EU leaf
+Y:40:60:0:0:2200000
+# Connecting an EU leaf to a US hub
+Y:45:60:20:1:2200000
+# Connecting a US hub to an AU leaf
+Y:42:240:0:0:2200000
+# Connecting an AU leaf to a US hub
+Y:43:240:60:1:2200000
+
+--------------------
+
+3.4) I Lines: [MANDATORY]
+
+ These lines are the ones initially responsible for letting clients connect
+ to your server. So called `client-authorization' lines, they define who
+ may connect, and which connection class they will connect through.
+ I lines, like C, N and O lines refer back to Y lines, as they allow
+ connections, and each connection to ircd needs to be assigned to a
+ connection class. If you dont provide a connection class, the connection
+ will be governed by the defaults set at compile time in your config.h.
+ When a client connects to the server, it gives its own information,
+ this information includes username, nick and can include a password, the
+ server then goes through its client-authorization rules (I lines) to see
+ if the client fits any of the connection criteria.
+ The rules for connection on the I lines are read from right to left, so
+ if a connection is made, it is made on the right most rule it matches on
+ the line. Also, since the ircd.conf is read upside down, the server will
+ put the client on the lowest I line matching the client information. This
+ means that if the 1st rule the client can connect on matches a connection
+ class (Y line) that is `full' (see above), the client will be rejected,
+ even if there is a line further up in the file that the client matches on
+ that uses a connection class that has room for more clients. This means
+ that I lines may be used in much the same fashion as K lines (see later)
+ to block certain clients. It also means that you may place certain clients
+ on many different connection classes. (examples later)
+ Syntax:
+I:IP-address-mask:optional password:host/domain-mask::connection class (opt)
+ Wildcards (`*') may be used in the mask fields (1 and 3) to allow for
+ very broad connection rules. Ident (for more information on this, see
+ rfc1413) can also be used by placing an `@' in the mask fields in the
+ appropriate positions. If you don't want to use ident, only give the
+ host/IP part of the connecting addresses, if you add a @ (usually used
+ as *@), ircd will try and use ident to check the real username of the
+ client, any connecting clients on host's that are running ident that
+ give usernames that dont match those found by ircd will be rejected by
+ the server. If the host is not running ident, a `~' will be placed in
+ front of the username of the connecting client to show that the its
+ host isnt running ident.
+
+ Examples:
+
+I:*@*:foobar:*@*::1
+ This line will allow anyone from any host that uses the password
+ "foobar" to connect through connection class 1 (Y line 1), the server
+ will also try and use ident to verify the username of the client.
+ Placed at the top of the I lines in your ircd.conf, this line may serve
+ as a fall-through for connecting clients, any client that does not match
+ any other I line but gives the password "foobar" will be able to connect
+ through this line (If Y line 1 has space).
+
+I:205.133.*::*.toledolink.com::1
+ This is a standard vanilla I: line which will permit anyone with an IP
+ address starting with 205.133 OR with a hostname ending in
+ .toledolink.com to connect to the server. remember, ircd uses the
+ right-most match, so if I connect as rmiller@glass.toledolink.com
+ (which is rmiller@205.133.127.8) I will show up on irc as
+ rmiller@glass.toledolink.com since that is the first match it found.
+ (Even though the second match is valid). Any clients comming through
+ on this line will use connection class 1.
+
+I:*@205.133.*::*@*.toledolink.com::1
+ Same as above, but the server will use ident. You may even specify
+ certain usernames with ident I lines, but they will only match if their
+ host is running ident.
+
+I:NOMATCH::rmiller@glass.toledolink.com::1
+ Putting NOMATCH in the first field will stop the ircd from matching
+ automatically against the IP address and it will force the server to
+ match against the hostname. (the "NOMATCH" string is not mandatory, you
+ can use any arbitrary text in the first field).
+
+I:*@*:ONE:*@*.com::1
+ Putting ONE is the second field says that only one user may connect through the 
+ use of this I:line. Once that one user is connected this I:line is ignored by 
+ other users.
+
+ Bulk example:
+I:NOMATCH::*@*::1
+I:NOMATCH::*@*.fr::2
+I:NOMATCH::*@*.de::3
+I:NOMATCH::*@*.se::4
+I:NOMATCH::*@*.au::5
+I:129.180.*::*.une.edu.au::6
+ In this example, conencting clients will 1st be matched against the mask
+ *.une.edu.au, if they match they will be placed on connection class 6
+ (note: if 6 is full, they will be rejected, they wont be passed on to the
+ next I line), then tried against the IP 129.180.*, if they match, they will
+ be placed on class 6. If the client dosen't match either of these masks, they
+ will be tried against the mask *.au, so if they are from Australia, but are
+ not from *.une.edu.au they will be placed on class 5. This goes on through
+ the other lines, being placed on the various connection classes if they match
+ any of the indicated host masks, if the client is not from the IP 129.180.*,
+ Australia, Sweden, Germany or France, they will be connected through the
+ final (top) I line as it serves as a fall-through, so these clients will be
+ put on class 1.
+
+--------------------
+
+3.5) O Lines: [OPTIONAL]
+
+ These lines provide rules as to who may gain Operator status on your server.
+ O lines are much like I lines in their operation and syntax.
+ Servers need not have any Operators as ircd, given well defined connection's
+ can perform all of its functions automatically. Server admins have the
+ ability to `kill -HUP' the server's PID to rehash the config file, removing
+ the need to use the /rehash command. However, a well running network such as
+ DALnet needs operators to oversee the users of the server, and make sure
+ users actually enjoy their time on IRC without being continually harrased
+ etc by troublematers.
+ O lines give users power over the whole network, to use commands
+ such as /kill, local Operators only have power on their local server, that
+ is, the server where they can use the /oper command to make themselves +o.
+ Abilities of Operators and Local Operators can be defined in your config.h.
+ When a user issues the /oper command to the server, the server will search
+ through all listed O lines for a match of the user's mask, much the same way
+ as I lines. As with I lines, you may specify the use of ident by placing an
+ `@' in the appropriate positions.
+
+ Syntax:
+
+O:hostname:password:nickname::class
+ See I lines for rules about the hostname and using ident.
+ If you use ident, a client matching the hostname must have ident running on
+ their host to be able to +o themselves.
+ If you compiled defining oper passwords to be crypted, you must 1st crypt
+ the plaintext using mkpasswd, a program supplied with the ircd distribution.
+ See src/crypt/README for more information on this.
+ The nickname is the nickname they must pass with the /oper command
+  ie:
+   /oper <nickname> <password>
+ The class is the connection class to be used when the user /oper's using
+ the O line, they connect using the standard I -- Y lines, but when they
+ /oper succusfully they are passed across to the new Y line.
+
+ Examples:
+
+O:RIP.org:waltspass:Walt::10
+ This line will allow anyone on the host RIP.org (running ident or not) to
+ issue the command `/oper Walt waltspass', at which point they will be moved
+ over to class 10 and be made usermode +o.
+
+--------------------
+
+3.6) U Lines: [OPTIONAL]
+
+ These lines define which server(s) on the network your server is connected
+ to will be able to `hack' channel modes.
+ On DALnet, services.dal.net is given this power, this allows the server
+ to change modes on channels without being a channel operator, the
+ commonly used form is ChanServ changing channel modes while not in the
+ channels.
+ If you are connected to a network such as DALnet that requires you to have
+ certain U lines and you don't have them, your server will cause problems
+ to the other servers when the server(s) that require U lines attempt to
+ change channel modes.
+ U lined servers also have the capability to add Akill's to your server,
+ Akill's are much the same as the /kline command except that they show up
+ as A: lines on /stats k.
+
+ Syntax:
+U:servername:*:*
+ The last 2 fields are currently unused so you only need to give the U
+ lined server's name.
+
+ Example:
+U:services.dal.net::
+U:services2.dal.net::
+ Both these lines are required on all DALnet server's, they allow servers
+ with the name's `services.dal.net' and `services2.dal.net' to hack channel
+ modes.
+
+--------------------
+
+3.7) C and N Lines [NETWORKED]
+
+ These lines are always used in pairs, one will not work without the other.
+ C lines define who your server may connect to, while N lines define what
+ servers may connect to you.
+ When two servers connect, they both send eachother the `SERVER' command,
+ this command contains the server name and server info (set by M lines)
+ along with this command is sent a password with the PASS command, C and N
+ lines provide a set of rules governing the connection between servers
+ given the details of the server and pass command's.
+ When one a server initiates the connection, the other server will check
+ the details of the incomming server against its N lines, if a match is
+ found, the server will return the server and pass command's to the
+ initiating server, which will also check its N lines for a match.
+ For a server to initiate a connection, it must have a C line. C lines
+ tell the server where to go to make the connection and what to send for
+ the pass command.
+ What this all means is that for two servers to make a complete connection,
+ they must have both C and N lines to refer to for the other server.
+
+ Syntax:
+C:remote server's hostname/IP:password:remote server's name:port:class
+N:remote server's hostname/IP:password:remote server's name:host mask:class
+ The remote server's hostname/IP should be the location on the internet that
+ the server can be found. IP addresses are prefered as they are more secure,
+ and can be a little quicker for the server. As with I and O lines, ident
+ can be used with this 1st field to specify the username the ircd on the
+ remote server is running from (if the remote server is running ident), to
+ use ident with C/N lines, place the username with an @ before the hostname.
+ The password should be crypted if you compile ircd specifying that link
+ passwords should be crypted. Your link passwords should be very secure, as
+ they provide more power, if hacked, than Operator passwords do. However
+ crypted link passwords can be very akward to keep track of.
+ Your C line password is the password used in the pass command, while your
+ N line password will be used to check against the pass command used by
+ incomming servers. So, your C line password should match the listed
+ server's N line password, and your N line password should match their C
+ line password.
+ If you compile your ircd specifying crypted link passwords, you only need
+ to crypt your N line passwords, use the same method as with O line
+ passwords. If you crypt your C line passwords, your link will not work!
+ Crypted passwords are a one sided affair, because one server crypts its
+ N line passwords does not mean the connecting servers must crypt their
+ C line passwords for that server.
+ For the 3rd field, the remote servers `name' should be used, this name is
+ the one given in that servers M line (see above). This name will be sent
+ with the SERVER command, so it must match the one given. The C and N line
+ pair should have the same name for this field.
+ The 4th field of C lines may contain the remote servers connection port.
+ Even though DALnet runs all its servers with a standard port 7000 open,
+ server -- server connections should be taken place through port 7325. It is
+ not mandatory that you place a port number in this field. If you don't give
+ a port number, the server will not try and autoconnect to the listed
+ server. If you do give a port number, the server will only try and
+ autoconnect to the listed server if there is enough room on the connection
+ class listed at the end of the C line (connection classes are covered in
+ more detail above, under Y lines), and the listed server is not visible
+ (ie: it is not connected to the network). If you don't give a port number,
+ any /connect commands for this C line will use the default port specified
+ in your config.h unless a port is given with the command. If you do put a
+ port number, any /connect command's will use this port unless another port
+ number is given with the command.
+ The 4th field of N lines is called the `host mask', this defined how many
+ parts of your hostname the incomming server will mask to. So, if your
+ server's name is disney.us.dal.net, and you want the connecting server to
+ see you as *.us.dal.net you will give a host mask of 1 in your N line. This
+ field should normally be left blank.
+ The 5th (last) field of both C and N lines gives the connection class to
+ place the connection on. If your C line has a 42 in this field, and your
+ server initiates a connection through this line, the connection will be
+ placed on class 42, however, if You have a 42 in your C line and a 43 in
+ your N line and an incomming server initiates a connection via this N
+ line, the server connection will be placed on class 43.
+ Examples: 
+C:143.53.233.32:mypass:somewhere.fr.dal.net:7325:35
+N:143.53.233.32:yourpass:somewhere.fr.dal.net::35
+ This set will allow a server named somewhere.fr.dal.net to connect to your
+ server if it has the IP address of 143.53.233.32 and gives a password of
+ `yourpass'. This connection will be governed by connection class 35.
+ If your server recieves the command /connect somewhere.*, it will try and
+ connect to the IP 143.53.233.32 through port 7325 and give the password
+ `mypass'.
+
+C:143.53.233.32:mypass:somewhere.fr.dal.net:7325:35
+N:143.53.233.32:yourpass:somewhere.fr.dal.net::35
+C:ircd@176.43.652.31:apass:elsewhere.jp.dal.net:7235:35
+N:ircd@176.43.652.31:THEpass:elsewhere.jp.dal.net::33
+ Both these set's will work as explained above, but if your Y line defining
+ class 35 has `max links' set to 1, and one of these servers is connected to
+ your server, your server will not try and autoconnect to the other since
+ the Y line is `full', but it will accept any incomming connections from the
+ other server and any /connect commands given for this server. If your Y
+ line allows for more connections but your C lines do not have port numbers,
+ your server will not try and autoconnect.
+ Since the second set in this example has a username, ident will be used to
+ authenticate any connections made to this server. If the listed server does
+ not run ident, or the incomming connection comes from another username, the
+ connection will be rejected.
+ If a connection is made via the second set by your server, the connection
+ will be ruled by connection class 35, if the other server initiates the
+ connection, the connection will use class 33.
+ Autoconnect C/N line pairs can be given prefrence over other pairs by placing
+ them lower in your ircd.conf, the lower the line, the higher the priority
+ when autoconnecting.
+ Connection classes and C/N line set's allow you to refine your autoconnects
+ to a very high degree, with practice you can have your server running so
+ it does not need any help.
+
+--------------------
+
+3.8) K Lines [OPTIONAL]
+
+ These lines restric access to certain users to your server based on
+ user@host matches and time of the day.
+ K lines can come in 3 forms, only one of which you can specify in your
+ ircd.conf, this type will show up as K on /stats k, the other other types
+ are `AutoKill' which will show up as A on /stats k, and `kline' which will
+ show up as k on /stats k. AutoKill's are set by U lined servers (see
+ above), they act in the same way as K lines except that they are set
+ remotly and are usually set on all servers, they dissapear when you
+ /rehash or restart your server. klines are set via the /kline command,
+ they operate more like AutoKill's than K lines because they also dissapear
+ when you /rehash, or restart the server. The /kline command can be used on
+ nicknames that appear on IRC, or you can use a user@host mask. If the
+ /kline is done on an existing nickname, a kline will be set with that users
+ mask and they will be killed off the server.
+
+ Syntax:
+K:hostmask:time/comment:username
+ The hostmask is the host that the user will have on IRC, this may be an
+ IP address or a standard host name. The time/comment field may either
+ contain nothing, a set of times, or a comment. This field should not
+ contain spaces, if you place a comment in the field, you should try and
+ be creative in your avoidance of spaces. The syntax of time specification
+ is:
+  from-to[,from-to[,from-to]]....
+ Again, you should not use spaces in this field, but you may specify as
+ many time periods as you want/need. 24 hour time should be used, AM and PM
+ will not work.
+ You may also specify a filename as a reason. To do so use |kc.reason as the 
+ reason. Replace reason with the reason for the ban. Note, all files must be in 
+ the format of kc.* to ensure no important configuration files are sent to the 
+ user. 
+ The username will be the username that shows up on IRC.
+ Wildcards (`*', `?') may be used with K lines in both the hostmask and
+ username fields.
+
+ Examples:
+K:RIP.org::walt
+ This will reject any user who appears as `walt@RIP.org'.
+
+K:*.edu:0800-1200,1300-1700:*
+ This will reject any user from any host with a top level `edu', In other
+ words, anyone appearing as *@*.edu are banned from the server.
+ This ban is only present during the hours of 8AM to 12AM, and again from
+ 1PM to 5PM, at times other than this, the K line will not be active.
+
+K:*.lamer.org:|kc.spamming:*
+ This will reject all users from *.lamer.org and play the file kc.spamming as 
+ the reason. 
+
+K:*::*rad
+ This K line will reject anyone with the username `rad', or anything ending
+ in `rad'. This ban will dissalow anyone using `rad' running ident or not.
+ You must always take into account the ident character (`~') that is placed
+ infront of usernames when their host is not running ident. If you place a
+ K line on a username `rad' the user will be banned only if they are running
+ ident, but if this user can turn off ident they can appear as ~rad, this
+ will allow them to bypass any ban of username `rad'. So, wildcards should
+ be used with usernames to take into account the ability to turn ident on
+ and off. (The ability to change usernames can only be tackled with a `*'
+ in the username field)
+
+--------------------
+
+3.9) Q Lines (server form) [DISCOURAGED]
+
+ Server form Q lines on DALnet servers are used to dissalow operators on
+ certain servers to use commands such as remote /kill's, and remote
+ /connect's, this will effectivly restrict the operators on the server to
+ local operator priveleges. These lines are usually only used for `test'
+ server situations. If a server isn't officially part of DALnet, they may
+ be temporarily linked and Q lined, this means the server can be tested
+ while not posing a threat to the rest of DALnet. Q lines need only be
+ placed on the hub connecting the `test' server.
+
+ Syntax:
+Q:*:*:servername
+ The 1st 2 fields are currently unused. A Q line placed on a hub connected
+ to the named server will dissalow operators on the server to affect other
+ DALnet users/servers.
+
+ Example:
+Q:::test-server.my.dal.net
+ Q line a server with the name `test-server.my.dal.net'.
+
+--------------------
+
+3.10) Q lines (nickname form) [OPTIONAL]
+
+ Nickname form Q lines have the ability to deny certain nicknames to users.
+ If a nickname is Q lined, the only people allowed to use those nicknames
+ are Operators. Q lines, like most other things in your ircd.conf, are local
+ only, for a nickname to be Q lined on a whole network all servers must have
+ a Q line for that nick. Q lines may also contain comments, these comments
+ are given to the user when they attempt to use the nickname and are asked
+ to choose another.
+
+ Syntax:
+Q:*:reason why nick is quarantined:nickname
+ The 1st field is currently unused. The 2nd field is the comment sent to any
+ user attempting to use the nickname. Unlike K lines, you may use spaces.
+ The last field is the nickname to be quarantined, this nickname may contain
+ wildcards.
+
+ Examples:
+Q::No nicknames on MY server!:*
+ This Q line will dissalow any nicknames on the server giving the reason:
+  No nicknames on MY server!
+ Only Operators will be allowed to use any nicknames, but since you must be
+ a user before you can be +o, you will effectivly ban everyone from your
+ server.
+
+Q::Do not use the Lords name in vain!:God
+ Anyone attempting to use the nickname `God' on your server will be told
+ that they must find a new nickname and will be given the reason:
+  Do not use the Lords name in vain!
+
+ DALnet has a set of standard Q lines that should be in place on all
+ server's. They are as follows:
+
+Q::Reserved for services:*Chan*S*rv*
+Q::Reserved for services:*Nick*S*rv*
+Q::Reserved for services:*Memo*S*rv
+Q::Reserved for services:*Oper*S*rv*
+Q::Reserved for services:*Help*S*rv*
+Q::Reserved for operators:DALnet
+Q::Reserved for operators:IRC*op*
+Q::Causes problems with mIRC:Status
+
+--------------------
+
+3.11) L Lines [OPTIONAL/NETWORKED]
+
+ These lines specify which servers are to behave as leaves, that is,
+ servers that may not have any other servers connected to them.
+ They will only be usefull if your server is a non-leaf (hub) server.
+ Not only can you limit servers to leaves, but you can also specify
+ what tree depth may appear after certain servers. If a server connects
+ but tells your server that it has a larger tree depth behind it than is
+ allowed via your L line for the server, the server will be rejected.
+ A limit of `0' will mean the server may only be a leaf. A limit of `1'
+ will mean that only leaf servers may be connected to the L lined server
+ when it is connected to your server.
+ You may also use L lines to restrict what servers may connect to certain
+ servers while they are connected to your server.
+
+ Syntax:
+L:hostmask of disallowed servers:*:server name:depth
+ The 1st field defines the limitations on servers allowed to connect to
+ the L lined server by hostmask. If any server connects to the L lined
+ server while it is connected to your server, and it's name matches the
+ hostmask given here, it will be rejected. Wildcards are allowed. You do not
+ need to put a value in this field.
+ The 2nd field is currently unused and should be left blank.
+ The 3rd field is the name of the server to be L lined, when this server
+ connects to your server, the restrictions defined by the L line are placed
+ on this server. Wildcards are allowed.
+ The 4th field defines the depth of servers allowed to be connected behind
+ the L lined server. 
+
+ Examples:
+L:::leaf.de.dal.net
+ This line will allow a server named `leaf.de.dal.net' to connect only as
+ a leaf. So this server may not connect any other servers behind it.
+
+L:::semi-hub.sg.dal.net:1
+ This line will force the server named `semi-hub.sg.dal.net' to allow only
+ leaf servers to connect behind it. ie: to have a tree depth of 1.
+
+L:*.us.dal.net::*.au.dal.net
+L:*.eu.dal.net::*.au.dal.net
+ These lines will make sure that any server with a name matching
+ *.au.dal.net will not introduce any servers matching *.us.dal.net or
+ *.eu.dal.net. This can be usefull for stopping certain hubs from letting
+ its autoconnects route the network badly.
+
+--------------------
+
+3.12) H Lines [OPTIONAL/NETWORKED]
+
+ These lines are similar to L lines, except that they define what servers
+ may act as a hub while connected to you. That is, which servers may
+ introduce other servers behind them.
+ You may limit what servers may be connected behind the H lined server.
+
+ Syntax:
+H:servers which are allowed behind the hub:*:hub servername
+ The 1st field defines what servernames the H lined server is allowed to
+ introduce. Wildcards are allowed.
+ The 2nd field is currently unused and should be left blank.
+ The 3rd field should be the exact name of the server allowed to be a hub
+ while connected to you. You may not use wildcards with this field unless
+ the server's name includes a `*' (See N lines for host masking).
+
+ Examples:
+H:*::dal-hub.us.dal.net
+ This line will allow the server with the name `dal-hub.us.dal.net' to act
+ as a hub server while you are connected to it, there are no restrictions
+ on the names of the servers it may introduce.
+
+H:*.us.dal.net::usa-hub.us.dal.net
+ This line will allow the server named `usa-hub.us.dal.net' to act as a hub
+ while your server is connected to it, but it is limited to introducing
+ servers with names matching `*.us.dal.net', so any servers trying to
+ connect to `usa-hub.us.dal.net' with a name such as `bad-link.nz.dal.net'
+ will be rejected by your server.
+
+--------------------
+
+3.13) P lines [OPTIONAL]
+
+ These lines will open up ports other than the port you specified in your
+ config.h when you compiled your ircd.
+ Using internet domain ports below 1024 mean that you must run ircd from
+ inetd. ircd can listen to ports in the UNIX domain as well as the internet
+ domain. With UNIX domain ports you must give a unix socket file, you must
+ also compile ircd with UNIXPORT defined in your config.h.
+ You may limit usage of ports in the internet domain to certain hostmasks.
+ You do not need to provide a P line for the default port you defined in
+ your config.h, only extra ports you wish to open. You should compile ircd
+ to run from port 7000, but it is recomended that you add a P line for port
+ 6667 as most IRC clients default to this port when connecting. If you are
+ connected to DALnet, you should have a P line for port 7325, this is the
+ standard server connection port for all DALnet servers.
+
+ Syntax:
+P:hostmask or UNIX socket file:*:*:port number
+ The 1st field should either specify a path to a UNIX socket file, or give
+ a hostmask to match against connecting clients on this port. Clients not
+ matching this mask will be rejected.
+ The 2nd and 3rd field's are currently unused, and should be left blank.
+ The last field is the port number to open up and listen to for connections.
+
+ Examples:
+P:*:::7325
+ This will open up the DALnet server connection port and wait for
+ connections. This line is mandatory if you run a server connected to DALnet
+
+P:*.net:::6665
+ This line will open up port 6665 and wait for connections, connections from
+ hosts not matching `*.net' will be rejected.
+
+P:/tmp/.ircd:*:*:6666
+ This line will open up the port 6666 in the UNIX domain, with a socket file
+ of: /tmp/.ircd.
+
+--------------------
+
+3.14) T lines [OPTIONAL]
+
+ These lines allow you to have multiple MOTD and RULES files in the same IRCd.
+ The idea of this is to allow you to have MOTD and RULES files in different  
+ languages for your users all over the world. The way this works is you can   
+ match a MOTD and RULES file to a certain part of a users host.  For example 
+ *.fr  (France) now you can make it so all *.fr users see a French MOTD and 
+ RULES where  as everyone else still sees the default.
+
+ Syntax:
+T:hostmask:motd file:rules file
+ The first field is where you specify the hostmask to match. This should be a  
+ TLD (Top Level Domain) but doesn't have to be. The second is the location of 
+ the MOTD file to display, this should be relative to DPATH. The last field is
+ the path to the RULES file, again this should also be relative to DPATH.  The 
+ best way to keep your T:lines MOTD/RULES files in order is to make a motds/ and  
+ rules/ then make files such as spanish.motd and spanish.rules etc.
+
+ Examples:
+T:bngr216-37-173ppp107.epix.net:motds/epix.motd:rules/epix.rules
+ This T:line uses a matches a specific host. When a user with the host bngr216- 
+ 37-173ppp107.epix.net requests a /MOTD they will see the file motds/epix.motd 
+ and when they request a /RULES they will see the file rules/epix.rules. 
+
+T:*.epix.net:motds/epix.motd:rules/epix.rules
+ This T:line matches based on ISP. When a user from *.epix.net requests a /MOTD 
+ or /RULES the specified files are played.
+
+T:*.dk:motds/danish.motd:rules/danish.rules
+ This T:line matches based on TLD. This is probably the most efficient method to 
+ use. When a user from the .dk TLD requests a /MOTD the Danish MOTD is played
+ when they request a /RULES the Danish RULES file is played.
+--------------------
+
+3.15) E Lines [OPTIONAL]
+
+ These lines allow you to exclude certain people from a K:line, or to prevent 
+ certain people from receiving a K:line. E:lines can be used with a more strict 
+ host than a K:line so for example if you K:line *.net and then E:line 
+ splitrock.net only users from splitrock.net may connect. These lines are also 
+ often used to prevent the server's staff from being K:lined from that server.
+
+ Syntax:
+E:hostmask:reason:ident
+ The first field is where you enter the hostmask that the E:line will apply to.  
+ The reason parameter allows you to specify why that hostmask is E:lined. The 
+ third field is optional. To E:line all idents just specify this field as an *. 
+ Examples:
+E:*.epix.net:Admin's ISP:*
+ This E:line affects all *.epix.net users with reason 'Admin's ISP'. The * in 
+ the ident field says that it applies to all *.epix.net users.
+
+E:*.epix.net:Server Admin:n64master
+ This E:line affects any *.epix.net user using the n64master ident, with reason 'Server Admin'. This is probably the best way to go if you are making the E:line 
+ to protect server staff.
+
+--------------------
+
+3.16) e Lines [OPTIONAL]
+
+ These lines allow you to specify which hosts will not be scaned by the proxy  
+ scanner. This will allow you to make certain proxys to connect while the rest 
+ are still killed. Note, if you want to allow all proxys, don't e:line *, just 
+ disable it at compile time.
+
+ Syntax:
+e:IP address:*:*
+ This line requires only one field, the first field is the IP address of the 
+ host to be e lined. Make sure you use an IP and not a hostname or this will not 
+ work.
+
+ Examples:
+e:234.45.32.1:*:*
+ This will prevent any user who's host resolves to 234.45.32.1 from being 
+ scanned for an open wingate/proxy by the proxy scanner when they connect.
+
+--------------------
+
+3.17) Summary:
+
+ Well, thats it for the lines you may use in your ircd.conf. Remember that
+ ircd.conf is an art, just like any other type of programming. Some parts
+ are particularly easy, but other's, like Y lines, can take a while to get
+ used to. Given a little time experementing with lines on a network of
+ servers, you will become well versed in ircd.conf programming.
+
+Good luck!
+
+--------------------
+
+4) dccdeny.conf:
+ The dccdeny.conf allows you to specify files which may not be sent through the 
+ use of DCC (Direct Client Connection). This is mainly to keep the speading of 
+ virii at a minimum on your network. It is strongly suggested that you set up a 
+ dccdeny.conf as it will help you provide a safe enviromnet for your users.
+
+4.1) deny Lines:
+ As with the ircd.conf, dccdeny.conf supports comments in the form of # comment. 
+ It is suggested that you place comments above each dccdeny for easy reference.
+ Syntax:
+deny filename reason
+ The first field is required to be deny, this tells the server that this line 
+ specifies a file which should be denied. The second field is where you specify 
+ what file should be denied. The last field is where you specify a reason. It is  
+ recommended you place a web address such as http://www.nohack.net in the reason 
+ so if the user is infected with a virus, they can learn how to remove it.
+
+deny dmsetup.exe You may be infected with DMSetup, visit http://www.nohack.net 
+ This line will deny users to send the file dmsetup.exe.  If they attempt to 
+ send this file the server will display the reason which is 'You may be infected 
+ with DMSetup, visit http://www.nohack.net. 
+
+deny *.jpg.bat You may be infected with a virus, visit http://www.nohack.net
+ This line will deny sends matching *.jpg.bat and display the reason 'You may be infected with a virus, visit http://www.nohack.net' when a send is attempted.
+
+--------------------
+
+5) chrestrict.conf:
+ The chrestrict.conf allows you to limit what channels users may join. This is 
+ strongly discouraged for most networks. This is just provided for the networks 
+ that wish to have one open channel on a specific topic.
+
+--------------------
+
+5.1) msg Lines:
+ The msg line allows you to specify a message that will be played when a user 
+ attempts to join a channel that is not allowed. 
+
+ Syntax:
+msg message
+ The first field tells the server that this is a message line. The second field 
+ is where you specify the message that will be displayed when a user attempts to 
+ join a denied channel.
+
+ Examples:
+msg Sorry, the channel you attempted to join is not allowed on this network
+ This line will display 'Sorry, the channel you attempted to join is not allowed 
+ on this network' when a user trys to enter a channel that is denied.
+
+--------------------
+
+5.2) allow Lines:
+
+ The allow lines say which channels users are allowed to join. Any channel not 
+ in an allow line will be denied to the user.
+
+ Syntax:
+allow channel
+ The first field tells the server this is an allow line. The second is where you 
+ specify the channel which users are allowed to join.
+
+ Examples:
+allow #help
+ This line will allow users to join #help and deny them from joining all other 
+ channels.
+
+--------------------
+
+6) vhost.conf:
+ The vhost.conf file allows you to integrate a BNC type program into your ircd. 
+ This command works through use of the SETHOST command. You must be set +x in 
+ order for you to be able to keep your vhost, setting -x will return you to your 
+ normal host.
+
+6.1) vhost Lines:
+ vhost lines are the lines that allow you to create specific vhosts for certain  
+ users. These lines are used along with the /VHOST login password command.
+
+ Syntax:
+vhost virtualhost username password hostmask
+ The first field tells the server this is a vhost command. The second field is 
+ where you specify what the users host will be changed to once they use the 
+ /VHOST command. The third field is the username field and forth is password, a 
+ user must use the correct username and password in order to use the vhost. The 
+ last field is the hostmask. This allows you to specify which users can use that 
+ vhost based on host, to allow all users use *@*.
+
+ Examples:
+vhost i.work.at.the.foobar.net john21 asdf1234 *@*
+ This line will grant the user the hostname i.work.at.the.foobar.net, if they 
+ supply the username john21 and the password asdf1234. This line allows any 
+ hostmask to use the line since it has *@*.
+
+vhost i.am.a.lamer.org codemastr jnh32 n64master@*.epix.net 
+ This line will give the user the hostname i.am.a.lamer.org, if they supply the   
+ username codemastr and the password jnh32, but only if they match the hostmask 
+ n64master@*.epix.net. 
+
+--------------------
+
+7) unrealircd.conf
+
+ The unrealircd.conf allows you to change certain settings in your IRCd that 
+ used to be set at compile time. This feature is especially beneficial to 
+ Windows users since they use a precompiled version. The unrealircd.conf works 
+ along with your network file (explained in section 8) to provide a completely 
+ customized IRCd.
+
+--------------------
+
+7.1) Include Line:
+ The include line allows you to tell the unrealircd.conf where your network file 
+ is located. This path must be relative to DPATH in order for your IRCd to work. 
+
+ Syntax:
+Include .................: filename
+ This line will say that the network file is located in the field filename,  
+ again the path to the file must be relative to DPATH.
+
+ Examples:
+Include .................: networks/roxnet.network
+ This line says that you will be using the roxnet.network file, which is located 
+ in the networks directory. The networks/yourfile.network is most likely the 
+ format you will use if you keep the standard DPATH.
+
+Include .................: roxnet.network
+ This line says you will use the file roxnet.network which is located in the 
+ same directory as DPATH. This is valid although it is not the default.
+
+--------------------
+
+7.2) Set KLINE_ADDRESS Line:
+ This line allows you to tell the IRCd what email should be displayed to a user 
+ when they are klined. It is strongly encouraged that you set this to a valid 
+ email address of someone on the server staff.
+
+ Syntax:
+Set KLINE_ADDRESS .......: emailaddress
+ This line tells the server that the K:Line email address is located in the 
+ field emailaddress. Note, the emailaddress is not checked to see if it is valid 
+ so it is up to you to set it right.
+
+ Examples:
+Set KLINE_ADDRESS .......: bob@myserver.net 
+ This tells the server that the K:Line email address is bob@myserver.net and 
+ when a user gets klined this will be the email address shown to them.
+
+--------------------
+
+7.3) Set MODE_X Line:
+ This line lets you tell the server whether or not to set a user +x when they 
+ connect to the server. Set it to 1 for yes, or 0 for no. It is encouraged that 
+ you set this to 1 as it will help prevent users against nukes and other 
+ malicious attacks.
+
+ Syntax:
+Set MODE_X ..............: 1/0
+ If this line is set to 1 then the server will set users +x when they connect to 
+ the server. If it is set to 0 they will not be set +x on connect.
+
+ Examples:
+Set MODE_X ..............: 1
+ This line has auto +x on connect enabled, this is the recommended setting for 
+ security purposes.
+
+Set MODE_X ..............: 0
+ This line has auto +x disabled. This is discouraged, but it is not required 
+ that auto +x be enabled.
+
+--------------------
+
+7.4) Set MODE_I Line:
+ This line lets you tell the server whether or not to set a user +i when they 
+ connect to the server. Set it to 1 for yes, or 0 for no. It is encouraged that 
+ you set this to 1 as it will help prevent users from getting unwanted messages 
+ from users.
+
+ Syntax:
+Set MODE_I ..............: 1/0
+ If this line is set to 1 then the server will set users +i when they connect to 
+ the server. If it is set to 0 they will not be set +i on connect.
+
+ Examples:
+Set MODE_I ..............: 1
+ This line has auto +i on connect enabled, this is the recommended setting for 
+ security purposes.
+
+Set MODE_I ..............: 0
+ This line has auto +i disabled. This is discouraged, but it is not required 
+ that auto +i be enabled.
+
+--------------------
+
+7.5) Set TRUEHUB Line:
+ The Set TRUEHUB line allows you to tell the server the server you are a Hub and 
+ not a HalfHub. For most networks it is recommended that you set this to 1 to 
+ enable your server as a Hub. Note, if you compiled your server as a leaf and 
+ set this to 1 it will give an error. Only set this to 1 if you compiled your 
+ server as a hub.
+
+ Syntax:
+Set TRUEHUB .............: 1/0
+ If this line is set to 1 then TRUEHUB is enabled. If it is set to 0 it is 
+ disabled. Again it is recommended for most networks that this is set to 1, and 
+ may only be used if you compiled as a Hub.
+
+ Examples:
+Set TRUEHUB .............: 1
+ This line has TRUEHUB enabled, the server will send a GLOBOPS when it links.
+
+Set TRUEHUB .............: 0
+ This line has TRUEHUB disabled. The server will not send a GLOBOPS when it 
+ links, and it will link as a half hub.
+
+--------------------
+
+7.6) Set CONFIG_FILE_STOP Line:
+ The Set CONFIG_FILE_STOP line must be set to 0 in order for your IRCd to work. 
+ If this is set to 1 your IRCd will give an error and won't start. This line is 
+ there just to makesure you take the time to read over your unrealircd.conf and  
+ configure it correctly.
+
+ Syntax:
+Set CONFIG_FILE_STOP ....: 1/0
+ If this line is set to 1 then your IRCd will not start and will give you an 
+ error. It must be set to 0 in order to work. If set to 0 your IRCd will load 
+ normally.
+
+ Examples:
+Set CONFIG_FILE_STOP ....: 1
+ In this line, the IRCd will die and give an error when it attempts to load the 
+ unrealircd.conf.
+
+Set CONFIG_FILE_STOP ....: 0
+ This line will allow the IRCd to load and run fine without giving any errors.
+
+--------------------
+
+7.7) Set SHOWOPERS line:
+ This line sets whether non opers will be allowed to user /stats O to see a list 
+ of IRCOps on the server. This line may be set to whatever you want, although it 
+ is recommended you set this to 0 you may set it to 1.
+
+ Syntax:
+Set SHOWOPERS ...........: 1/0
+ If this line is set to 1, then all users will be able to see a list of O:lines, 
+ note a non oper will not see the host allowed by this line for security 
+ reasons. If this line is set to 0 then only opers may request a /stats O.
+
+ Examples:
+Set SHOWOPERS ...........: 1
+ This line allows all users to view a list of all the opers on a server. Again 
+ they will not be able to see the O:lines hosts or flags for security reasons.
+Set SHOWOPERS ...........: 0
+ This line only allows opers to request a /stats O, if a user requests it, it 
+ will return no information. 
+
+--------------------
+
+7.8) Set KILLDIFF Line:
+ This line allows you to set whether the new /kill format should be used. Then 
+ new format includes the server from which the /kill came from, the old format 
+ does not.
+
+ Syntax:
+Set KILLDIFF ............: 1/0
+ If this line is set to 1 the new format will be used. If it is set to 0 then 
+ the standard format will be used. Note, if you set this to 1 then some users 
+ scripts may not function correctly, so if you want backwards compatibility set 
+ this to 0.
+
+ Examples:
+Set KILLDIFF ............: 1
+ This line will make the server use the new /kill format, and the server name 
+ will be displayed.
+
+Set KILLDIFF ............: 0
+ This line will disable the new /kill format and the standard format will be 
+ displayed to the user. This is recommended for backwards compatibility.
+
+--------------------
+
+7.9) Set SHOWOPERMOTD Line:
+ This line allows you to set whether or not the OperMOTD will be displayed to a 
+ user when they /oper. This is completely up to you as to what it shoul be set 
+ to, although it is recommended that if you do not have an OperMOTD you set this 
+ to 0 to avoid the error message from being displayed.
+
+ Syntax:
+Set SHOWOPERMOTD ........: 1/0
+ If this line is set to 1 then the OperMOTD is displayed when the user /oper's. 
+ If it is set to 0 then the user must /OperMOTD to see the OperMOTD.
+
+Set SHOWOPERMOTD ........: 1
+ This line will make the server display the OperMOTD to the user when the /oper 
+ up.
+
+Set SHOWOPERMOTD ........: 0
+ This line will not make the server display the OperMOTD, and instead make the 
+ user have to type /OperMOTD to view the OperMOTD.
+
+--------------------
+
+7.10) Set HIDE_ULINES Line:
+
+ This line allows you to hide U:lined servers from non-opers in /links. This can 
+ help in adding security, since a user can not DoS services uplink to disconnect 
+ the services, but can also be a disadvantage if you have servers with a lot of 
+ hops to services, since a user can not get closer to the services server.
+
+ Syntax:
+Set HIDE_ULINES .........: 1/0
+ If this line is set to 1, then non-opers can not see U:lines in /links, if it 
+ is set to 0 non-opers can see U:lines in /links.
+
+ Examples:
+Set HIDE_ULINES .........: 1
+ This line makes it so only opers can see U:lined servers in /links.
+
+Set HIDE_ULINES .........: 0
+ This line makes it so anyone can see U:lined servers in /links.
+
+--------------------
+
+8) network files:
+ The networks files allow you to specify some information specific about your 
+ network you may use a current network file, or you can create your own. To 
+ create your own network file edit the template.network file to suit your needs, 
+ then add that file to your unrealircd.conf (See section 7.1). To use an 
+ existing network file just add the file to your unrealircd.conf (See section 
+ 7.1).
+
+--------------------
+
+8.1) Network line:
+ The Network line tells the server what the name of your IRC network is. You can 
+ set this line to anything you want, although it may not be left empty.
+
+ Syntax:
+Network >..........: yournetwork
+ This line tells the server that your networks name is located in the field  
+ yournetwork. Note, yournetwork should be the same on all servers to let users 
+ know what network they are on.
+ Examples:
+Network >..........: NeoHorizon
+ This tells the server that your network is called NeoHorizon and will display 
+ this to the user when it is requested.
+
+--------------------
+
+8.2) Set ircnetwork Line:
+ This line does the same thing as the Network line, but it is required that Set 
+ ircnetwork be the exact same as the Network line or your IRCd will not work. So 
+ if your Network line has Bunker7 then your Set ircnetwork line must also have 
+ Bunker7.
+
+ Syntax:
+Set ircnetwork ....: yournetwork
+ This tells the server that your network's name is found in the file called 
+ yournetwork.
+
+ Examples:
+Set ircnetwork ....: Bunker7
+ This defines your IRC networks name as Bunker7, again if this was your line you 
+ must also have Bunker7 in your Network line.
+
+--------------------
+
+8.3) Set defserver Line:
+ This line defines the server that the IRCd will tell users to go to when the 
+ IRCd is full. It is recommended that you point this to a random server pool if 
+ one is available.
+
+ Syntax:
+Set defserver .......: servername
+ This tells the server to tell the user to go to the contents of the field names 
+ servername with the server is full.
+
+ Examples:
+Set defserver .......: irc.dragonwings.org
+ This will display the server irc.dragonwings.org in the server is full message 
+ when a user attempts to connect to a full server.
+
+--------------------
+
+8.4) Set SERVICES_NAME Line:
+ This line is very important. It must be set correctly for commands such as 
+ /nickserv, /chanserv, /memoserv, /operserv, etc. to work. If this is not set 
+ correctly you must use /msg servicesname to use services.
+
+ Syntax: 
+Set SERVICES_NAME .: servicesserver
+ This line tells the IRCd to redirect /nickserv, /chanserv etc to servicesserver 
+ and find the correct client.
+
+ Examples:
+Set SERVICES_NAME .: services.realchat.org
+ This tells the server to redirect the services commands to 
+ services.realchat.org.
+
+--------------------
+
+8.5) Set oper_host Line:
+
+ This allows you to specify a host that Global IRCOps will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set oper_host .....: operhost
+ This tells the server to switch the host of the user to operhost when they 
+ /oper.
+
+ Examples:
+Set oper_host .....: opers.nevernet.net
+ This will make a Global Oper's host change to opers.nevernet.net when they 
+ /oper up if iNAH is enabled.
+
+--------------------
+
+8.6) Set admin_host Line:
+
+ This allows you to specify a host that Admins will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set admin_host ....: adminhost
+ This tells the server to switch the host of the admin to adminhost when they 
+ /oper.
+
+ Examples:
+Set admin_host ....: admins.nevernet.net
+ This will make a Admin's host change to admins.nevernet.net when they /oper up 
+ if iNAH is enabled.
+
+--------------------
+
+8.7) Set locop_host Line:
+
+ This allows you to specify a host that Local IRCOps will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set locop_host ....: locophost
+ This tells the server to switch the host of the Local Oper to locophost when 
+ they /oper.
+
+ Examples:
+Set locop_host ....: locop.nhn.net
+ This will make a Local Oper's host change to locop.nhn.net when they /oper up 
+ if iNAH is enabled.
+
+--------------------
+
+8.8) Set sadmin_host Line:
+
+ This allows you to specify a host that Services Admins will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set sadmin_host ...: sadminhost
+ This tells the server to switch the host of the Services Admin to sadminhost 
+ when they /oper.
+
+ Examples:
+Set sadmin_host ...: sops.spynet.org
+ This will make a Services Admin's host change to sops.spynet.org when they 
+ /oper up if iNAH is enabled.
+
+--------------------
+
+8.9) Set netadmin_host Line:
+
+ This allows you to specify a host that NetAdmins will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set netadmin_host .: netadminhost
+ This tells the server to switch the host of the NetAdmin to netadminhost when 
+ they /oper.
+
+ Examples:
+Set netadmin_host .: netadmin.spynet.org
+ This will make a NetAdmin's host change to netadmin.spynet.org when they /oper  
+ up if iNAH is enabled.
+
+--------------------
+
+8.10) Set coadmin_host Line:
+
+ This allows you to specify a host that CoAdmins will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set coadmin_host ..: coadminhost
+ This tells the server to switch the host of the CoAdmin to coadminhost when 
+ they /oper.
+
+ Examples:
+Set coadmin_host ..: coadmin.starspace.net
+ This will make a CoAdmin's host change to coadmin.starspace.net when they /oper 
+ up if iNAH is enabled.
+
+--------------------
+
+8.11) Set techadmin_host Line:
+
+ This allows you to specify a host that TechAdmins will receive when they 
+ /oper, this only works if iNAH (See section 8.17) is enabled. If this is left 
+ blank it can cause some problems in your IRCd so it is recommended that you 
+ fill in a value.
+
+ Syntax: 
+Set techadmin_host : techadminhost
+ This tells the server to switch the host of the TechAdmin to techadminhost when 
+ they /oper.
+
+ Examples:
+Set techadmin_host : techadmin.starspace.net
+ This will make a TechAdmin's host change to techadmin.starspace.net when they 
+ /oper up if iNAH is enabled.
+
+--------------------
+
+8.12) Set hidden_host Line:
+ The Set hidden_host line allows you to specify what the masked part of a users 
+ host will look like when they set +x. Most networks tend to use a part of their 
+ network's name, for example MegaIRC uses mega for their hidden host. Note, if 
+ you leave this blank it may cause some problems in your IRCd.
+
+ Syntax:
+Set hidden_host ...: hiddenhost
+ This tells the server to use the contents of hiddenhost as the masked part of a 
+ users host when they set +x.
+
+ Examples:
+Set hidden_host ...: neo
+ This will use the word neo as the masked part of a users host.
+
+--------------------
+
+8.13) Set netdomain Line:
+ This is used to specify the domain name of your IRC network. It is used to give 
+ the user your www address and ftp address in the /info reply. If you leave this 
+ blank, users may find difficulty getting help with a specific topic.
+
+ Syntax:
+Set netdomain .....: networkdomain
+ This tells the server to use the field networkdomain for your networks domain.
+
+ Examples:
+Set netdomain .....: Infinity-IRC.org 
+ This will make the server set your domain as Infinity-IRC.org, and display the 
+ www and ftp as www.Infinity-IRC.org and ftp.Infinity-IRC.org in the /info 
+ reply.
+
+--------------------
+
+8.14) Set helpchan Line:
+ This line specifies a channel which the user can go to for help, this is also 
+ used as a reply in the /info command. Again, leaving this blank may cause users 
+ to have problems when seeking help.
+
+ Syntax:
+Set helpchan ......: channel
+ This will make the server use the field channel as your Official Help Channel 
+ in the /info reply.
+
+ Examples:
+Set helpchan ......: #help
+ This will tell the user that the server's help channel is #help when they 
+ request a /info.
+
+--------------------
+
+8.15) Set STATS_SERVER Line:
+ This line is used to tell the IRCd where your StatServ is located for use in 
+ the /StatServ command.
+
+ Syntax:
+Set STATS_SERVER ..: statserver
+ This tells the server to send all /StatServ's to the field statserver.
+
+ Examples:
+Set STATS_SERVER ..: stats.tspre.org
+ This tells the server to forward all /StatServ commands to stats.tspre.org.
+
+--------------------
+
+8.16) Set HUB Line:
+
+ This line is obsolete and no longer in use. It is provided only for backwards 
+ compatibility.
+
+--------------------
+
+8.17) Set iNAH Line:
+
+ This line allows you to specify whether or not oper's hosts should be changed 
+ when they send a /oper command. Most networks set this on, but there are some 
+ that do not like the host masking feature.
+
+ Syntax:
+Set iNAH ..........: 1/0
+ Set this line to 1 to enable the oper host masking, or set it to 0 to disable 
+ the host masking.
+
+ Examples:
+Set iNAH ..........: 1
+ This line tells the server to mask an oper's host when they issue a /oper 
+ command.
+
+Set iNAH ..........: 0
+ This tells the server not to mask an oper's host when they send a /oper 
+ command.
+
+--------------------
+
+8.18) Set net_quit Line:
+
+ This line is no longer in use and is only provided for compatibility with older 
+ versions of Unreal.
+
+--------------------
+
+[ $Id$ ]
diff --git a/doc/example.conf b/doc/example.conf
new file mode 100644 (file)
index 0000000..754ef8f
--- /dev/null
@@ -0,0 +1,481 @@
+#
+# IRC - Internet Relay Chat, doc/example.conf
+# Copyright (C) 1994, Helen Rose
+# $Id$
+#
+#   This program is free software; you can 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.
+#
+# This is an example configuration file for the Unreal3.0-Morrican
+# and higher IRC servers.
+# 
+# You only need an ircd.conf (IRC server configuration file) if you are
+# running an IRC server. If you are running a standalone client this file
+# is not necessary.
+#
+# This file will explain the various lines in the IRC server
+# configuration file. Not all lines are mandatory. You can check to make
+# sure that your configuration file is correct by using the program
+# "chkconf", provided in the server distribution (and when you do "make
+# install" this program will be installed in the same directory as the irc
+# server). 
+#
+# This document modified for use by with the Unreal3.0 IRCD
+#
+#
+# The options for whether a line is needed or not are: 
+# MANDATORY: you absolutely MUST have this line
+# NETWORKED: you must have this line if you are connecting this irc
+#            server to any other server (servers can run standalone).
+# SUGGESTED: it is highly suggested that you use this line
+# OPTIONAL: it's completely up to you whether to define this or not
+# DISCOURAGED: you really really should not use this line if at all
+#              possible. 
+# OBSOLETE: an old or out of date line that isn't needed.
+#
+# MANDATORY lines are absolute *musts*, that is, if you do not have this
+# line then your server will not work properly. SUGGESTED lines are
+# close-to-mandatory (that is, the server will run without it, but you are
+# highly encouraged to use these lines).
+#
+# Note that "*" in a field indicates an "unused" field.
+#
+#
+# ========================================================================
+# NOTE! this entire configuration file is read UPSIDE-DOWN! So if you have
+# to put something in a specific order (for example, client-connection
+# lines), put them in reverse order!
+# ========================================================================
+#
+#
+# M: [MANDATORY]. This line sets your server's name, description, port
+# number, and IP address to bind to. Fields, in order, are: 
+#
+# If you are compiling this server for use on dalnet, port number 7000
+# as the default is recommended.  If you leave IP address field blank or
+# *, it defaults to binding all local IP addresses on the machine.
+#
+# M:hostname:IP:Description Of Your Server:7000
+#
+M:server.my.net:*:My IRC Server:7000
+#
+# A: [MANDATORY]. This line lists your administrative information
+# (contact address, etc). To view this information, /admin (server) will
+# show it to you.
+#
+# The A: line has no set information, in fact, you can put arbitrary text
+# in there if you wish (it is encouraged that you put at *least* a contact
+# address for a person responsible for the irc server, however)
+#
+A:Generic Internet Access:Admin John Doe:jdoe@generic.com
+#
+# Y: [SUGGESTED]. These lines define connection classes. Connection
+# classes allow you to fine-tune your client and server connections. It is
+# suggested that clients and servers be placed in seperate classes, and if
+# you have lots of server connections (if you do have lots of servers you
+# shouldn't be reading this file :-) each set of servers (defined
+# arbitrarily by you) should have its own class. If you have clients
+# coming in from lots of different sites, you may want to seperate them
+# out into classes. For instance, you may want to put local users in one
+# class, with remote users in another class.
+#
+# The class numbers are not arbitrary. In auto-connecting servers -- that
+# is, servers that you have a port number (e.g. 6667) on the end of the C:
+# line (see below) the higher the number the higher the priority in
+# auto-connecting.
+#
+# The fields in order are: class number, ping frequency (in seconds),
+# connect frequency (in seconds), maximum number of links (used for
+# auto-connecting, and for limiting the number of clients in that class),
+# and sendq (this overrides any value set in include/config.h for #define
+# MAXSENDQLENGTH).
+#
+# Note that it is a good idea to have ping frequency the same at both ends
+# of the link.
+# 
+# in this case, connect-frequency is 0 indicating that this is a client
+# class (servers never connect to clients, it is the other way around).
+Y:1:90:0:20:100000
+#
+# These are the recommended server Y:lines for connecting to dalnet.
+# In addition to these you should have at *least* one client class, and one
+# oper class (see O:lines).  By convention on dalnet, these are usually
+# numbered from 5 to 10.
+#
+# Class 50 - Hub to hub, autoconnect
+Y:50:90:60:1:4000000
+#
+# Class 51 - Hub to hub, no autoconnect
+Y:51:90:60:0:4000000
+#
+# Class 30 - Hub to US leaf
+Y:30:90:0:0:3500000 
+#
+# Class 32 - Hub to EU leaf
+Y:32:180:0:0:3500000
+#
+# Class 34 - Hub to AU leaf
+Y:34:300:0:0:3500000
+#
+# Class 40 - US leaf to hub, autoconnect
+Y:40:90:90:1:3500000
+#
+# Class 41 - US leaf to hub, no autoconnect
+Y:41:90:90:0:3500000
+#
+# Class 42 - EU leaf hub
+Y:42:180:90:1:3500000
+#
+# Class 44 - AU leaf to hub
+Y:44:300:120:1:3500000
+#
+# I: [MANDATORY]. The I: lines are client-authorization lines. Without
+# these lines, no clients will be able to connect to your server.
+# Wildcards ("*") are permitted. Passwords are also permitted (clients can
+# be configured to send passwords).
+# 
+# Ident (for more information on this, see rfc1413) can also be used by
+# placing a @ in the appropriate fields.
+#
+# Fields are as follows:
+# I:IP-address-mask:optional password:domain-mask::connection class (opt)
+#
+# With a password..... This will allow anyone from anywhere to connect
+# as long as they know the password ("foobar"). Note listing this I: line
+# first, it will be read *last*, meaning it is the "fall-through". That
+# is, anyone who doesn't match the I: lines listed below must know the
+# password ("foobar") to connect.
+#
+I:*@*:foobar:*@*::1
+# This is a standard vanilla I: line which will permit anyone with an IP
+# address starting with 205.133 OR with a hostname ending in 
+# .toledolink.com to connect to the server. NOTE, the ircd matches on the 
+# *right-most* match, so if I connect as rmiller@glass.toledolink.com 
+# (which is rmiller@205.133.127.8) I will show up on irc as 
+# rmiller@glass.toledolink.com since that is the first match it found. 
+# (Even though the second match is valid). 
+I:205.133.*::*.toledolink.com::1
+# 
+# using ident
+I:*@205.133.*::*@*.toledolink.com::1
+# and you can even specify just certain usernames running ident (as long
+# as the client's site is running the ident daemon):
+I:NOMATCH::rmiller@glass.toledolink.com::1
+# putting NOMATCH in the first field will stop the ircd from matching
+# automatically against the IP address and it will force the server to
+# match against the hostname. (the "NOMATCH" string is not mandatory, you
+# can use any arbitrary text in the first field).
+I:*@*:ONE:*@*::1
+# putting the ONE in the password field makes it so that only 1 user matching
+# that host or IP can connect through that I:line.
+# 
+#
+# O: [OPTIONAL]. These lines define operator access. You do not need to
+# have an operator to run a server. A well configured leaf site should not
+# need an operator online, if it's connections are well defined, the irc
+# administrator can use kill -HUP on the ircd to reload the configuration
+# file. 
+# The fields are as follows:
+# O:hostname (ident "@" permitted):password:NickName:AccessFlags:class
+# if the person in "NickName" is not coming from the hostname defined in
+# the first field then the person will get the error message "No O: lines
+# for your host". 
+# NOTE that since Crypted Passwords are defined by default in
+# include/config.h this text probably will not be plaintext. See
+# ircd/crypt/README for more information.
+#
+# class is the Y:Line class you want this operator to end up in after they
+# have successfully /oper'd.
+#
+# Access flags may be left blank, or * to give full access rights. Flags
+# are in the form of single characters making a string.  Any combination
+# of the following can be used(these are cAsE sensitive characters):
+#
+# r = access to /rehash server
+# R = access to /restart server
+# D = access to /die server
+# h = oper can send /help ops
+# g = oper can send /globops
+# w = oper can send /wallops
+# l = oper can send /locops
+# c = access to do local /squits and /connects
+# L = access to do remote /squits and /connects
+# k = access to do local /kills
+# K = access to do global /kills
+# b = oper can /kline users from server
+# B = oper can /unkline users from server
+# n = oper can send local server notices(/notice $servername message)
+# G = oper can send global server notices(/notce $*.my.net message)
+# S = oper can join unlimited amount of channels
+# A = admin
+# u = oper can set /umode +c
+# f = oper can set /umode +f
+# ^ = oper can set /umode +I
+# e = oper can set /umode +e
+# W = oper can set /umode +W
+# H = oper gets auto +x on /oper
+# o = local oper, flags included: rhgwlckbBnuf
+# O = global oper, flags included: oRDCK
+# a = services admin, access to /samode
+# C = co admin
+# T = tech admin
+# A = admin
+# N = network admin access to remote /rehash and remote /restart and a bunch more
+# * = flags included: AaNCTzSHW^
+
+#
+# This is a plain vanilla O:line:
+O:*.toledolink.com:nopassword:Russell:*:10
+#
+# and this line forces ident:
+O:rmiller@glass.toledolink.com:nopassword:Russell::10
+# 
+# This line is a generic "local operator", because of the flags, the only
+# thing that really makes them global operators, is if they have the flags
+# CKN set in their access flags.
+#
+# this line permits the nickname "jhs" with the password of "ITBites" to
+# be a local operator only (be able to issue commands locally -- can /kill
+# and /squit and /connect -- but *only* locally)
+#
+O:*.something.net:ITBites:jhs:o:10
+#
+# a crypted password line (NOTE that if you have crypted passwords, *all*
+# of you passwords must be crypted! In fact, if you are getting an error
+# "Incorrect Password" it may well be because crypted passwords are
+# defined and you have used plaintext.  So my example of plaintext and
+# crypted strings in the same IRC server configuration file is an
+# impossibility (but it is just theoretical, which is why I explained both).
+#
+O:rmiller@*.toledolink.com:T0eiVgHrqeKTQ:Russell::10
+#
+# U: [OPTIONAL]. This line defines the servers that IRC recognizes as being
+# allowed to make various changes to the IRC environment (mode changes, for
+# example), without complaining or otherwise obstructing them. For example,
+# DALnet requires the following line:
+U:services.my.net:*:*
+#
+# X: [ENCOURAGED]. This line defines the password that an operator must use
+# to restart or die the server. Note that they still myst have they R and D
+# flags. This is just a security precaution against  accidentaly typing
+# /die or /restart
+# X:<password for /DIE>:<password for /RESTART>
+X:diepass:restartpass
+
+# C: [NETWORKED]. These lines define what servers your server tries to
+# connect to. 
+# N: [NETWORKED]. These lines define what servers your server permits
+# connections to be initiated from. 
+# C/N lines MUST be used in pairs. You cannot have one without the other. 
+#
+# C: lines contain the following fields:
+# C:remote server's hostname:passwd:remote server's name:port:conn class
+# (connection class)
+# N: lines contain the following fields:
+# N:remote server's hostname:passwd:remote server's name:host mask:conn class
+# (connection class)
+# "host mask" is the number of parts in *your* hostname to mask to. For
+# instance, with my servername being "csa.bu.edu", if I wanted to present
+# my servername to be "*.bu.edu" I would have a host-mask portion of "1". 
+#
+# it is *strongly* advised that your C/N line passwords be different for
+# security's sake.
+#
+# ident is allowed in the server's hostname part of the field.
+# these lines tell the server to automatically (note the port number, that
+# means automatic connection) connect to server2.my.net:
+C:foobar@server2.my.net:bigspark:server2.my.net:7000:32
+N:foobar@server2.my.net:bigalpha:server2.my.net::32
+#
+# This server's connection lines are more vanilla, masking the host to
+# *.toledolink.com (as described above):
+C:*.my.net:camelsrk00l:*.my.net::32
+N:*.my.net:andsoarellamas:*.my.net:1:32
+#
+# K: [OPTIONAL]. These lines define user@host patterns to be banned from
+# this particular server (with an optional time field). Note that K: lines
+# are *not* global, and if you ban a user they can still use any other IRC
+# server (unless they have specifically been banned there as well).
+#
+# The time field (same as reason) is only used if you #define
+# TIMED_KLINES in config.h, and even then they are discouraged.
+# 
+# the fields are defined as:
+# K:hostmask:reason:username
+# wildcards are permitted in any one of the fields, in other words, you can
+# K:*::* if you wanted (but your server wouldn't be used much ;-)
+#
+# Spaces are permitted in the reason field (you don't have to use _).
+# The /stats command has been modified to replace all spaces with _'s when
+# doing a /stats k. K:lines also allows you to specify a file to play to the
+# user when they are K:lined. To use this feature the reason must be in the
+# format of |filename. the filename must be kc.anythinghere, this is to prevent
+# the sending of text files such as your ircd.conf.
+#
+# This K: line bans the username "hrose" (the wildcards are used to make
+# sure that any ident-checking character will match) on any machine from
+# the University of Boston.
+K:*.bu.edu:Hacking #UnrealIRCD:*hrose*
+#
+# This K: line bans any users from acs*.bu.edu between the hours of 8am
+# and 12pm and 1pm and 5pm (the time is always the server's local time).
+# Time-based K-lines such as this require TIMED_KLINES in config.h to be
+# #defined.
+K:acs*.bu.edu:0800-1200,1300-1700:*
+# Note that 24 hour time is used (no "AM" or "PM").
+# This K: line bans all *.foobar.com users and will play the file |kc.flooding
+# to the user as the reason.
+K:*.foobar.com:|kc.flooding:*
+# 
+# E: [OPTIONAL]. This allows kline exceptions, even if a person matches
+# a K:line or /kline they are still allowed to connect.
+#
+# The fields are as follows
+# E:hostmask:reason:usermask
+# 
+E:foo.bar.com:Oper on this server:*john21*
+#
+#
+# q: [DISCOURAGED]. These lines "quarantine" specified servers.  Because
+# of the way they operates, the same q: lines MUST be installed by
+# everyone or the net will keep breaking. I CANNOT EMPHASIZE THIS ENOUGH.
+# Do NOT use q: lines lightly!
+#
+# This is NOT a nick q-line, if you wish to quarantine a NICK, see below.
+#
+# The fields are as follows:
+# q:*:reason why quarantine is in place:servername
+#
+q::this server is too slow and lags the net:cm5.eng.umd.edu
+#
+# Q: [OPTIONAL]. Different from the above type of q: line, these lines
+# prevent users on your server from picking certain nicks. This is useful
+# if your network has 'reserved' nicknames that should not be taken by
+# normal users.  Note the difference in capitalization and BE CAREFUL!
+#
+# The fields are as follows:
+# Q:*:reason why quarantine is in place:nickname
+#
+# For example, You might want to use the following lines:
+Q::Reserved for services:ChanServ
+Q::Reserved for services:NickServ
+Q::Reserved for services:MemoServ
+Q::Reserved for services:OperServ
+Q::Reserved for services:HelpServ
+Q::Reserved for services:StatServ
+Q::Reserved for operators:IRCop
+Q::Reserved for operators:*Oper*
+Q::Reserved for administrators:Admin*
+#
+# 
+# T: [OPTIONAL]. These allow you to specify different MOTD and RULES files
+# based on a users host.  This is made so you can have MOTDs in different
+# languages so all users can see the MOTD and understand it.
+#
+# The fields are as follows:
+# T:host:motdfile:rulesfile
+#
+# T:*.fr:french.motd:french.rules
+#
+#
+# e: [OPTIONAL]. These lines allow you to specify a host which will not 
+# be scanned by the proxy scanner when they connect. This is made so you
+# can allow some open proxys to connect while still killing others. Make
+# sure you use an IP and not a host for this line or it will not work.
+# NOTE: These are not the same as E:lines.
+#
+# The fields are as follows:
+# e:IP:*:*
+#
+# e:123.123.123:*:*
+#
+#
+# Z: [DISCOURAGED]. These block ALL incoming connections from a certain
+# IP address mask.  They can stop users who log on and issue the SERVER
+# command a couple of times just to annoy irc ops.  They are more
+# powerful that K-lines because they can stop users before they've had a
+# chance to register.  This works on servers, SO BE VERY CAREFUL WITH
+# YOUR Z-LINE MASKS.  Z-lines are a LAST RESORT.  They are much too
+# dangerous and powerful to be using them instead of K-lines and akills.
+#
+# NOTE 1: Z-lines do NOT work on host names!  Only IP addresses.
+# NOTE 2: Z-lines are part of /stats k.  
+# NOTE 3: The :* at the end is REQUIRED.  Not using it will cause both
+# ircd and chkconf to segfault without saying why.
+#
+# Syntax:
+# Z:IP mask:reason for zapping:*
+Z:127.0.0.1:Please don't log on from the local machine:*
+#
+# L: [OPTIONAL]. These lines "Leaf" specified servers. They are only
+# useful if you are a non-leaf site yourself. There are two ways you can
+# use L: lines. The first will limit one particular site to a particular
+# tree depth (including 0, which would mean the server has to connect with
+# no servers linked behind it otherwise the connection will fail). The
+# second will allow you to be selective about which other servers you wish
+# the connecting server to behave as a leaf towards.
+#
+# The fields are as follows:
+# L:disallow connections to this hostmask::server name:depth
+# For example, this will force kaja.gi.alaska.edu to connect only as a
+# leaf (if it is not a leaf, the link will be dropped):
+L:::kaja.gi.alaska.edu
+# This line will force cm5.eng.umd.edu to have a depth of only 1 below it
+# (that is, it is allowed to have only leaves connected to it):
+L:::cm5.eng.umd.edu:1
+#
+# This line will prohibit anything matching *.edu to be connected behind
+# any server matching *.au:
+L:*.edu::*.au
+#
+# H: [OPTIONAL]. These lines define who you permit to act as a "hub" to
+# you (that is, who you permit to connect non-leafed servers to you).
+#
+# the first field may use wildcards, the third field *must* be an exact
+# match for a server's name (NOT a server's hostname, if they differ, the
+# server's name must be used). If the servername is a wildcard (e.g. *.au)
+# that is an acceptable name for the third field. 
+#
+# The fields are as follows:
+# H:servers which are permitted entry::hub server
+#
+# Example, permit server.my.net to allow any servers behind it to 
+# connect: 
+H:*::server2.my.net
+#
+# Example, permit irc-2.mit.edu to allow any MIT servers behind it to
+# connect: 
+H:*.mit.edu::irc-2.mit.edu
+#
+# P: [OPTIONAL]. This field allows the server to listen on various ports
+# (other than 7000) for connections. Any internet domain port that is
+# below 1024 means the ircd has to be run from inetd. The server can
+# listen to ports in the UNIX domain or the internet domain. If you wish
+# to create a port in the UNIX domain you must compile with UNIXPORT
+# defined in include/config.h. If you are permitting connections to a
+# seperate port, you can control access to that port by the host field.
+#
+# You can now bind internet ports to specific IP interface devices.  To do
+# this put the IP address of the interface in the host field.  To bind to
+# all interfaces, leave empty or put * in.
+#
+# The fields are as follows::
+# P:IP# or UNIX socket file:*:*:port number
+# for example, an internet domain socket on port 6665 for the local
+# computer
+P:127.0.0.1:*:*:6665
+#
+# This line is an example of a UNIX domain socket in /tmp
+P:/tmp/.ircd:*:*:6666
+
diff --git a/doc/faq b/doc/faq
new file mode 100644 (file)
index 0000000..69c37fa
--- /dev/null
+++ b/doc/faq
@@ -0,0 +1,193 @@
+[ $Id$ ]
+
+UnrealIRCd FAQ
+Made by Stskeeps
+
+This file will contain frequently asked questions about 
+Unreal IRCd. If you need more help email stskeeps@tspre.org
+
+1) * I compile and everything seems fine during the compiling, but when it
+   comes time for the program to link, I get errors complaining about dns and
+   res things. What causes this?
+
+A: You need to make sure -lresolv is included in the "extra libraries"
+   option of ./Config (or IRCDLIBS in top-level makefile)
+
+2) * When I start up the IRCd it complains about something with chdir()?
+
+A: You need to make sure the right directory is specified when you was 
+   asked about "What directory are all the server configuration files in?"
+   ./Config question
+
+3) The server says like: 
+   *** Link server1 -> server2 is now synced [secs: 30 recv: 130.4 sent: 120.0]
+   when I link two servers together, what does that mean?
+
+A: That means the link is "synced" (all infodata transfered about the server).
+   The "secs" (30 in this example) means it took 30 seconds to do the sync
+   "recv: 130.4" means there was recieved 130 KiloBytes and 4 bytes.
+   "sent: 120.0" means there was sent 120 kilobytes from my side.
+
+4) What is a negative TS split?
+
+A: Every computer/server has got a time (so they can do TimeStamps) .. 
+   When the clock on the computer is set wrong and the computer it links 
+   upto is wrong it creates a Negative TS split (means time is lower it
+   actually is. How to fix this is contacting the root of the machine
+   and ask him to fix the time (when you made sure it's YOUR server that's 
+   wrong)
+
+5) What is an uProtocol ?
+
+A: UnrealIRCd uses numbers to check if a link is compatible with itself
+   F.x Unreal v2.1.3 has got number 2103 while version 2.1 only has got 
+   2100 - This means .. if the number is lower/higher than the uProtocol
+   the server uses, it's an incompatible link (of some reasons)
+
+6) How does T:Lines work and what are they?
+
+A: T:Lines is a new Unreal feature that makes it able to show different 
+  MOTDs and RULES to people who matches a certain hostmask . Lemme show you some examples:
+   T:*.dk:motds/danish.motd:rules/danish.rules
+   T:*.fr:motds/french.motd:rules/french.rules
+  This will get people from Denmark to see the "Danish" MOTD and the "Dandish" RULLES
+  and people from France to see the French ones:) 
+  
+  NOTE: T:Lines are read up side down so if you have a T:*:ircd.motd:ircd.rules in the bottom
+        it should be at the top so the other motd lines can work as well
+
+7) Where can i download updates to Unreal?
+
+A: Mostly you can download the newest version at 
+   http://unreal.tspre.org
+
+   Versions may be spewed out regulary due to new features and bugs.. 
+
+8) Why does it say "unlimit core failed" or something when I boot the IRCd?
+A: It's just a warning, mainly just ignore it.
+
+9) I use Linux Mandrake and ./Config always hangs! What can I do??
+A: Go edit the Config script and remove those lines:
+-SNIP START-
+cat > $TMP <<__EOF__
+#$STRINGH STRINGH
+#$STRINGSH STRINGSH
+#ifdef STRINGH
+#include <string.h>
+#endif
+#ifdef STRINGSH
+#include <strings.h>
+#endif
+main()
+{
+       char  *t = "a", *s = strtok(t, ",");
+       if (!strcmp(t, s))
+               exit(0);
+       exit(1);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -ne 0 ] ; then
+       echo $n " strtok$c"
+       NSTRTOK=define
+else
+       $EXEC
+       if [ $? -ne 0 ] ; then
+               echo $n " strtok$c"
+               NSTRTOK=define
+       fi
+fi
+$RM -f $EXEC $TMP
+--- SNIP END---
+And replace it by
+NSTRTOK=undef
+
+This should get it to work=) (thanks to Joe Whipple for reporting this bug)
+---END----
+
+10) Hosts show up as (null).network.net !!
+A:  This is because you have forgotten to include the network file.
+    The correct form is (in unrealircd.conf)
+    Include ..........: <network file>
+
+    If this doesn't work .. seek me at irc.global-irc.net #unrealircd
+
+11) The IRCd uses like 66.7% CPU !!!?
+A:  Try run it with nice :
+    /usr/bin/nice -n 19 src/ircd
+
+    if services go this way too just place ./<name> instead of src/ircd
+    Any more support seek me at the default place:P
+
+12) My IRCd which runs on a FreeBSD says something about FDs and
+    Max: 0 What shall I do?? 
+A:  Well it's somekinda bug but you can workaround it by removing those
+    lines in src/s_bsd.c: (init_sys())
+
+<- snippet 1 ->
+#ifdef RLIMIT_FD_MAX
+       struct rlimit limit;
+       int     pid;
+
+       if (!getrlimit(RLIMIT_FD_MAX, &limit))
+           {
+# ifdef        pyr
+               if (limit.rlim_cur < MAXCONNECTIONS)
+#else
+               if (limit.rlim_max < MAXCONNECTIONS)
+# endif
+                   {
+                       (void)fprintf(stderr,"ircd fd table too big\n");
+                       (void)fprintf(stderr,"Hard Limit: %d IRC max: %d\n",
+                               limit.rlim_max, MAXCONNECTIONS);
+                       (void)fprintf(stderr,"Fix MAXCONNECTIONS\n");
+                       exit(-1);
+                   }
+# ifndef       pyr
+               limit.rlim_cur = limit.rlim_max; /* make soft limit the max */
+               if (setrlimit(RLIMIT_FD_MAX, &limit) == -1)
+                   {
+                       (void)fprintf(stderr,"error setting max fd's to %d\n",
+                                       limit.rlim_cur);
+                       exit(-1);
+                   }
+# endif
+           }
+#endif
+
+<-snippet 2->
+#ifdef sequent
+# ifndef       DYNIXPTX
+       int     fd_limit;
+
+       fd_limit = setdtablesize(MAXCONNECTIONS + 1);
+       if (fd_limit < MAXCONNECTIONS)
+           {
+               (void)fprintf(stderr,"ircd fd table too big\n");
+               (void)fprintf(stderr,"Hard Limit: %d IRC max: %d\n",
+                       fd_limit, MAXCONNECTIONS);
+               (void)fprintf(stderr,"Fix MAXCONNECTIONS\n");
+               exit(-1);
+           }
+# endif
+#endif
+
+13) I run debian-sparc and i get errors when compiling in match.c
+    What should I do?
+A: If it says like this
+<-snippet->
+match.c: In function 'myncmp':
+match.c:247: argument 'str1' doesn't match prototype
+/usr/include/string.h:255: prototype declaration
+match.c:247: argument 'str2' doesn't match prototype
+/usr/include/string.h:255: prototype declaration
+match.c:247: argument 'n' doesn't match prototype
+/usr/include/string.h:255: prototype declaration
+<-end of snippet>
+
+Then go into include/setup.h and add this line:
+#define GOT_STRCASECMP
+
+(C) Carsten Munk 1999
\ No newline at end of file
diff --git a/doc/irc.1 b/doc/irc.1
new file mode 100644 (file)
index 0000000..eaecee5
--- /dev/null
+++ b/doc/irc.1
@@ -0,0 +1,82 @@
+.\" $Id$
+.TH IRC 1 "7 October 1990"
+.SH NAME
+irc \- User Interface to Internet Relay Chat Protocol
+.SH SYNOPSIS
+\fBirc\fP [\fB-p\fP \fIportnum\fP] [\fB-c\fP \fIchannel\fP] [ \fInickname\fP [ \fIserver\fP ]]
+.SH DESCRIPTION
+.LP
+\fBIrc\fP is a user interface to the Internet Relay Chat, a CB-like
+interactive discussion environment.  It is structured into \fIchannels\fP,
+which are public discussion forums, and also allows for private intercommunication.
+Each participant has a \fInickname\fP, which is the one specified in the command
+line or else his login name.
+.LP
+Once invoked, \fBirc\fP connects as a client to the specified server,
+\fIserver\fP or to the default one (see below).  The screen splits into a dialogue
+window (the major part
+of the screen) and a command line, from which messages can be sent and
+commands given to control irc.
+.SH COMMAND SYNTAX
+The syntax of irc commands is of the form \fB/COMMAND\fP.  The most notable
+ones are listed below.  For an uptodate list, use the \fBHELP\fP command
+of \fBirc\fP.  Case is ignored.
+.IP "\fB/ADMIN\fR [\fIserver\fP]"
+Prints administrative information about an IRC \fIserver\fP.
+.IP "\fB/AWAY\fP [\fImessage\fP]"
+Mark yourself as being away (with an automatic reply \fImessage\fP
+if specified)
+.IP "\fB/BYE\fR, \fB/EXIT\fR, \fB/QUIT\fR"
+Terminate the session
+.IP "\fB/CHANNEL\fR [\fIchannel\fP]"
+Join another \fIchannel\fP
+.IP "\fB/CLEAR\fR"
+Clear the screen
+.IP "\fB/HELP\fR [\fIcommand\fP]"
+Display a brief description of the \fIcommand\fP (or list all commands, if none
+specified).
+.IP "\fB/SUMMON\fR \fIuser\fP"
+Allows to summon a \fIuser\fP specified as a full Internet address, i.e.,
+\fIlogin@host.domain\fP, to an IRC dialogue session (in much the same
+way as the talk(1) command).  It is usable ONLY if the irc daemon runs on
+the target machine (host.domain).
+.IP "\fB/TOPIC\fR \fItopic\fP"
+Sets the \fItopic\fP for the current channel
+.IP "\fB/WHO\fR [\fIchannel\fP|*]"
+Lists all users of IRC if no argument, of the specified \fIchannel\fP or of the
+current channel (*).
+.SH ARGUMENTS
+.IP "\fB-p\fP \fIportnum\fP"
+TCP/IP "port number.  Default is 6667 and this option should seldom if ever"
+be used.
+.IP "\fB-c\fP \fIchannel\fP"
+\fIChannel\fP number to join upon beginning of the session.  Default is no channel.
+.IP "\fInickname\fP"
+\fINickname\fP used in the session (can be changed with the \fB/NICK\fP command).
+Default is user login name.
+.IP "\fIserver\fP"
+\fIServer\fP to connect to.  Default is specified in the irc system configuration
+file, and can be superseded with the environment variable IRCSERVER.
+.SH EXAMPLE
+.RS
+.nf
+tolmoon% \fBirc -p6667 Wizard tolsun\fP
+.fi
+.RE
+.LP
+connects you to irc server in host tolsun (port 6667) with nickname Wizard
+.SH COPYRIGHT
+Copyright (c) 1988 University of Oulu, Computing Center, Finland.
+.nf
+Copyright (c) 1988,1989,1990 Jarkko Oikarinen
+.nf
+All rights reserved.
+For full COPYRIGHT see LICENSE file with IRC package.
+.SH "SEE ALSO"
+ircd(8)
+.SH BUGS
+What bugs ?
+.SH AUTHOR
+Jarkko Oikarinen <jto@tolsun.oulu.fi>
+.nf
+Manual page updated by Michel Fingerhut <Michel.Fingerhut@ircam.fr>
diff --git a/doc/ircd.8 b/doc/ircd.8
new file mode 100644 (file)
index 0000000..16bdc15
--- /dev/null
@@ -0,0 +1,140 @@
+.\" $Id$
+.TH IRCD 8 "29 March 1989"
+.SH NAME
+ircd \- The Internet Relay Chat Program Server 
+.SH SYNOPSIS
+.hy 0
+.IP \fBircd\fP
+[-a] [-c] [-i] [-o] [-q] [-t] [-d directory]
+[-f configfile] [-x debuglevel] [-h hostname] [-p portnum]
+.SH DESCRIPTION
+.LP
+\fIircd\fP is the server (daemon) program for the Internet Relay Chat
+Program.  The \fIircd\fP is a server in that its function is to "serve"
+the client program \fIirc(1)\fP with messages and commands.  All commands
+and user messages are passed directly to the \fIircd\fP for processing
+and relaying to other ircd sites.  The \fIirc(1)\fP program depends upon
+there being an \fIircd\fP server running somewhere (either on your local
+UNIX site or a remote ircd site) so that it will have somewhere to connect
+to and thus allow the user to begin talking to other users. 
+.SH OPTIONS
+.TP
+.B \-d directory
+This option tells the server to change to that directory and use
+that as a reference point when opening \fIircd.conf\fP and other startup
+files.
+.TP
+.B \-o
+Starts up a local ircdaemon. Standard input can be used to send IRC
+commands to the daemon. The user logging in from standard input will
+be given operator privileges on this local ircd. If ircd is a setuid program,
+it will call setuid(getuid()) before going to local mode. This option
+can be used in inetd.conf to allow users to open their own irc clients
+by simply connecting their clients to the correct ports. For example:
+.TP
+.B
+irc stream tcp nowait irc /etc/ircd ircd \\-f/etc/ircd.conf \\-o
+
+allows users connecting to irc port (specified in /etc/services) to start
+up their own ircdaemon. The configuration file should be used to check from
+which hosts these connections are allowed from. This option also turns
+on the autodie option -a.
+.TP
+.B \-a
+Instructs the server to automatically die off if it loses all it's clients.
+.TP
+.B \-t
+Instructs the server to direct debugging output to standard output.
+.TP
+.B \-x#
+Defines the debuglevel for ircd. The higher the debuglevel, the more stuff
+gets directed to debugging file (or standard output if -t option was used
+as well).
+.TP
+.B \-i
+The server was started by inetd and it should start accepting connections
+from standard input. The following inetd.conf-line could be used to start
+up ircd automatically when needed:
+.TP
+.B
+ircd stream tcp wait irc /etc/ircd ircd \-i
+
+allows inetd to start up ircd on request.
+.TP
+.B \-f filename
+Specifies the ircd.conf file to be used for this ircdaemon. The option
+is used to override the default ircd.conf given at compile time.
+.TP
+.B \-c
+This flag must be given if you are running ircd from \fI/dev/console\fP or
+any other situation where fd 0 isnt a tty and you want the server to fork
+off and run in the background. This needs to be given if you are starting
+\fIircd\fP from an \fIrc\fP (such as \fI/etc/rc.local\fP) file.
+.TP
+.B \-q
+Using the -q option stops the server from doing DNS lookups on all the
+servers in your \fIircd.conf\fP file when it boots. This can take a lengthy
+amount of time if you have a large number of servers and they are not all
+close by.
+.TP
+.B \-h hostname
+Allows the user to manually set the server name at startup. The default
+name is hostname.domainname.
+.B \-p portname
+Specifies the port where the daemon should start waiting for connections.
+This overrides the default which is given at compile time.
+.TP
+.SH
+If you plan to connect your \fIircd\fP server to an existing Irc-Network,
+you will need to alter your local IRC CONFIGURATION FILE (typically named
+"ircd.conf") so that it will accept and make connections to other \fIircd\fP
+servers.  This file contains the hostnames, Network Addresses, and sometimes
+passwords for connections to other ircds around the world.  Because 
+description of the actual file format of the "ircs.conf" file is beyond the
+scope of this document, please refer to the file INSTALL in the IRC source
+files documentation directory.
+.LP
+BOOTING THE SERVER:  The \fIircd\fP server can be started as part of the
+UNIX boot procedure or just by placing the server into Unix Background.
+Keep in mind that if it is *not* part of your UNIXES Boot-up procedure 
+then you will have to manually start the \fIircd\fP server each time your
+UNIX is rebooted.  This means if your UNIX is prone to crashing
+or going for for repairs a lot it would make sense to start the \fIircd\fP
+server as part of your UNIX bootup procedure.  In some cases the \fIirc(1)\fP
+will automatically attempt to boot the \fIircd\fP server if the user is
+on the SAME UNIX that the \fIircd\fP is supposed to be running on.  If the
+\fIirc(1)\fP cannot connect to the \fIircd\fP server it will try to start
+the server on it's own and will then try to reconnect to the newly booted
+\fIircd\fP server.
+.SH EXAMPLE
+.RS
+.nf
+tolsun% \fBircd\fP
+.fi
+.RE
+.LP
+Places \fIircd\fP into UNIX Background and starts up the server for use.
+Note:  You do not have to add the "&" to this command, the program will
+automatically detach itself from tty.
+.SH COPYRIGHT
+(c) 1988,1989 University of Oulu, Computing Center, Finland,
+.LP
+(c) 1988,1989 Department of Information Processing Science,
+University of Oulu, Finland
+.LP
+(c) 1988,1989,1990,1991 Jarkko Oikarinen
+.LP
+For full COPYRIGHT see LICENSE file with IRC package.
+.LP
+.RE
+.SH FILES
+ /etc/utmp
+ "irc.conf"
+.SH "SEE ALSO"
+irc(1)
+.SH BUGS
+None... ;-) if somebody finds one, please inform author
+.SH AUTHOR
+Jarkko Oikarinen, currently jto@tolsun.oulu.fi,
+manual page written by Jeff Trim, jtrim@orion.cair.du.edu,
+later modified by jto@tolsun.oulu.fi.
diff --git a/doc/m4macros b/doc/m4macros
new file mode 100644 (file)
index 0000000..5282d7f
--- /dev/null
@@ -0,0 +1,47 @@
+[ $Id$ ]
+The following macros are included in "ircd.m4" for use with the m4 text
+preprocessor.  "ircd.m4" is parsed before the IRC server conf file so they
+are all available for use with that.
+
+NOTE:  The "ircd.m4" file is *ONLY* created by a "make install".
+
+VERSION - current version string as in patchlevel.h
+DEBUGMODE - if DEBUGMODE is define in config.h, is also defined for m4.
+HOSTNAME - taken from hostname(1)
+USER - username of person doing the "make install"
+PORT - default port number as in config.h
+PFREQ - default ping frequency as in config.h
+CFREQ - default connect frequency as in config.h
+MAXSENDQ - default max sendq as in config.h
+CL - use this to wrap a class number
+HOST - use this to wrap a hostname
+HOSTM - use this to wrap the hostmask number in N-lines
+ID - when wrapping the host field in an I-line, causes ident string return
+     to be used instead of user supplised username.
+PASS - use this to wrap passwords in C/N/I/O lines
+PING - use this to wrap the ping value in Y-lines
+APORT - use this to wrap the port number in I-lines
+CPORT - use this to wrap the port number in C-lines
+SERV - use this to wrap server names
+
+You might use some of these as
+C:foo.bar.edu:PASS(boo):foo.bar.edu:APORT(6667)
+I:ID(128.250.*)::ID(*.mu.oz.au):CPORT(6667)
+
+In addition to these (rather weak macros), some more complete ones are
+defined which already perform the above.
+
+ADMIN - provide fields to it as you would an A-line
+ALLOW - provide fields to it as you would an N-line
+BAN - provide fields to it as you would an K-line
+CLASS - provide fields to it as you would an Y-line
+CLIENT - provide fields to it as you would an I-line
+CONNECT - provide fields to it as you would an C-line
+ME - provide fields to it as you would an M-line
+HUB - first parameter is server you want to hub, second is optional and is
+      a mask against which other servers introduced must match against.
+LEAF - works like HUB, except that the mask is matched against server names
+       to check if the link should be dropped.
+SERVER - uses 6 fields, the first 4 as are found in an N-line, the last two
+         should be as you would use in a C-line.  It expands out to provide
+         both a C and N line.
diff --git a/doc/server-compile-guide b/doc/server-compile-guide
new file mode 100644 (file)
index 0000000..f30b85c
--- /dev/null
@@ -0,0 +1,294 @@
+  [ $Id$ ]
+From: Carlo Kid - Runaway <carlo@sg.tn.tudelft.nl>
+Subject: GUIDE for compiling your server
+To: wastelanders@rush.cc.edu (New Wastelanders MailingList)
+Date: Thu, 26 May 94 13:44:10 METDST
+Cc: carlo@sg.tn.tudelft.nl
+Mailer: Elm [revision: 66.33]
+Status: RO
+
+GUIDE for compiling your server,     by Runaway
+===============================================
+
+First of all you must get all the files you need, as an example
+I will explain how to compile irc2.8.19.U3.2.
+The files you'll need in general are:
+
+- irc2.8.19.U3.2.tar.gz
+
+Or, when you already have an older version -say irc2.8.19.U3.1- a patch:
+
+- irc2.8.19.U3.1-2.patch
+
+It is possible you need more then one patch, especially when you already
+upgraded more often. But in that case you already have those old patches.
+Of course, in that case, you also already have the old directory tree:
+
+/home..../yourname/....ircd/irc2.8.19.U3.1/
+
+Scripts, patches and directory trees
+====================================
+
+It is good practise to:
+1) Call the directory tree after the version
+2) Let this directory ONLY contain what comes with the .tar.gz file!
+   Thus: Do NOT put ircd.conf, or any patches etc in it!!!
+   In general, you must be able to delete this whole directory tree
+   when you still have the original .tar.gz file and patches applied to it.
+3) Put it in a directory ending on /ircd, THIS directory will contain
+   your ircd.motd, ircd.pid, ircd.conf and patches...
+
+So, you end up with:
+
+...ircd/irc2.8.19.U3.1-2.patch
+...ircd/irc2.8.19.U3.1.tar.gz
+
+or just:
+
+...ircd/irc2.8.19.U3.2.tar.gz
+
+at once.
+
+Before you can delete the old directory tree, you must be SURE to save
+everything thats in it. This is thus the .tar.gz file, all patches but
+ALSO the following files:
+
+Makefile
+include/config.h
+include/setup.h
+
+You should always keep a copy of those files OUTSIDE the irc2.8.19.U3.2/
+directory tree. For instance:
+
+...ircd/irc.personal/Makefile
+...ircd/irc.personal/include/config.h
+...ircd/irc.personal/include/setup.h
+
+To make these backups easy, you should make a script, called backup.personal
+containing:
+
+cp Makefile ../irc.personal/Makefile
+cp include/config.h ../irc.personal/include/config.h
+cp include/setup.h ../irc.personal/include/setup.h
+
+If you also change anything in the other Makefiles (ircd/Makefile and
+common/Makefile) you can add those too. Be sure to make the directories
+by hand first.
+
+Make the script 'backup.personal' executable with:
+chmod 700 backup.personal
+You must be able to run it from any directory, so put it in your ..bin/
+
+Ok... so now you have a backup of everything. If you wanted to start
+ALL over you could delete the directory tree, unzip and untar the archive
+again, apply all patches to it, change the Makefile and config.h again,
+put setup.h back, recompile and reinstall.
+In some cases it is easy to do this with an other script, I call it 'repatch',
+it provides you with an easy-to-change overview of the patched you have used.
+Here is how my 'repatch' looks now (it is located in .../ircd/repatch).
+
+cd ~/irc/ircd
+rm -rf irc2.8.19 irc2.8.19.U3.2
+zcat irc2.8.19.tar.gz | tar xf -
+mv irc2.8.19 irc2.8.19.U3.2
+cd irc2.8.19.U3.2
+#patch -p1 < ../Makefile.config.h.patch 2> ../patch.out
+#cp ../setup.h include/setup.h
+patch -p1 < ../irc2.8.19-TSpre8.2.patch 2>> ../patch.out
+patch -p1 < ../irc2.8.19.TSpre8-note.patch 2>> ../patch.out
+patch -p1 < ../irc2.8.19.TSpre8-wallops.patch 2>> ../patch.out
+patch -p1 < ../irc2.8.19.TSpre8-bquiet.patch 2>> ../patch.out
+patch -p1 < ../irc2.8.19.TSpre8-silence.2.patch 2>> ../patch.out
+#patch -p1 < ../irc2.8.19.U3-ban.patch 2>> ../patch.out
+make clean
+vi include/patchlevel.h
+grep -e '\.rej' -e '[Ff]ail' -e fuzz ../patch.out
+
+As you can see I commented out the patches Makefile.config.h.patch and
+irc2.8.19.U3-ban.patch, and don't copy setup.h here. This is because
+I wanted to make a virgin .U3.2.tar.gz for distribution via ftp-sites.
+If I change the name of the directory, I have to change it in three
+places :/
+This script forces me to edit the patchlevel.h :) :)
+The last grep warns me if anything went wrong with the patches.
+
+Moreover, as you can see, I have a 'Makefile.config.h.patch'.
+You should make your own as soon as you completely installed
+and tested your server. It is very handy for re-installing a new
+version.
+
+To make this patch, edit the Makefile's and and config.h and type:
+
+backup.personal
+cd ..
+rm -rf irc2.8.19
+zcat irc2.8.19.tar.gz | tar xf -
+diff -rc irc2.8.19 irc.personal > Makefile.config.h.patch
+
+Check it with an editor if it looks ok. In the above, 'irc2.8.19.tar.gz'
+is the virgin 'Avalon' version, I change the Makefiles in the .U3
+however also, so you might wanna use the virgin .U3.2.tar.gz.
+
+Starting ALL over (or begining for the first time)
+==================================================
+
+This is about EDITTING the Makefile(s) and config.h, and creating the
+setup.h for the first time.
+
+2.8.19 is different from 2.8.16 and before. You will have to EDIT the
+Makefile and config.h that comes with the distribution. You can NOT
+use the old Makefile and config.h you had !
+
+First write down the path you want to use where you are going to put
+the ircd.conf etc...
+
+Edit the Makefile. Comments are in it. You should simply define that
+what is needed for your Operating System.
+
+Then edit the config.h
+
+Then run ./Config to create setup.h ... at first simply hit return all the
+time. If you insist on using gcc instead of cc, you must edit that in your
+Makefile BEFORE running setup.h. You can't change that running Config,
+although it asks for it. If you have more then one cc, you can add the
+right path to in the Makefile (if it uses the wrong one).
+
+Since U3.2, I changed the Makefile and config.h a little. The changes are:
+- I added note.o to the dependency
+- I added *.orig files to the 'make clean' (otherwise the *.orig generated
+  by some 'patch' programs will be left).
+If you want this too, and you have .U3.1, you can get the patch from
+sg.tn.tudelft.nl (file: Makefile.conf.U3.patch).
+
+As soon as you are done, run backup.personal. To stay up to date with your
+backup.
+
+Then make the Makefile.conf.patch as described above. (or wait with that
+till you are sure it works... otherwise it might be done more then once
+which is a waste of time).
+
+Special remarks
+---------------
+
+Makefile:
+First occurance of
+        CC=cc
+Change this NOT if you want another compiler, add another CC= later, close
+to your OS specific #defines...
+
+# IRCDDIR must be the same as DPATH in include/config.h
+#
+IRCDDIR=/sb/users/carlo/irc/ircd
+Make sure you use the same path in the config.h :)
+
+SUBDIRS=common ircd
+By removing the 'irc' from this line, you stop 'make' from making the client
+as well.
+
+config.h:
+/*
+ * NOTE: On some systems, valloc() causes many problems.
+ */
+#undef  VALLOC                  /* Define this if you have valloc(3) */
+I never try it, even if I have it.
+
+#define USE_VARARGS
+For defines like this, you best check the online manual if you have them
+(man vprintf in this case)... I didn't have man page for vscanf() but it
+still worked... (I DO have them for vprintf and vsprinf).
+
+#undef  DEBUGMODE               /* define DEBUGMODE to enable debugging mode.*/
+Debug mode uses a lot more memory and is a lot slower. ONLY define
+when your server gives problems like crashing/coredumping, or other
+things like not wanting to startup etc. In other words: when you are really
+*USING* this feature to do DEBUGing !
+
+#define NPATH "/sb/users/carlo/irc/server/Undernet/.ircdnote"
+The '#ifdef notdef' '#endif' around NPATH mean: notdef = NOT DEFINED.
+You should *never* #define notdef... It is used to "comment out" *examples*.
+By defining it, you enable all examples (like making your server SUI :/)
+Simply *remove* the lines '#ifdef notdef' and '#endif' around the NPATH.
+
+#define DPATH   "/sb/users/carlo/irc/ircd"
+Must be the same as in the Makefile!
+#define SPATH   "/sb/users/carlo/bin/ircd" /* path to server executeable */
+This is used when you do a /RESTART. For fast restarting a NEW version (upgrade)you can let this point to a symbolic link, and then change this link to the
+new executable. Do a 'restart' and voila...
+For instance:
+.../bin/ircd.U3.2*
+.../bin/ircd -> ircd.U3.2
+The last made with:
+ln -s ircd.U3.2 ircd
+Then when you upgrade:
+rm ircd
+ln -s ircd.U3.3 ircd
+and a /RESTART
+
+#undef  CRYPT_LINK_PASSWORD
+Make sure your ircd.conf isn't world readable like on pasadena :/
+(and on ircserver.et.tudelft.nl once - we DID have to change all passwords
+ then)
+
+Compiling the server
+====================
+
+*** FIRST edit your include/patchlevel.h ***
+
+If you don't want to compile the client, you can change the Makefile
+as mentioned above, or type:
+make server
+
+After a succesfull compilation (ignore warning ;), you can type
+make install
+or just
+cp ircd/ircd ~/bin/ircd.U3.2
+cd ~/bin
+chmod 700 ircd.U3.2
+rm ircd
+ln -s ircd.U3.2 ircd
+
+I changed my Makefile to do the latter thing when I type 'make install'
+
+Then run the server by typing 'ircd'. Don't do this on the
+...ircd/irc2.8.19.U3.2/ircd/ directory, because when in your PATH the
+'.' comes before your '~/bin' you start up THAT exucutable, disallowing
+you to recompile later (text file busy).
+
+Compile errors
+==============
+
+If anything goes wrong with note, it most likely is because you
+1) Didn't define NPATH correctly
+2) Didn't add the note.o to the dependencies.. remove note.o and recompile.
+
+[ For a non-undernet version: irc2.8.19.tar.gz is bugged, get the -note.patch
+  from ftp.undernet.org. ]
+
+If you get problems while linking saying it has undefined _something
+and something is something with 'res', you must add -lresolv to your
+IRCDLIBS in the Makefile.
+
+If you get problems with any function beging defines twice are giving
+errors like not compatible with previous definition (likely atol() in
+note.c), just remove that whole function from the .c file (put #ifdef notdef
+around it). You have it already in your system libraries.
+
+Last remarks
+============
+
+Add those U: lines!!!
+And change your ircd.motd to reflect the new commands/features :)
+( /MOTD uxb*   -- Nice motd RedRum! :)
+
+-------------------------------------------------------------------
+
+Run
+
+--
+-------------------------------------------------------------------------------
+|  carlo@sg.tn.tudelft.nl           |  Run @ IRC                              |
+|                                   |  Admin of Delft.NL.EU.undernet.org      |
+| * Don't expect anything of live,  |  and      Ircserver.et.tudelft.nl       |
+| or you'll miss all the rest of it.|                                         |
+-------------------------------------------------------------------------------
+
diff --git a/doc/tao.of.irc b/doc/tao.of.irc
new file mode 100644 (file)
index 0000000..d78e3c5
--- /dev/null
@@ -0,0 +1,271 @@
+
+The Tao of Internet Relay Chat
+Copyright (C) Ove Ruben R Olsen 1994
+Version of 940110
+Contributing masters: Master ScottM
+
+-----
+Something is formed by the electrons, born in the silent cable. Shaping
+and growing and ungrowing. It is there yet not there. It is the source of
+Internet Relay Chat. I do not know the name, thus I will call it the Tao
+of Internet Relay Chat.
+
+If the Tao is great, then the IRC is running ceaselessly. If the IRC is
+great then the server is running without ever stoping. If the server is
+great then the client will always be the server. The luser is then pleased
+and there is Chat in the world.
+
+The Tao of IRC squits far away and connects on returning.
+
+
+-----
+The genetic potential of birth, a lot to know, yet unknown.
+
+In the begining there was nothing.
+
+Out of nothing the Tao gave birth to tolsun.oulu.fi. tolsun gave birth to
+OuluBox.
+
+OuluBox gave birth to rmsg.
+
+rmsg was not Tao, so MUT gave birth to IRC.
+
+No one knows when IRC came into existance, the mighty master WiZ have it
+to be at the end of the eight month in the year of the Dragon.
+
+
+-----
+Each channel has its purpose, however humble. Each channel is the Yin and
+Yang of IRC. Each channels has it's place within the IRC.
+
+In the beginning there was only channel 0, thus channel 0 is the soil of
+IRC.
+
+Channel 1 to channel 10 then was open as the sea. Channel 11 to 999 was the
+trees and forests of IRC. Channels above 999 should not be mentioned, and
+channels below 0 were unborn and contained many secrets.
+
+This was not the right Tao, so IRC gave birth to +channels.
+
++channels had the yin and yang. Mode does not.
+
+This was not the right Tao still, so IRC gave birth to #channels.
+
+#channels have the yin and yang.
+
+Only channel 0 is the right path to Tao, but avoid speaking on channel 0.
+
+
+-----
+There was a great dispute among the Broom-Walkers of the Relay. Some of them
+wanted neither yin nor yang. Out of this Eris came into existance. Some of the
+Broom-Walkers then created Eris Free-net.
+
+This was the right Tao.
+
+Kind Gentle and Boring Net was another wrong path to the Tao of Internet Relay
+Chat.
+
+Some time later there was a quantity of some lusers who wanted to be
+Broom-Walkers also. The Eris Free Broom-Walkers did not agree with them,
+thus a new IRC was born. This IRC is called the Undernet.
+
+But this is not the right Tao, either.
+
+
+-----
+There will always be disputes among the Broom-Walkers of Internet Relay Chat.
+
+This is the very nature of the IRC.
+
+
+-----
+Lusers that do not understand the Tao is always using the yang of Mode on
+their channels. Lusers that do understand the Tao are always using Ignore
+on their channels.
+
+How could this not be so ?
+
+
+-----
+The wise sage luser is told about the Chat and uses it. The luser is told
+about the IRC and is looking for it. The flock are told about the Tao and
+make a fool of the IRC.
+
+If there was no laughter, there would be no Tao.
+
+
+-----
+The master says:
+"Without the Tao of Internet Relay Chat, life becomes meaningless."
+
+The Relay of the old time was mysterious and sacred. We can neither imagine
+its thoughts nor path; we are left but to describe.
+
+
+-----
+The sage luser must be aware like a frog crossing the highway.
+
+
+-----
+The great master Wumpus once dreamed that he was an automaton. When he awoke
+he exclaimed:
+        "I don't know whether I am Wumpus dreaming that I am a client,
+                 or a client dreaming that I am Wumpus!"
+                 
+So was the first Automata born.
+
+The master Nap then said:
+        "Any automata should not speak unless spoken to.
+         Any automata shall only whisper when spoken to."
+
+Thus replied the master Gnarfer:
+        "The lusers shall keep in mind that a automata can be either good or
+         bad. Create good automata, and the IRC will hail you and you will
+         gain fame and fortune. Create bad automata and people will start to
+         hate you, and finaly you will be /KILLed to ethernal damnation"
+
+Many lusers have fallen into the clutches of ethernal damnation. They where
+not following the Tao.
+
+
+-----
+There once was a luser who went to #BotSex. Each day he saw the automatons.
+The luser decided that he also would have such a automata.
+He asked another luser for his automata. The other luser gave his automata
+away.
+
+The luser was not within the Tao, so he just started the automata. The automata
+had only Yang inside so all the lusers files where deleted.
+
+Some moons laither the same luser then had become a sage luser, and did create
+his automata from the very grounds with materials found inside the IRC.
+The luser was now within the Tao and his automata lived happily ever after.
+
+
+-----
+There once was a master who wrote automatons without the help of master Phone.
+A novice luser, seeking to imitate him, began with the help of master Phone.
+When the novice luser asked the master to evaluate his automata the master
+replied: "What is a working automata for the master is not for the luser.
+You must must BE the IRC before automating."
+
+
+-----
+Master BigCheese gave birth to master Troy; his duty clear. Master Troy gave
+birth to master Phone, for the Tao of Irc must be eternal and must flow as the
+ceaseless river of Time itself.
+
+
+-----
+Master Phone once said about the ircII client:
+        "public_msg is for a message from someone NOT on the channel
+         public_other is for a message on a channel that doesn't belong to
+         a window. public is for a message on a channel that belongs to a
+         window!"
+
+Out of this raised the mighty chaos.
+
+
+-----
+The sage luser came to the master who wrote automata without the help of
+master Phone. The sage luser asked the master who wrote automata: "Which is
+easiest to make. A automata with the help of master Phone or an automata
+made with the help of a language ?"
+
+The master who wrote automata then replied:
+        "With the help of a language."
+
+The sage luser was disapointed and exclaimed: "But, with master Phone you
+do not need to know anything about the soil of IRC. Is not that the easiet
+way ?"
+
+"Not really" said the master who wrote automata, "when using master Phone
+you are closed inside a box. For sure, it is a great box for the lusers,
+but the master will need more power, thus a language is the only path to go.
+With the language the master will never have to limit himself. When using
+such a language the master will seek the best between the need and the
+availibility."
+
+"I see", said the sage luser.
+
+This is the essence of Tao of IRC automatas.
+
+
+-----
+A client should be light and be used for communication. The spirit of a good
+client is that it should be very convinient for the luser to use, but hard
+for the luser who want to create automata.
+There should never ever be too many functions or too few functions.
+
+There should always be a ignore.
+
+Without ignore the client is not within the Tao of Chating.
+
+The client should always respond the luser with messages that will not
+astnonish him too much. The server likewise. If the server does not, then it
+is the clients job to explain what the server says.
+
+A client which fails this, will be useless and cause confusion for the lusers.
+The only way to correct this is to use another client or to write a new one.
+
+
+-----
+A luser asked the masters on #IrcHelp: "My client does not work".
+The masters replied: "Upgrade your client".
+The luser then wondered why the master knew. The master then told him about
+the Protocol.
+
+"Your client does not work beaucse it does not understand the server. Why
+should it always work ? Only a fool would expect such. But, clients are made
+by humans, and humans are not perfect. Only Tao is.
+
+The IRC is solid. The IRC is floating, and will always be dynamic. Live with
+that or /quit."
+
+
+-----
+The luser came to the masters of #IrcHelp, asking about the Tao of IRC within
+the client.
+The masters then said that the Tao of IRC always lies inside the client
+regardless of how the client connects to the server.
+
+"Is the Tao in irc ?" asked the luser.
+"It so is" replied the masters of #IrcHelp.
+"Is the Tao in the ircII, Kiwi, rxirc, vms, rockers and msa ?" asked the
+luser.
+"In all of them and in the TPC, irchat, zenirc, zircon X11-irc and even the
+dos irc has the Tao" said the master quietly.
+"Is the Tao in a telnet connection directly to the server ?"
+
+The master then was quiet for a long time and said. "Please leave, such
+questions are not within the Tao of IRC".
+
+
+-----
+The master says: "Without the Protocol of TCP the messages will not travel.
+                  Without the client, the server is useless."
+
+
+-----
+There once was a luser who used the ircII client. "ircII can do anything I
+ever need for using IRC" said the emacs client user, "I have /ON's, I have
+assignments, I have aliasing. Why don't you use this instead of the huge
+emacs client, which also has a messy screen?"
+The emacs client user then replied by saying that "it is better to have a
+scripting language that is the client instead of have a client that has
+a scripting language." Upon hearing this, the ircII client luser fell silent.
+
+
+-----
+The master Wumpus said: "Time for you to leave. I did, now I'm happy."
+The master Gnarfer replied: "Use, but never overuse IRC, then you will also
+be happy within IRC"
+
+
+-----
+A luser came unto the masters of #EU-Opers and asked, "How can I be, yet not
+be, a user@host within the IRC?"
+The masters of #EU-Opers replied: "To be Tao is to be ones true self. To hide
+ones self is not Tao, and is not IRC, you have much to learn before you shall
+be at rest within the Flow of Irc.  Please leave"
diff --git a/doc/unrealircd.doc b/doc/unrealircd.doc
new file mode 100644 (file)
index 0000000..5480e76
--- /dev/null
@@ -0,0 +1,407 @@
+                ****** UnrealIRCd v2.1.7 Documentation ******
+        [ $Id$ ]
+
+1) About UnrealIRCd
+
+       I started making UnrealIRCd about 1-2 months ago. (July 1999 now)
+       First it was called mpx2.0b13.soundforge - as I was
+       inspired of the 'forge' word. I quickly changed name
+       after I realized the IRCd had more potential.
+        Unreal is based off Elite2.0b13 and some of
+       the minor bugfixes Potvin came up with. First lemme
+       introduce myself. My nick is Techie/Stskeeps. I hang
+       out at Global-IRC.net, DALnet, DragonWings.org and so on
+       
+       Unreal is a hybrid of Elite (as I said) mixed with some
+       Twilight IRCd, TerraIRCd, TS4 (channel mode +h & +e) features
+       (IMHO TwilightIRCd is one of the best dreamforge hybrids I've seen!
+       Unreal is not a rip-off of other IRCds - I added a lot of features myself!
+       I really cannot mention some major features as I think a IRCd is a
+       IRCd when it has got useful commands- and people actually say mine has!
+       
+       Anyways I dunt demand donations or anything. I just do coding for fun
+       I treat coding like playing with toys. It makes me happy(or is it just
+       caffeine?;). An addy to send donations is at the Donation file in the IRCd dir
+       And.. I don't sweat while making features unlike some Potvin coder so dunt
+       send me towels;) I would be more happy if someone e-mailed me with ideas
+       to the IRCd.. The whole IRCd is GNU so if you want to rip off any of my ideas
+       You are generally welcome:) Just remember to do what's said in the Changes file!
+       -- So.. Enjoy this IRCd:) It may become a dream to IRCd owners as its infact
+          a sortof hybrid of EliteIRCd (Cite .man-pages/page1 in Elite:
+       EliteIRCD has become a dream to many ircd owners</end cite>
+          -- Carsten Munk / Techie .. =)
+
+2) Commands (User Commands)
+
+       *** WATCH Command ***
+       Watch is a new notify-type system in UnrealIRCd which is both faster
+       and uses less network resources than any old-style notify
+       system. You may add entries to your Watch list with the command
+       /watch +nick1 [+nick2 +nick3 ..., and the server will send
+       you a message when any nickname in your watch list logs on or off.
+       Use /watch -nick to remove a nickname from the watch list, and
+       just /watch to view your watch list.
+       The watch list DOES NOT REMAIN BETWEEN SESSIONS - you (or your
+       script or client) must add the nicknames to your watch list every
+       time you connect to an IRC server. /Watch was made in DreamForge IRCd
+       which UnrealIRCd in ground is based off
+
+        *** HELPOP Command ***
+       HelpOp is a new system of getting IRC Server help. You type either
+       /HelpOp ? <help system topic>  or /HelpOp ! <question>
+       The "?" in /HelpOp means query the help system and if you get no
+       response you can choose '!' to send it to the Help Operators online
+       ------------oOo--------------
+
+     *** LIST Command ***
+       New extended /list command options are supported.  To use these
+       features, you will likely need to prefix the LIST command with
+       /quote to avoid your client interpreting the command.
+
+       Usage: /quote LIST options
+       
+       If you don't include any options, the default is to send you the
+       entire unfiltered list of channels. Below are the options you can
+       use, and what channels LIST will return when you use them.
+       >number  List channels with more than <number> people.
+       <number  List channels with less than <number> people.
+       C>number List channels created between now and <number> minutes ago.
+       C<number List channels created earlier than <number> minutes ago.
+       T>number List channels whose topics are older than <number> minutes
+                (Ie., they have not changed in the last <number> minutes.
+       T<number List channels whose topics are newer than <number> minutes.
+       *mask*   List channels that match *mask*
+       !*mask*  List channels that do not match *mask*
+       LIST defaults to sending a list of channels with 2 or more members,
+       so use the >0 option to get the full channel listing.  
+
+               *** PRIVMSG Command ***
+       PRIVMSG and NOTICE, which are used internally by the client for
+       /msg and /notice, in UnrealIRCd support two additional formats:
+       /msg @#channel <text> will send the text to channel-ops on the
+       given channel only. /msg @+#channel <text> will send the text
+       to both ops and voiced users on the channel. While some clients
+       may support these as-is, on others (such as ircII), it's necessary
+       to use /quote privmsg @#channel <text> instead. It's perhaps a
+       good idea to add the/alias omsg /quote privmsg @$0 $1 into
+       your script (.ircrc) file in that case.
+
+       **** KNOCK Command ****
+       /Knock is a new UnrealIRCd command which enables you to
+       'knock' on a channel if it is +i and these criteria is met
+       - Channel is not +K (No knocks)
+       - Channel is not +I (No invites!)
+       - You're not banned!
+       - And you are not already there:)
+
+       Syntax:
+      /Knock #Channel :Reason
+     
+      **** LICENSE Command ****
+       This command shows the GNU License
+       Which is hard-coded into the IRCd:)
+       Syntax: /License [optional server]
+
+       *** SetName Command ***
+       /SetName is a new feature in UnrealIRCd
+       Which allows users to change their 'Real name'
+       (GECOS) directly online at IRC without reconnecting
+       
+       Syntax:
+       /SetName :New Real Name
+
+
+       *** MODE Command ***
+       This is basically the /mode command as it has always
+       been on IRC. Thou in Channel mode basis it has got an
+       Extra feature (/mode #Channel ^ ) which reports channel
+       modes represented in a bitstring (may be handy, maybe not)
+       UnrealIRCd has got some new channel / usermodes I think you
+       wish to take a look at
+       Channel Modes Help: /HelpOp CHMODES
+       User modes help: /HelpOp UMODES
+       *** STATSERV Command ***
+       This is a alias for the /msg StatServ command,
+       But is more secure. If the IRC network doesn't have StatServ
+       It will report it is down.
+       
+       Syntax:
+       /StatServ <command>
+
+       *** /Credits Help ***
+       This command will list the credits I've created
+       to thank the people who has helped me with making
+       UnrealIRCd. Anyone who I've forgotten all my kind
+       thoughts go to -- Techie'99
+       
+       Syntax:
+       /Credits [optional server]
+
+       *** /DALINFO Help ***
+       This command will list the credits that the
+       Dreamforge IRCd team/the IRCd developers
+       from the start when IRCd got developed
+       
+       Syntax:
+       /DALInfo [optional server]
+
+3) Operator Commands
+
+       This section is the IRCOp's only commands
+       area:) - These topics are available:
+       Note: This doesnt include Dreamforge commands
+
+       SETHOST    SETIDENT     SDESC
+       ADCHAT     NACHAT       TECHAT
+       GLINE      REMGLINE     STATS
+       MKPASSWD   SNOTES       SNOTE
+       ADDLINE    LAG          RPING
+       ADDMOTD    ADDOMOTD     OPERMOTD
+       CHGHOST    TSCTL        SAJOIN
+
+       *** ADDMOTD Command Help ***");
+       This will add the text you specify to the MOTD
+       (the general motd - T:lines doesnt count ..)
+       Server Admin & Co-Admin only
+
+       Syntax: /ADDMOTD :text
+
+       *** ADDOMOTD Command Help ***
+       This will add the text you specify to the Operator MOTD
+       Server Admin & Co-Admin only
+       
+       Syntax: /ADDOMOTD :text
+
+       *** OPERMOTD Command Help ***
+       This is a IRCop only command - shows the IRCd Operator MOTD
+       Syntax: /OperMotd
+                       
+       *** SETHOST Command Help ***
+       This command is so you can change your
+       Virtual host (hiddenhost) to everything you want to
+       Except special characters;). 
+       
+       Syntax:
+       /SetHost <new hostname>)
+       
+       Example:
+       /Sethost ircaddicts.org
+       
+       *** SETIDENT Command Help ***
+       With this command you can change your
+       ident (username).
+       
+       Syntax:
+       /SetIdent <new ident>
+
+       Example:
+       /SetIdent root
+
+       *** SDesc Command help ***
+       NOTE: This is a Server Admin/Co Admin only command
+       With this command you can change your Server Info Line
+       Without having to squit and reconnect.
+       Syntax: /SDesc :New description
+       Example: /SDesc :If you belong to me..          
+
+       *** AdChat Command Help ***
+       This command sends to all Admins online (IsAdmin)
+       Only for Admins. This is a ChatOps style command
+       Syntax: /AdChat :<text>
+       Example: /AdChat :Hey guys!
+  
+       *** NAChat Command Help ***
+       This command sends to all NetAdmins & TechAdmins online
+       Only for Net/Techadmins. This is a ChatOps style command
+       Syntax: /NAChat :<text>
+       Example: /NAChat :Hey guys!
+       
+       *** Stats Command Help ***
+       UnrealIRCd has got a extension called /Stats G
+       Which will list the current G:Lines
+       Syntax: /Stats G
+
+       *** TEChat Command Help ***
+       This command sends to all TechAdmins online
+       Only for Net/Techadmins. This is a ChatOps style command
+       Syntax: /TEChat :<text>
+       Example: /TEChat :Hey guys!
+
+       *** CHGHOST Command help ***
+       This command makes you able to change other people's virtual hostname
+       - IRCop only.
+       Syntax: /CHGHOST <nick> <newhost>
+       
+       *** TSCTL Command Help ***");
+       This is a highly advanced command");
+       Syntax:");
+        /TSCTL OFFSET +|- <time> - Adjust internal IRC clock");
+        /TSCTL TIME - Will give TS report");
+
+       *** SAJOIN Command help **");
+       Makes <nick> join channel <channel>");
+       Services Admin only..");
+       Syntax: /SAJOIN nick channel");
+
+
+       *** RemGline Command Help
+       This command can remove G:Lines
+       
+       Syntax:
+       /RemGline <user@host mask>
+       
+       Example:
+       /RemGline *@*.flirt.org
+       *** G:line command Help ***
+       This command provides timed G:Lines. If you match
+       a G:Line you cannot connect to ANY server at the
+       IRC network
+       Syntax:
+       /GLINE <user@host mask> <seconds to be banned> :<reason>
+       Example:
+       /GLINE *@*.dal.net 900 :Spammers
+       this will ban all users matching *@*.dal.net for 15 minutes
+       with reason 'Spammers'
+
+       *** MkPasswd Command help ***
+       This command will encrypt the string it has been given
+       So u can add it directly to the ircd.conf if you use
+       Encrypted passwords. /MKPassWd is disabled in UnrealIRCd/32
+       Syntax : /MkPasswd :string to be encrypted
+   
+       *** SNOTE Command Help ***
+       This will store the parameter of the command to a file
+       Which then can be read by using /SNOTES LIST
+       Syntax:  /SNOTE :<message>
+       
+       *** SNOTES Command Help ***
+       This command is made to view notes
+       Written to the SNOTE file by using /SNOTE
+       Syntax: /SNOTES LIST
+      or /SNOTES <number>
+
+       *** ADDLINE Command Help ***
+       This command can be used to add lines to the ircd.conf file
+       Only for Server Admins
+       Syntax: /AddLine :<line>
+
+       *** LAG Command Help ***
+       This command is like a sonar/traceroute for IRC servers
+       You type in /lag server1.irc.net and it will
+       reply from every server it passes with time and so on
+       Useful for looking where lag is and optional TS future/past travels
+       Syntax: /LAG <servername>
+
+       **** RPING Command help ***     
+        This will calculate the milliseconds (lag) between servers
+       
+        Syntax: /RPING <servermask>
+
+ 4) *** UnrealIRCd Usermodes ***
+               o = Global IRCop
+               O = Local IRCop
+               i = Invisible (Not shown in /who searches)
+               w = Can listen to wallop messages
+               g = Can read & send to globops, and locops
+               h = Available for help
+               s = Can listen to server notices
+               k = See's all the /KILL's which were executed
+               S = For services only. (Protects them)
+               a = Is a services admin
+               A = Is a server admin
+               N = Is a network admin
+               T = Is a tech admin
+               C = Is a co admin
+               c = See's all connects/disconnects on local server
+               f = Listen to flood alerts from server
+               r = Identifies the nick as being registered
+               x = Gives the user hidden hostname
+               e = Can listen to server messages sent to +e users
+               b = Can read & send to chatops
+               W = (IRCops only) Lets you see when people does a /whois on you
+               q = (Services Admins only) Gets you unable to be
+                    kicked unless by U:Lines
+               B = (users) Marks you being a Bot
+               F = (net|tech admin only) Lets you see far client connect/disconnects
+               I = (net|tech admin only) Invisible Join/Part. Makes you
+                    being hidden at channels
+               1 = (IRCops only) Marks you a Coder 
+5) *** UnrealIRCd Channel Modes ***
+           p = Private channel
+           s = Secret channel
+           i = Invite-only allowed
+           m = Moderated channel, noone can speak except users with mode +voh
+           n = No messages from outside channel
+           t = Only channel operators may set the topic
+           r = Channel is registered
+           R = Requires a registered nickname to join the channel
+           x = No ANSI color can be sent to the channel
+           q = Channel owner (The big cheese)
+           Q = No kicks able in channel unless by U:Lines
+           O = IRCop only channel (setable by Opers)
+           A = Server Admin | Network Admin | Tech Admin only channel (same as above)
+           K = /Knock is not allowed
+           I = /Invite is not allowed
+           S = Strip all incoming colours away
+           l <number of max users> = Channel may hold at most <number> of users
+           b <nick!user@host>      = Bans the nick!user@host from the channel
+           k <key>                 = Needs the channel key to join the channel
+           o <nickname>            = Gives operator status to the user
+           v <nickname>            = Gives voice to the user (May talk if chan is +m)
+           a <nickname>            = Gives protection to the user (No kick/drop)
+           e <exception ban>       = Exception ban - If someone matches it
+                                         they can join even if some else ban matches!
+           h <nickname>            = Gives halfop status to the user       
+           L <chan2>               = If channel is full (+l) the next user
+                                       will autojoin <chan2>
+           You can get additional explanation on modes:
+                Q h
+           With /HELPOP mode-<x> where <x> is Q f.x. like mode-Q
+
+       *** Channel mode +Q ***
+               This is the 'peace' mode. Noone can kick eachother
+               except by U:Lines. Bans can be placed thou.
+
+       *** Channel halfops (+h) *** 
+               If you are marked as halfop (% in /names) you can do:
+                - Set topic
+                - Kick non-ops
+                - Set modes +vmntibe
+
+6) *** UnrealIRCd O:Line flags ***
+               r = Access to /rehash server
+               R = Access to /restart server
+               D = Access to /die server
+               h = Oper can send /help ops - gets +h on oper up
+               g = Oper can send /globops
+               w = Oper can send /wallops
+               l = Oper can send /locops
+               c = Access to do local /squits and /connects
+               Y = Access to do remote /squits and /connects
+               k = Access to do local /kills
+               K = Access to do global /kills
+               b = Oper can /kline users from server
+               B = Oper can /unkline users from server
+               n = Oper can send local server notices(/notice $servername message)
+               N = Oper can send global notices(/notice $*.network.net message)
+               u = Oper can set /umode +c
+               f = Oper can set /umode +f
+               o = Local oper, flags included: rhgwlckbBnuf
+               O = Global oper, flags included: oRDCKN
+               A = Gets +A on oper up. Is server admin
+               a = Gets +a on oper up. Is services admin
+               N = Gets +N on oper up. Is network admin
+               T = Gets +T on oper up. Is tech admin
+               C = Gets +C on oper up. Is co admin
+               z = Can add /zlines
+               H = Gets +x on oper up.
+               W = Gets +W on oper up.   
+                ^ = Allows to use umode +I
+
+7) Last word
+
+This documentation is based off src/help.c in Unreal2.1.7
+For version Unreal2.1.7 - $Date$ 
+Made by Carsten Munk 1999 (Stskeeps)
\ No newline at end of file
diff --git a/dynconf b/dynconf
new file mode 100644 (file)
index 0000000..42ce7bf
--- /dev/null
+++ b/dynconf
@@ -0,0 +1,21 @@
+                    [ $Id$ ]
+             Dynamic Configuration Guide
+
+Okay first you have to go edit the file "unrealircd.conf" in 
+the directory "networks/". In that file you see a field with
+name "Include" .. if you want to create your own network file
+(IRC network specification) you have to write like 
+"networks/<irc network>.network" like "networks/myircnetwork.network"
+
+If there is already a network file you can just put in the path
+like : "networks/dragonwings.org"
+
+If you want to create your own network file 
+copy the file "template.network" to the name you want to use for 
+your network file and edit it.
+
+If you experince any problems email me at stskeeps@tspre.org
+or try msg me at /server irc.global-irc.net : #UnrealIRCd
+My nick is mostly Stskeeps or Techie (or Nightwalker if i had a bad night:P)
+
+--Stskeeps
diff --git a/extras/extras.txt b/extras/extras.txt
new file mode 100644 (file)
index 0000000..90a1d60
--- /dev/null
@@ -0,0 +1 @@
+...
\ No newline at end of file
diff --git a/extras/tsp/Makefile b/extras/tsp/Makefile
new file mode 100644 (file)
index 0000000..030582a
--- /dev/null
@@ -0,0 +1,12 @@
+all: client server
+
+client:
+       gcc -o tsp-client tsp-client.c sscript.c
+
+server:
+       gcc -o tsp-server-run tsp-server-run.c
+       gcc -o tsp-skin socker.c
+
+clean:
+       rm -f *~
+       rm -f tsp-server-run tsp-client tsp-skin
\ No newline at end of file
diff --git a/extras/tsp/README b/extras/tsp/README
new file mode 100644 (file)
index 0000000..4db1390
--- /dev/null
@@ -0,0 +1,26 @@
+
+how to use tsp-client:
+
+first make it "make"
+
+then run it like this:
+$ ./tsp-client <tsp server> <port>
+
+do this a couple of times
+if the answers come within 1 second count its right
+then take the most common time difference count and do in UnrealIRCd like
+this:
+
+/quote tsctl offset + <difference count>
+
+then your server is time synched
+
+current tsp servers online:
+
+server           port
+-----------------------------
+irc.flirt.org    6100
+
+
+if you want to make your own TSP server (must be a box using NTP)
+run ./tsp-server, it will then start running on port 6100
\ No newline at end of file
diff --git a/extras/tsp/README.sscript b/extras/tsp/README.sscript
new file mode 100644 (file)
index 0000000..c23556b
--- /dev/null
@@ -0,0 +1,40 @@
+
+
+                    Socket Script C library
+                    -----------------------
+
+Home page:
+http://www.linsupport.com
+
+This is a simple library that provides usefull functions for C 
+networking applications. It's based on the Socket Script scripting
+language, but meant for C programmers. These functions are really
+shortcuts to C functions, meant to make their use simple.
+
+This can create a static lib: libsscript.a
+
+To compile:
+
+make
+
+Then to install it:
+
+make install
+
+
+(C) Copyright 1998-2000 Patrick Lambert <drow@post.com>
+
+This library is under the LGPL license which means:
+
+1- You can copy and use this program freely.
+
+2- You may not claim that you wrote it.
+
+3- If you want to include parts of this software in your own product,
+you can do so if that product stays under free software and if all
+copyright notices in source and documentation, as well as the no warranty
+comment, remains.
+
+4- This program is distributed without ANY WARRANTY, without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE.
diff --git a/extras/tsp/socker.c b/extras/tsp/socker.c
new file mode 100644 (file)
index 0000000..c62ecc2
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+       SOCKER Socket redirector  version 0.1
+       Patrick Doyle  Oct 1998
+       Based on tserver by Michael Johnson and Erik Troan
+
+       Puts a normal stdin & stdout based program up on a port
+       as a server process.  Each connection spawns a new copy
+       of the program.
+
+       Please notify me of any changes to this code tha you
+       subsequently redistribute.  I can be contacted at
+       patrick@minotaursoftware.com.
+
+       Also, please leave my name and those of Michael Johnson
+       and Erik Troan at the top of this file.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define ZOMBIE  /* Causes zombies to be collected.  Only works under Linux. */
+
+#define debug printf
+#undef debug
+void debug(char *format, ...){}
+
+int sock = -1;
+
+void die(char *msg){
+       perror(msg);
+       exit(1);
+}
+
+void handle_sig(int signum){
+       if(signum == SIGCHLD){
+               /* Collect exit statuses.  Prevent zombies. */
+               int status;
+               while(0 < waitpid(-1, &status, WNOHANG));
+       }else{
+               fprintf(stderr, "\nSocker exiting normally.\n");
+               close(sock);
+               exit(0);
+       }
+}
+
+#define asizeof(x) (sizeof(x)/sizeof(x[0]))
+
+void setup_sig_handler(){
+       int sa_num;
+       static int sigs[] = {
+               SIGHUP, SIGINT, SIGQUIT, SIGXCPU, SIGXFSZ, SIGTERM
+#      ifdef ZOMBIE
+               , SIGCHLD
+#      endif
+       };
+       static struct sigaction sig_actions[asizeof(sigs)];
+       debug("Starting setup_sig_handler\n");
+       memset(sig_actions, 0, sizeof(sig_actions));
+       sig_actions[0].sa_handler = handle_sig;
+       sigemptyset(&(sig_actions[0].sa_mask));
+       for(sa_num=1; sa_num < asizeof(sigs); sa_num++){
+               memcpy(sig_actions+sa_num, sig_actions, sizeof(sig_actions[0]));
+       }
+       for(sa_num=0; sa_num < asizeof(sigs); sa_num++){
+               if(sigaction(sigs[sa_num],  sig_actions+sa_num, NULL))
+                       die("sigaction");
+       }
+#      ifdef ZOMBIE
+       siginterrupt(SIGCHLD, 0); /* Don't let SIGCHLD interrupt socket calls */
+#      endif
+       debug("Ending setup_sig_handler\n");
+}
+
+int main(int argc, char *argv[]) {
+       struct sockaddr_in address;
+       int conn, i, portnum;
+       size_t addrLength = sizeof(struct sockaddr_in);
+
+       fprintf(stderr, "SOCKER  Socket Redirector  Patrick Doyle  Oct 1998\n");
+
+       if (argc < 3 || !(portnum = atoi(argv[1]))){
+               fprintf(stderr, "Usage: socker {port_num} {command}\n");
+               fprintf(stderr, "Waits for TCP connections on the given port, and then\n");
+               fprintf(stderr, "spawns a new process executing {command} for each connection.\n");
+               fprintf(stderr, "Exit status: 0=caught signal and exited; 1=error\n");
+               exit(1);
+       }
+
+       if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+               die("socket");
+
+       debug("Calling setup_sig_handler\n");
+       setup_sig_handler();
+
+       /* Let the kernel reuse the socket address. This lets us run
+          twice in a row, without waiting for the (ip, port) tuple
+          to time out. */
+       i = 1;
+       setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&i, i); 
+
+       address.sin_family = AF_INET;
+       address.sin_port = htons(portnum);
+       memset(&address.sin_addr, 0, sizeof(address.sin_addr));
+
+       if (bind(sock, (struct sockaddr *) &address, sizeof(address)))
+               die("bind");
+
+       if (listen(sock, 5))
+               die("listen");
+
+       while ((conn = accept(sock, (struct sockaddr *) &address, &addrLength)) >= 0) {
+               if(fork()){ /* Parent; loop back to accept another */
+                       close(conn);
+               }else{ /* Child; exec given command line */
+                       close(sock);
+                       /* Redirect stdin & stdout to socket */
+                       if(0 != dup2(conn, 0) || 1 != dup2(conn, 1))
+                               die("dup2 redirection");
+                       /* Turn off buffering */
+                       /* Note: this seems to have no effect beyond execvp */
+                       setbuf(stdin, 0);
+                       setbuf(stdout, 0);
+                       setbuf(stderr, 0);
+                       /* Execute command */
+                       execvp(argv[2], argv+2);
+                       /* Error if we get here */
+                       fprintf(stderr, "execvp failed.  Please make sure that '%s' refers to a valid program.\n", argv[2]);
+                       _exit(1)/*
+                               man fork says _exit should be called to prevent parent from
+                               being corrupted.
+                       */;
+               }
+       }
+
+       if (conn < 0) 
+               die("accept");
+       
+       /* Shouldn't get here */
+       close(sock);
+       return 2;
+}
diff --git a/extras/tsp/sscript-lib.doc b/extras/tsp/sscript-lib.doc
new file mode 100644 (file)
index 0000000..6b2a46c
--- /dev/null
@@ -0,0 +1,115 @@
+Socket Script Library 2.0
+-------------------------
+
+Here are the functions and errno code numbers returned by some of SScript's
+functions:
+
+errno:
+SSCRIPT_SOCKET_FAILED             10
+SSCRIPT_BIND_FAILED               11
+SSCRIPT_GETSOCKETNAME_FAILED      12
+SSCRIPT_FLAGS_FAILED              13
+SSCRIPT_CONNECT_FAILED            20
+SSCRIPT_UDPSEND_FAILED            31
+SSCRIPT_UDPRECEIVE_FAILED         32
+SSCRIPT_READ_FAILED               33
+
+The following are the SScript functions available in this library.
+They return either a string, an int or void. If an error occurs, it returns
+NULL (in case of a string) or -1 (in case of an int) and sets errno to
+the right error code (see above). Note that since each connection is
+associated with a socket number (sockfd), it is possible to make
+multiple connections.
+
+- char *sscript_lindex(char *input_string, int word_number);
+Get <word_number> from <input_string>. Returns the requested word.
+
+- char *sscript_lrange(char *input_string, int starting_at);
+Return everything after <starting_at> in <input_string>.
+
+- int sscript_connect(char *server, int port, char *virtual);
+Connect to <server> at port <port>, binding to virtual address
+<virtual>. If no binding is required, use NULL. Returns the socket
+number.
+
+- int sscript_server(int port);
+Initialize a server socket. Returns the socket number.
+
+- int sscript_wait_clients(int sockfd, int port, int forking);
+Listen to port <port> and wait for clients. This function is a
+blocking function. It will stay there untill it gets a client, and when
+it does, it will create a child and return its associated socket number.
+The child will go in the background if <forking> is set to 1
+(required for multithreading). This returns the child' sockfd.
+
+- char *sscript_get_remote_ip();
+This function returns the IP that connected to a server-oriented program.
+
+- void sscript_disconnect(int sockfd);
+Diconnects the connection pointed by <sockfd>.
+
+- void sscript_dump(int sockfd, char *filename);
+Dumps the content of <filename> to the connection pointed by <sockfd>.
+
+- void sscript_ping(char *hostname);
+Sends a TCP ping (echo to port 7) to <hostname>. This is a blocking
+function and only returns if the ping worked.
+
+- int sscript_test(char *hostname, int port);
+This tests if port <port> from <hostname> is open. Returns 0 if it is.
+
+- char *sscript_version();
+Returns the current library version.
+
+- char *sscript_read(int sockfd, int chop);
+Read from the connection pointed by <sockfd> and clear the last
+char if <chop> is set to 1.
+
+- void sscript_write(int sockfd, char *string);
+Write <string> to the connection pointed by <sockfd>.
+
+- int sscript_udp_send(char *hostname, int port, char *msg);
+Send an UDP packet to <hostname> at port <port> containing the message <msg>
+
+- char *sscript_udp_listen(int port);
+Listen for UDP packets on port <port>. Available to root only.
+
+- char *sscript_icmp_detect();
+Listen for ICMP messages and return the type (see ICMP.types) and the IP
+that sent one. Available to root only.
+
+- char *sscript_resolve_host(char *hostname);
+Resolve <hostname> into an IP.
+
+- char *sscript_resolve_ip(char *ip);
+Resolve <ip> into an hostname.
+
+- char *sscript_get_localhost();
+Get the local hostname.
+
+- void sscript_binary_send(int sockfd, char *filename);
+This function sends a binary file.
+
+- void sscript_binary_get(int sockfd);
+This function receives a binary file.
+
+- char *sscript_login_to_passwd(char *login)
+This function converts a login name to its crypted password.
+
+- char *sscript_uid_to_login(long uid)
+This function finds the login name for the UID provided.
+
+- int sscript_sokstat(char *option, int sockfd)
+This will give the settings for the currently open socket sockfd. Option
+is what you want the setting of and can be sendbuf, recvbuf, error or type.
+
+- char *sscript_time_read(int sockfd, int time);
+This function reads from sockfd for time secs, and then returns what it
+read, or "timeout".
+
+- void sscript_redir(int sockfd1, int sockfd2);
+This function will redirect packets from sockfd1 to sockfd2, and the
+other way around.
+
+- void sscript_nodelay(int sockfd);
+Set the socket in non-blocking mode.
diff --git a/extras/tsp/sscript.c b/extras/tsp/sscript.c
new file mode 100644 (file)
index 0000000..d28ca8a
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+* SScript - See the sscript.doc
+* (C) 1998 Drow <drow@wildstar.net>
+* http://devplanet.fastethernet.net
+*/
+
+#include "sscript.h"
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#ifndef FNDELAY
+#define FNDELAY O_NONBLOCK
+#endif
+#ifdef POSIX
+#include <pwd.h>
+#include <sys/utsname.h>
+#endif
+
+char global_var[9][1024]; /* need to find why gcc outputs warns without this */
+char remoteIP[30];
+
+char *sscript_lindex(char *input_string, int word_number)
+{
+ char *tokens[1024];
+ static char tmpstring[1024];
+ int i;
+ strncpy(tmpstring,input_string,1024);
+ (char *)tokens[i=0] = (char *)strtok(tmpstring, " ");
+ while (((char *)tokens[++i] = (char *)strtok(NULL, " ")));
+ tokens[i] = NULL;
+ return(tokens[word_number]);
+}
+
+int sscript_connect(char *server, int port, char *virtual)
+{
+ struct sockaddr_in address;
+ struct sockaddr_in la;
+ int len, sockfd;
+ sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if(sockfd<1) 
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return -1;
+ }
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = inet_addr(server);
+ address.sin_port = htons(port);
+ len = sizeof(address);
+ if(virtual!=NULL)
+ {
+  la.sin_family = AF_INET;
+  la.sin_addr.s_addr = inet_addr(virtual);
+  la.sin_port = 0;
+  bind(sockfd, (struct sockaddr *)&la, sizeof(la));
+ }
+ if(connect(sockfd, (struct sockaddr *)&address, len)<0)
+ {
+  errno = SSCRIPT_CONNECT_FAILED;
+  return -1;
+ }
+ return sockfd;
+}
+
+int sscript_server(int port)
+{
+ int sockfd2, listen_len;
+ struct sockaddr_in listen_addr;
+ sockfd2 = socket(AF_INET, SOCK_STREAM, 0);
+ if(sockfd2<1)
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return -1;
+ }
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ listen_addr.sin_port = htons(port);
+ listen_len = sizeof(listen_addr); 
+ if(bind(sockfd2, (struct sockaddr *)&listen_addr, listen_len))
+ {
+  errno = SSCRIPT_BIND_FAILED;
+  return -1;
+ }
+ return sockfd2;
+}
+
+int sscript_wait_clients(int sockfd2, int port, int forking)
+{
+ int sockfd=(int)NULL,len,from_len,pid;
+ struct sockaddr_in address;
+ struct sockaddr_in from_addr;
+ struct sockaddr_in listen_addr;
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ listen_addr.sin_port = htons(port);
+ len = sizeof(address);
+ listen(sockfd2, 5);
+ for(;;)
+ {
+  if(forking) if(sockfd!=(int)NULL) close(sockfd);
+  sockfd = accept(sockfd2, (struct sockaddr *)&address, &len);
+  if(forking) if((pid=fork())) break;
+ }
+ from_len=sizeof(from_addr);
+ memset(&from_addr, 0, sizeof(from_addr));
+ if(getpeername(sockfd, (struct sockaddr *)&from_addr,&from_len) < 0)
+ {
+  strcpy(remoteIP,"unknown");
+ }
+ else
+ {
+  strcpy(remoteIP,inet_ntoa(from_addr.sin_addr));
+ }
+ return sockfd;
+}
+
+char *sscript_get_remote_ip()
+{
+ return remoteIP;
+}
+
+void sscript_disconnect(int sockfd)
+{
+ shutdown(sockfd,2);
+ close(sockfd);
+}
+
+void sscript_dump(int sockfd, char *filename)
+{
+ char temp[1024]="";
+ FILE *fpa;
+ fpa=fopen(filename,"r");
+ if(fpa==NULL) return;
+ while(fgets(temp,1024,fpa)!=NULL)
+  write(sockfd, temp, strlen(temp));
+ fclose(fpa);
+}
+
+void sscript_ping(char *hostname)
+{
+ struct sockaddr_in other_addr;
+ int sockfd, result;
+ char temp[255];
+ sockfd=socket(AF_INET, SOCK_STREAM, 0);
+ if(sockfd<0)
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return;
+ }
+ other_addr.sin_family = AF_INET;
+ other_addr.sin_addr.s_addr = inet_addr(hostname);
+ other_addr.sin_port = htons(7);
+ connect(sockfd, (struct sockaddr*) &other_addr,sizeof(other_addr));
+ result=write(sockfd,"ping\n",strlen("ping\n"));
+ result=read(sockfd,temp,result);
+ close(sockfd);
+}
+
+int sscript_test(char *hostname, int port)
+{
+ int sockfd;
+ struct sockaddr_in other_addr;
+ if((sockfd=socket(AF_INET, SOCK_STREAM, 0))<0)
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return -1;
+ }
+ other_addr.sin_family = AF_INET;
+ other_addr.sin_addr.s_addr = inet_addr(hostname);
+ other_addr.sin_port = htons(port);
+ if(connect(sockfd, (struct sockaddr*)&other_addr,sizeof(other_addr))==-1)
+ {
+  errno = SSCRIPT_CONNECT_FAILED;
+  close(sockfd);
+  return -1;
+ }
+ close(sockfd);
+ return 0;
+}
+
+char *sscript_version()
+{
+ return ABOUT;
+}
+
+char *sscript_read(int sockfd, int chop)
+{
+ int i, result;
+ char inchar;
+ char string[1024];
+ bzero(string,1024);
+ strcpy(string,"");
+ for(i=0;(result=read(sockfd,&inchar,1))!='\0';i++)
+ {
+  string[i]=inchar;
+  if(inchar=='\n') break;
+ }
+ if (chop) string[i-1]=' ';
+ strcpy(global_var[0],string);
+ return global_var[0];
+}
+
+void sscript_write(int sockfd, char *string)
+{
+ write(sockfd, string, strlen(string));
+}
+
+int sscript_compare(char *case1, char *case2)
+{
+ return (strcmp(case1,case2));
+}
+
+char *sscript_lrange(char *input_string, int starting_at)
+{
+ char *tokens[555];
+ static char tmpstring[512]="";
+ int i;
+ char out_string[512]="";
+ strcpy(out_string,"");
+ if(input_string==NULL) {
+  strcpy(out_string," ");
+  strcat(out_string,NULL);
+  strcpy(global_var[1],out_string);
+  return global_var[1]; }
+ strcpy(tmpstring,input_string);
+ (char *)tokens[i=0] = (char *)strtok(tmpstring, " ");
+ while(((char *)tokens[++i] = (char *)strtok(NULL, " ")));
+ tokens[i] = NULL;
+ i++;
+ if(i<starting_at) return (int)NULL;
+ while(tokens[starting_at] != NULL)
+ {
+  strcat(out_string,tokens[starting_at]);
+  strcat(out_string, " ");
+  starting_at++;
+ }
+ strcpy(global_var[2],out_string);
+ return global_var[2];
+}
+
+int sscript_udp_send(char *hostname, int port, char *msg)
+{
+ int udpsock;
+ struct sockaddr_in udpaddr;
+ udpsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if(udpsock<0)
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return -1;
+ }
+ udpaddr.sin_family = AF_INET;
+ udpaddr.sin_port = htons(port);
+ udpaddr.sin_addr.s_addr = inet_addr(hostname);
+ if(sendto(udpsock,msg,sizeof(msg),0,(struct sockaddr *)&udpaddr,sizeof(udpaddr))<0)
+ {
+  errno = SSCRIPT_UDPSEND_FAILED;
+  return -1;
+ }
+ return 0;
+}
+
+char *sscript_udp_listen(int port)
+{
+ int udpsock,len;
+ struct sockaddr_in udpaddr, from;
+ char msg[255];
+ udpsock = socket(AF_INET, SOCK_DGRAM, 0);
+ if(udpsock<0)
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return (char *)NULL;
+ }
+ udpaddr.sin_family = AF_INET;
+ udpaddr.sin_addr.s_addr = INADDR_ANY;
+ udpaddr.sin_port = htons(port);
+ if(bind(udpsock,(struct sockaddr *)&udpaddr,sizeof(udpaddr))<0)
+ {
+  errno = SSCRIPT_BIND_FAILED;
+  close(udpsock);
+  return (char *)NULL;
+ }
+ len = sizeof(from);
+ if(recvfrom(udpsock,msg,sizeof(msg),0,(struct sockaddr *)&from,&len)<0)
+ {
+  errno = SSCRIPT_UDPRECEIVE_FAILED;
+  close(udpsock);
+  return (char *)NULL;
+ }
+ close(udpsock);
+ strcpy(global_var[3],msg);
+ return global_var[3];
+}
+
+char *sscript_icmp_detect()
+{
+ int icmpsock,len,result,type;
+ struct sockaddr_in icmpaddr;
+ char readbuf[1024]="";
+ char msg[255];
+ if((icmpsock=socket(AF_INET, SOCK_RAW, IPPROTO_ICMP))<0)
+ {
+  errno = SSCRIPT_SOCKET_FAILED;
+  return (char *)NULL;
+ }
+ icmpaddr.sin_family = AF_INET;
+ icmpaddr.sin_addr.s_addr = INADDR_ANY;
+ icmpaddr.sin_port = 0;
+ if(bind(icmpsock,(struct sockaddr *)&icmpaddr,sizeof(icmpaddr))<0)
+ {
+  errno = SSCRIPT_BIND_FAILED;
+  close(icmpsock);
+  return (char *)NULL;
+ }
+ len=sizeof(icmpaddr);
+ if(getsockname(icmpsock,(struct sockaddr *)&icmpaddr,&len)<0)
+ {
+  errno = SSCRIPT_GETSOCKETNAME_FAILED;
+  close(icmpsock);
+  return (char *)NULL;
+ }
+ if((result=read(icmpsock,readbuf,sizeof(readbuf)))<0)
+ {
+  errno = SSCRIPT_READ_FAILED;
+  close(icmpsock);
+  return (char *)NULL;
+ }
+ type=readbuf[20] & 0xff;
+ sprintf(msg,"%d %d.%d.%d.%d ",type,readbuf[12]&0xff,readbuf[13]&0xff,readbuf[14]&0xff,readbuf[15]&0xff);
+ close(icmpsock);
+ strcpy(global_var[4],msg);
+ return global_var[4];
+}
+
+char *sscript_resolve_host(char *hostname)
+{
+ struct hostent *hp;
+ struct sockaddr_in from;
+ char result[255];
+ memset(&from, 0, sizeof(struct sockaddr_in));
+ from.sin_family = AF_INET;
+ hp=gethostbyname(hostname);
+ if(hp==NULL) strcpy(result,"unknown");
+ else
+ {
+  memcpy(&from.sin_addr,hp->h_addr,hp->h_length);
+  strcpy(result,inet_ntoa(from.sin_addr));
+ }
+ strcpy(global_var[5],result);
+ return global_var[5];
+}
+
+char *sscript_resolve_ip(char *ip)
+{
+ struct hostent *hp;
+ struct sockaddr_in from;
+ char result[255];
+ from.sin_family = AF_INET;
+ from.sin_addr.s_addr = inet_addr(ip);
+ hp=gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr),from.sin_family);
+ if(hp==NULL) strcpy(result,"unknown");
+ else strcpy(result,(char *)hp->h_name);;
+ strcpy(global_var[6],result);
+ return global_var[6];
+}
+
+char *sscript_get_localhost()
+{
+ char result[255];
+ gethostname(result,sizeof(result));
+ strcpy(global_var[7],result);
+ return global_var[7];
+}
+
+void sscript_binary_send(int sockfd, char *string)
+{
+ char temp4[255], temp2[255];
+ int cnt;
+ FILE *fpa;
+ sprintf(temp4,"uuencode %s %s > %s/.temp.uue 2>/dev/null",string,string,TMP_DIR);
+ system(temp4);
+ sprintf(temp2,"%s/.temp.uue",TMP_DIR);
+ fpa=fopen(temp2,"r");
+ if(fpa==NULL || fileno(fpa)<0) return;
+ else {
+  while((cnt = read(fileno(fpa), temp4, 250))>0)
+  write(sockfd, temp4, cnt);
+  if(fpa!=NULL) fclose(fpa);
+  sprintf(temp4,"rm -f %s/.temp.uue",TMP_DIR);
+  system(temp4);
+ }
+}
+
+void sscript_binary_get(int sockfd)
+{
+ char temp2[255], temp4[255], inchar, inall[1024];
+ FILE *fpa;
+ int i;
+ sprintf(temp2,"%s/.temp.uue",TMP_DIR);
+ fpa=fopen(temp2,"w");
+ if(fpa==NULL || fileno(fpa)<0) return;
+ while(strcasecmp(inall,"end\n"))
+ {
+  bzero(inall, 1024);
+  for(i=0;read(sockfd,&inchar,1)!='\0';i++)
+  {
+   inall[i]=inchar;
+   if(inchar=='\n') break;
+  }
+  fputs(inall,fpa);
+ }
+ if(fpa!=NULL) fclose(fpa);
+ sprintf(temp4,"uudecode %s/.temp.uue",TMP_DIR);
+ system(temp4);
+ sprintf(temp4,"rm -f %s/.temp.uue",TMP_DIR);
+ system(temp4);
+}
+
+char *sscript_login_to_passwd(char *login)
+{
+#ifdef POSIX
+ struct passwd *pw;
+ pw = getpwnam(login);
+ if(pw!=NULL) return pw->pw_passwd;
+#endif
+ return (char *)NULL;
+}
+
+char *sscript_uid_to_login(long my_uid)
+{ 
+#ifdef POSIX
+ struct passwd *pw;
+ pw = getpwuid(my_uid);
+ if(pw!=NULL) return pw->pw_name;
+#endif
+ return (char *)NULL;
+}
+
+int sscript_sokstat(char *option, int sockfd)
+{  
+ int optlen=sizeof(int),optval=1;
+ if(!strcasecmp(option,"sendbuf")) getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&optval, &optlen);
+ else if(!strcasecmp(option,"recvbuf")) getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&optval, &optlen);
+ else if(!strcasecmp(option,"error")) getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen);
+ else if(!strcasecmp(option,"type")) getsockopt(sockfd, SOL_SOCKET, SO_TYPE, (char *)&optval, &optlen);
+ else optval=-1;
+ return optval;
+}
+
+char *sscript_time_read(int sockfd, int time_sec)
+{
+ struct timeval timeout;
+ int max_fd;
+ fd_set readfs, newfs;
+ timeout.tv_sec=time_sec;
+ timeout.tv_usec=0;
+ FD_ZERO(&readfs);
+ FD_SET(sockfd, &readfs);
+ max_fd = sockfd;
+ memcpy(&newfs, &readfs, sizeof(readfs));
+ select(max_fd+1, &newfs, NULL, NULL, &timeout);
+ if(FD_ISSET (sockfd, &newfs))
+ {
+  read(sockfd, global_var[8], sizeof(global_var[8]));
+  return(global_var[8]); 
+ }
+ return("timeout");
+}
+
+void sscript_redir(int sockfd, int rsck)
+{
+ char buf[4096];
+ fd_set readfs, newfs;
+ int max_fd, len;
+ FD_ZERO(&readfs);
+ FD_SET(sockfd, &readfs);
+ FD_SET(rsck, &readfs);
+ if(sockfd>rsck) max_fd = sockfd;
+ else max_fd = rsck;
+ while(1) {
+  memcpy(&newfs, &readfs, sizeof(readfs));
+  select(max_fd+1, &newfs, NULL, NULL, NULL);
+  if(FD_ISSET(sockfd, &newfs))
+  {
+   if((len=read(sockfd, buf, sizeof(buf)))<1) break;
+   if(write(rsck, buf, len)!=len) break;
+  }
+  if(FD_ISSET(rsck, &newfs))
+  {
+   if((len=read(rsck, buf, sizeof(buf)))<1) break;
+   if(write(sockfd, buf, len)!=len) break;
+  }
+ }
+}
+
+void sscript_nodelay(int sockfd)
+{
+ int i;
+ if(( i = fcntl(sockfd, F_GETFL, 0)) == -1);
+ else if (fcntl(sockfd, F_SETFL, i | FNDELAY) == -1);
+}
+
diff --git a/extras/tsp/sscript.h b/extras/tsp/sscript.h
new file mode 100644 (file)
index 0000000..5d6ff23
--- /dev/null
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define SSCRIPT_SOCKET_FAILED             10
+#define SSCRIPT_BIND_FAILED               11
+#define SSCRIPT_GETSOCKETNAME_FAILED      12
+#define SSCRIPT_FLAGS_FAILED              13
+#define SSCRIPT_CONNECT_FAILED            20
+#define SSCRIPT_UDPSEND_FAILED            31
+#define SSCRIPT_UDPRECEIVE_FAILED         32
+#define SSCRIPT_READ_FAILED               33
+
+#define ABOUT "Socket Script library 2.0 by Patrick Lambert (drow@post.com)"
+#define POSIX
+#define TMP_DIR "."
+
+char *sscript_lindex(char *input_string, int word_number);
+int sscript_connect(char *server, int port, char *virtual);
+int sscript_server(int port);
+int sscript_wait_clients(int sockfd2, int port, int forking);
+char *sscript_get_remote_ip();
+void sscript_disconnect(int sockfd);
+void sscript_dump(int sockfd, char *filename);
+void sscript_ping(char *hostname);
+int sscript_test(char *hostname, int port);
+char *sscript_version();
+char *sscript_read(int sockfd, int chop);
+void sscript_write(int sockfd, char *string);
+int sscript_compare(char *case1, char *case2);
+char *sscript_lrange(char *input_string, int starting_at);
+int sscript_udp_send(char *hostname, int port, char *msg);
+char *sscript_udp_listen(int port);
+char *sscript_icmp_detect();
+char *sscript_resolve_host(char *hostname);
+char *sscript_resolve_ip(char *ip);
+char *sscript_get_localhost();
+void sscript_binary_send(int sockfd, char *string);
+void sscript_binary_get(int sockfd);
+char *sscript_login_to_passwd(char *login);
+char *sscript_uid_to_login(long my_uid);
+int sscript_sokstat(char *option, int sockfd);
+char *sscript_time_read(int sockfd, int time_sec);
+void sscript_redir(int sockfd, int rsck);
+void sscript_nodelay(int sockfd);
diff --git a/extras/tsp/tsp-client.c b/extras/tsp/tsp-client.c
new file mode 100644 (file)
index 0000000..89c9d44
--- /dev/null
@@ -0,0 +1,39 @@
+ /* compile with: gcc -lsscript -o example example.c */
+
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+main(int argc, char *argv[])
+{
+/* initializing variables */
+ char result[255]=".";
+ char *p;
+ int port = atoi(argv[2]);
+ int sockfd=0,i;
+time_t t,d;
+/* connect somewhere */
+ printf("Connecting to %s:%i .. \n", argv[1], port);
+/* call to sscript_connect to connect to the server */
+ sockfd=sscript_connect(sscript_resolve_host(argv[1]),port,NULL);
+
+/* if it returns -1, then print the error code */
+ if(sockfd<1)
+ {
+  printf("An error occured: %d\n",errno);
+  exit(1);
+ }
+
+/* call to sscript_read and copy the result in 'result' */
+ p = (char *)sscript_time_read(sockfd,5);
+  if (p)
+  {
+       strcpy(result,p);
+       t = atol(result);
+       d = t - time(NULL);
+       printf("TS difference from timeserver is %li (%li)\n", d, t);
+  }
+/* print the result */
+/* disconnects */
+ sscript_disconnect(sockfd);
+}
+
diff --git a/extras/tsp/tsp-server b/extras/tsp/tsp-server
new file mode 100755 (executable)
index 0000000..2dceb02
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/sh
+./tsp-skin 6100 ./tsp-server-run &
\ No newline at end of file
diff --git a/extras/tsp/tsp-server-run.c b/extras/tsp/tsp-server-run.c
new file mode 100644 (file)
index 0000000..604258a
--- /dev/null
@@ -0,0 +1,3 @@
+main() {
+       printf("%li", time(0));
+}
\ No newline at end of file
diff --git a/include/channel.h b/include/channel.h
new file mode 100644 (file)
index 0000000..4ed0aaa
--- /dev/null
@@ -0,0 +1,44 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/channel.h
+ *   Copyright (C) 1990 Jarkko Oikarinen
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+
+#ifndef        __channel_include__
+#define __channel_include__
+#define CREATE 1       /* whether a channel should be
+                          created or just tested for existance */
+
+#define        MODEBUFLEN      200
+
+#define NullChn        ((aChannel *)0)
+
+#define ChannelExists(n)       (find_channel(n, NullChn) != NullChn)
+
+#define IsULine(cptr,sptr)     (sptr->flags & FLAGS_ULINE)
+
+/* NOTE: Timestamps will be added to MODE-commands, so never make
+ * RESYNCMODES and MODEPARAMS higher than MAXPARA-3. DALnet servers
+ * before Dreamforge aren't safe with more than six. -Donwulff
+ */
+#include "msg.h"
+#define        MAXMODEPARAMS   (MAXPARA-2)     /* Maximum modes processed */
+#define RESYNCMODES    12              /* Max modes per MODE in resync */
+#define MODEPARAMS     6               /* Max modes from user */
+
+#endif
diff --git a/include/cio.h b/include/cio.h
new file mode 100644 (file)
index 0000000..342973b
--- /dev/null
@@ -0,0 +1,27 @@
+// $Id$
+#include <windows.h>
+
+
+#define CIOCLASS    "CioClass"
+
+#ifndef CIO
+#define CIO
+
+typedef struct tag_CioLine
+{
+       BYTE    *Data;
+       WORD    Len;
+       struct tag_CioLine      *Prev, *Next;
+} CioLine;
+
+typedef struct tag_CioWndInfo
+{
+       CioLine *FirstLine, *CurLine;
+       int     Lines, Scroll;
+       int     Width, Height, XChar, YChar, YJunk, ScrollMe;
+       HFONT   hFont;
+       BYTE    FR, FG, FB;
+} CioWndInfo;
+
+#endif
+
diff --git a/include/ciofunc.h b/include/ciofunc.h
new file mode 100644 (file)
index 0000000..c5274bf
--- /dev/null
@@ -0,0 +1,20 @@
+// $Id$
+#include "Cio.h"
+
+#define GWL_USER        0
+#define CIO_ADDSTRING   WM_USER
+#define CIO_CLEAR       WM_USER+1
+
+// Cio_Init.c
+BOOL Cio_Init(HINSTANCE hInstance);
+
+// Cio_Main.c
+LRESULT CALLBACK Cio_WndProc(HWND, UINT, WPARAM, LPARAM);
+HWND Cio_Create(HINSTANCE hInstance, HWND hParent, DWORD Style, int X, int Y, int W, int H);
+BOOL Cio_WndCreate(HWND hWnd);
+BOOL Cio_WndPaint(HWND hWnd);
+BOOL Cio_WndDestroy(HWND hWnd);
+BOOL Cio_WndAddString(HWND hWnd, int Len, char *Buffer);
+BOOL Cio_WndSize(HWND hWnd, LPARAM lParam);
+void Cio_Scroll(HWND hWnd, CioWndInfo *CWI, int Scroll);
+BOOL Cio_PrintF(HWND hWnd, char *InBuf, ...);
diff --git a/include/class.h b/include/class.h
new file mode 100644 (file)
index 0000000..7bcf966
--- /dev/null
@@ -0,0 +1,71 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/class.h
+ *   Copyright (C) 1990 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ *   $Id$
+ */
+
+#ifndef        __class_include__
+#define __class_include__
+
+#ifndef PROTO
+#if __STDC__
+#       define PROTO(x) x
+#else
+#       define PROTO(x) ()
+#endif
+#endif
+
+typedef struct Class {
+       int     class;
+       int     conFreq;
+       int     pingFreq;
+       int     maxLinks;
+       long    maxSendq;
+       int     links;
+       struct Class *next;
+} aClass;
+
+#define        Class(x)        ((x)->class)
+#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)    (Class(x)->links)
+#define        ConfMaxLinks(x) (Class(x)->maxLinks)
+#define        ConfClass(x)    (Class(x)->class)
+#define        ConfConFreq(x)  (Class(x)->conFreq)
+#define        ConfPingFreq(x) (Class(x)->pingFreq)
+#define        ConfSendq(x)    (Class(x)->maxSendq)
+
+#define        FirstClass()    classes
+#define        NextClass(x)    ((x)->next)
+
+extern aClass  *classes;
+
+extern aClass  *find_class PROTO((int));
+extern int     get_conf_class PROTO((aConfItem *));
+extern int     get_client_class PROTO((aClient *));
+extern int     get_client_ping PROTO((aClient *));
+extern int     get_con_freq PROTO((aClass *));
+extern void    add_class PROTO((int, int, int, int, long));
+extern void    check_class PROTO((void));
+extern void    initclass PROTO((void));
+
+#endif /* __class_include__ */
diff --git a/include/common.h b/include/common.h
new file mode 100644 (file)
index 0000000..559676a
--- /dev/null
@@ -0,0 +1,216 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/common.h
+ *   Copyright (C) 1990 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$
+ */
+
+#ifndef        __common_include__
+#define __common_include__
+
+#include <time.h>
+#ifdef _WIN32
+#include <malloc.h>
+#include <windows.h>
+#include <winsock.h>
+#include <process.h>
+#include <io.h>
+#include "struct.h"
+#endif
+#include "dynconf.h"
+
+#ifdef PARAMH
+#include <sys/param.h>
+#endif
+
+#ifndef PROTO
+#if __STDC__
+#      define PROTO(x) x
+#else
+#      define PROTO(x) ()
+#endif
+#endif
+
+#define ID_CVS(x) static char id_cvs[] = x
+#define ID_Copyright(x) static char id_copyright[] = x
+#define ID_Notes(x) static char id_notes[] = x
+
+#define BMAGIC 0x4675636B596F754661736369737473
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifdef TRUE
+#undef TRUE
+#endif
+
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#define FALSE (0)
+#define TRUE  (!FALSE)
+
+#ifndef UNSURE
+#define UNSURE (2)
+#endif
+
+#if 0
+#ifndef        MALLOCH
+char   *malloc(), *calloc();
+void   free();
+#else
+#include MALLOCH
+#endif
+#endif
+
+
+extern int     match PROTO((char *, char *));
+#define mycmp(a,b) \
+ ( (toupper((a)[0])!=toupper((b)[0])) || smycmp((a)+1,(b)+1) )
+extern  int     smycmp PROTO((char *, char *));
+#ifndef GLIBC2_x
+extern int     myncmp PROTO((char *, char *, int));
+#endif 
+
+#ifdef NEED_STRTOK
+extern char    *strtok2 PROTO((char *, char *));
+#endif
+#ifdef NEED_STRTOKEN
+extern char    *strtoken PROTO((char **, char *, char *));
+#endif
+#ifdef NEED_INET_ADDR
+extern unsigned long inet_addr PROTO((char *));
+#endif
+
+#if defined(NEED_INET_NTOA) || defined(NEED_INET_NETOF) && !defined(_WIN32)
+#include <netinet/in.h>
+#endif
+#ifdef NEED_INET_NTOA
+extern char *inet_ntoa PROTO((struct in_addr));
+#endif
+
+#ifdef NEED_INET_NETOF
+extern int inet_netof PROTO((struct in_addr));
+#endif
+
+int global_count, max_global_count;
+extern char *myctime PROTO((time_t));
+extern char *strtoken PROTO((char **, char *, char *));
+
+#define PRECISE_CHECK
+
+#ifndef MAX
+#define MAX(a, b)      ((a) > (b) ? (a) : (b))
+#endif
+#ifndef MIN
+#define MIN(a, b)      ((a) < (b) ? (a) : (b))
+#endif
+
+#define DupString(x,y) do{x=MyMalloc(strlen(y)+1);(void)strcpy(x,y);}while(0)
+
+#ifdef USE_CASETABLES
+extern int casetable;
+extern u_char *tolowertab, tolowertab1[], tolowertab2[];
+extern u_char *touppertab, touppertab1[], touppertab2[];
+#else
+extern u_char tolowertab[], touppertab[];
+#endif
+
+#undef tolower
+#define tolower(c) (tolowertab[(c)])
+
+#undef toupper
+#define toupper(c) (touppertab[(c)])
+
+#undef isalpha
+#undef isdigit
+#undef isxdigit
+#undef isalnum
+#undef isprint
+#undef isascii
+#undef isgraph
+#undef ispunct
+#undef islower
+#undef isupper
+#undef isspace
+#undef iscntrl
+
+extern unsigned char char_atribs[];
+
+#define PRINT 1
+#define CNTRL 2
+#define ALPHA 4
+#define PUNCT 8
+#define DIGIT 16
+#define SPACE 32
+#define ALLOW 64
+
+#ifndef KLINE_TEMP
+#define KLINE_PERM 0
+#define KLINE_TEMP 1
+#define KLINE_AKILL 2
+#define KLINE_EXCEPT 3
+#endif
+
+#define        iscntrl(c) (char_atribs[(u_char)(c)]&CNTRL)
+#define isallowed(c) (char_atribs[(u_char)(c)]&ALLOW)
+#define isalpha(c) (char_atribs[(u_char)(c)]&ALPHA)
+#define isspace(c) (char_atribs[(u_char)(c)]&SPACE)
+#define islower(c) ((char_atribs[(u_char)(c)]&ALPHA) && ((u_char)(c) > 0x5f))
+#define isupper(c) ((char_atribs[(u_char)(c)]&ALPHA) && ((u_char)(c) < 0x60))
+#define isdigit(c) (char_atribs[(u_char)(c)]&DIGIT)
+#define        isxdigit(c) (isdigit(c) || 'a' <= (c) && (c) <= 'f' || \
+                    'A' <= (c) && (c) <= 'F')
+#define isalnum(c) (char_atribs[(u_char)(c)]&(DIGIT|ALPHA))
+#define isprint(c) (char_atribs[(u_char)(c)]&PRINT)
+#define isascii(c) ((u_char)(c) >= 0 && (u_char)(c) <= 0x7f)
+#define isgraph(c) ((char_atribs[(u_char)(c)]&PRINT) && ((u_char)(c) != 0x32))
+#define ispunct(c) (!(char_atribs[(u_char)(c)]&(CNTRL|ALPHA|DIGIT)))
+
+extern char *MyMalloc();
+extern void flush_connections();
+extern struct SLink *find_user_link(/* struct SLink *, struct Client * */);
+
+/*
+ * Protocol support text.  DO NO CHANGE THIS unless you know what
+ * you are doing.
+ */
+#define PROTOCTL_CLIENT "TOKEN WATCH=128 SAFELIST HCN PREFIX=@+%"
+#define PROTOCTL_SERVER "NOQUIT TOKEN NICKv2 SJOIN SJOIN2"
+
+#ifdef _WIN32
+/*
+ * Used to display a string to the GUI interface.
+ * Windows' internal strerror() function doesn't work with socket errors.
+ */
+extern int     DisplayString(HWND hWnd, char *InBuf, ...);
+#undef strerror
+#endif
+
+#if defined(__FreeBSD__) || defined(__APPLE__)
+extern char *malloc_options;
+#endif
+
+extern int lu_noninv, lu_inv, lu_serv, lu_oper, 
+           lu_unknown, lu_channel, lu_lu, lu_lulocal, lu_lserv, 
+           lu_clu, lu_mlu, lu_cglobalu, lu_mglobalu;
+           
+time_t now;
+
+#endif /* __common_include__ */
diff --git a/include/config.h b/include/config.h
new file mode 100644 (file)
index 0000000..7ab99b9
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ *   IRC - Internet Relay Chat, include/config.h
+ *   Copyright (C) 1990 Jarkko Oikarinen
+ *
+ *   $Id$
+ * 
+ *   This program is free software; you can 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.
+ */
+
+#ifndef        __config_include__
+#define        __config_include__
+
+#include "setup.h"
+#include "settings.h"
+/*
+ *
+ *   NOTICE
+ *
+ * Under normal conditions, you should not have to edit this file.  Run
+ * the Config script in the root directory instead!
+ *
+ * Windows is not a normal condition, edit this file if you use it. :-)
+ *
+ *
+ */
+/*
+ * To windows porters:
+ *   You can specify name and url for their diff wircd sites
+ *   #undef WIN32_SPECIFY for not having any notice about it in the wIRCd
+ *    --Techie
+ */
+#undef WIN32_SPECIFY
+
+#ifdef WIN32_SPECIFY
+#define WIN32_PORTER ""
+#define WIN32_URL ""
+#endif
+
+ /*
+ * Define this if you're testing/debugging/programming.
+ */
+#undef DEBUG
+
+/* Type of host. These should be made redundant somehow. -avalon */
+
+/*     BSD                     Nothing Needed 4.{2,3} BSD, SunOS 3.x, 4.x */
+/*     HPUX                    Nothing needed (A.08/A.09) */
+/*     ULTRIX                  Nothing needed (4.2) */
+/*     OSF                     Nothing needed (1.2) */
+/* #undef      AIX             /* IBM ugly so-called Unix, AIX */
+/* #undef      MIPS            /* MIPS Unix */
+/*     SGI                     Nothing needed (IRIX 4.0.4) */
+/* #undef      SVR3            /* SVR3 stuff - being worked on where poss. */
+/* #undef      DYNIXPTX        /* Sequents Brain-dead Posix implement. */
+/* #undef      SOL20           /* Solaris2 */
+/* #undef      ESIX            /* ESIX */
+/* #undef      NEXT            /* NeXTStep */
+/* #undef      SVR4 /* */
+
+/* Additional flags to give FreeBSD's malloc, only play with this if you
+ * know what you're doing.
+ */
+#define MALLOC_FLAGS_EXTRA ""
+/* 
+   ConferenceRoom Java Client Hack -Fish
+   if you want it to work #define CONFROOM_JAVA_PORT <port>
+   where port MUST be a seperate port java clients connects on .. 
+*/
+#undef CONFROOM_JAVA_PORT
+
+/* 
+   REMOVE_ADVERTISING -ice
+      If you send a text to a user like "irc.roxnet.org" it will show up as "irc.******.org"
+   Off by default --stskeeps
+*/
+#undef REMOVE_ADVERTISING
+
+/* 
+     UnrealIRCd WebTV support
+*/
+#undef WEBTV
+
+#ifdef WEBTV
+/* enable /msg irc user */
+#define WEBTV_IRCUSER
+/* NOTICE's dont exist (except from server) */
+#define WEBTV_NONOTICE
+#endif
+
+/*
+    dog3/comstud ircd fdlists
+    undef this to make them work
+*/
+
+#undef NO_FDLIST
+/*
+   OPER_NO_HIDING
+      This makes +I an unexisting mode
+   On by default --stskeeps
+*/
+#undef OPER_NO_HIDING
+
+/*
+ * Admin's chat...
+ */
+#define ADMINCHAT 1
+
+/*
+  Remote rehash
+*/
+#define REMOTE_REHASH
+
+/*
+ * No spoof code
+ *
+ * This enables the spoof protection.
+ */
+/* #define NOSPOOF 1 /* */
+
+/*
+ *
+ * This controls the "nospoof" system.  These numbers are "seeds" of the
+ * "random" number generating formula.  Choose any number you like in the
+ * range of 0x00000000 to 0xFFFFFFFF.  Don't tell anyone these numbers, and
+ * don't use the default ones.  Change both #define NOSPOOF... lines below.
+ *
+ * Other data is mixed in as well, but these guarantee a per-server secret.
+ * Also, these values need not remain constant over compilations...  Change
+ * them as often as you like.
+ */
+#ifdef NOSPOOF
+
+#ifndef NOSPOOF_SEED01
+#define NOSPOOF_SEED01 0x12345678
+#endif
+
+#ifndef NOSPOOF_SEED02
+#define NOSPOOF_SEED02 0x87654321
+#endif
+
+#endif /* NOSPOOF */
+
+/*
+ * HOSTILENAME - Define this if you want the hostile username patch included,
+ *              it will strip characters that are not 0-9,a-z,A-Z,_,- or .
+ */
+#define HOSTILENAME    /* */
+
+/*
+ * Define this to prevent mixed case userids that clonebots use. However
+ * this affects the servers running telclients WLD* FIN*  etc.
+ */
+#undef DISALLOW_MIXED_CASE
+
+/*
+ * Define this if you wish to ignore the case of the first character of
+ * the user id when disallowing mixed case. This allows PC users to
+ * enter the more intuitive first name with the first letter capitalised
+ */
+#define        IGNORE_CASE_FIRST_CHAR
+
+/*
+** Nick flood limit
+** Minimum time between nick changes.
+** (The first two changes are allowed quickly after another however).
+**
+** Define NICK_DELAY if you want this feature.
+*/
+
+#define NICK_DELAY 15                   /* recommended value 15 */
+
+/*
+ * Define this if you wish to output a *file* to a K lined client rather
+ * than the K line comment (the comment field is treated as a filename)
+ */
+#undef COMMENT_IS_FILE
+
+
+/* Do these work? I dunno... */
+
+/* #undef      VMS             /* Should work for IRC client, not server */
+/* #undef      MAIL50          /* If you're running VMS 5.0 */
+/* #undef      PCS             /* PCS Cadmus MUNIX, use with BSD flag! */
+
+/*
+ * NOTE: On some systems, valloc() causes many problems.
+ */
+#undef VALLOC                  /* Define this if you have valloc(3) */
+
+/*
+ * read/write are restarted after signals defining this 1, gets
+ * siginterrupt call compiled, which attempts to remove this
+ * behaviour (apollo sr10.1/bsd4.3 needs this)
+ */
+#ifdef APOLLO
+#define        RESTARTING_SYSTEMCALLS
+#endif
+
+/*
+ * If your host supports varargs and has vsprintf(), vprintf() and vscanf()
+ * C calls in its library, then you can define USE_VARARGS to use varargs
+ * instead of imitation variable arg passing.
+#define        USE_VARARGS
+
+ * NOTE: with current server code, varargs doesn't survive because it can't
+ *       be used in a chain of 3 or more funtions which all have a variable
+ *       number of params.  If anyone has a solution to this, please notify
+ *       the maintainer.
+ */
+
+/* #undef      DEBUGMODE       /* define DEBUGMODE to enable debugging mode.*/
+
+/*
+ * defining FORCE_CORE will automatically "unlimit core", forcing the
+ * server to dump a core file whenever it has a fatal error.  -mlv
+ */
+#define FORCE_CORE
+
+/*
+ * Full pathnames and defaults of irc system's support files. Please note that
+ * these are only the recommened names and paths. Change as needed.
+ * You must define these to something, even if you don't really want them.
+ */
+#define        CPATH           "ircd.conf"     /* server configuration file */
+#define        MPATH           "ircd.motd"     /* server MOTD file */
+#define RPATH          "ircd.rules"    /* server rules file */
+#define ZPATH          "ircd.notes"    /* server notes */
+#define ZCONF          "networks/unrealircd.conf" /* ircd configuration .. */
+#define OPATH          "oper.motd"     /* Operators MOTD file */
+#define        LPATH           "debug.log"     /* Where the debug file lives, if DEBUGMODE */
+#define        PPATH           "ircd.pid"      /* file for server pid */
+#define lPATH          "ircd.log"      /* server log file */
+#define VPATH          "ircd.svsmotd"  /* Services MOTD append. */
+#define IRCDTUNE       "ircd.tune"     /* tuning .. */
+
+/*
+ * Define this filename to maintain a list of persons who log
+ * into this server. Logging will stop when the file does not exist.
+ * Logging will be disable also if you do not define this.
+ * FNAME_USERLOG just logs user connections, FNAME_OPERLOG logs every
+ * successful use of /oper.  These are either full paths or files within DPATH.
+ */
+#define FNAME_USERLOG "users.log"
+#define FNAME_OPERLOG "opers.log"
+
+/* FAILOPER_WARN
+ *
+ * When defined, warns users on a failed oper attempt that it was/is logged
+ * Only works when FNAME_OPERLOG is defined, and a logfile exists.
+ * NOTE: Failed oper attempts are logged regardless.
+ */
+#define FAILOPER_WARN
+
+/* CHROOTDIR
+ *
+ * Define for value added security if you are a rooter.
+ *
+ * All files you access must be in the directory you define as DPATH.
+ * (This may effect the PATH locations above, though you can symlink it)
+ *
+ * You may want to define IRC_UID and IRC_GID
+ */
+/* #define CHROOTDIR /* */
+
+/* SHOW_INVISIBLE_LUSERS
+ *
+ * As defined this will show the correct invisible count for anyone who does
+ * LUSERS on your server. On a large net this doesnt mean much, but on a
+ * small net it might be an advantage to undefine it.
+ * (This will get defined for you if you're using userload (stats w).  -mlv)
+ */
+#define        SHOW_INVISIBLE_LUSERS
+
+
+/* OPER_* defines
+ *
+ * See ./docs/example.conf for examples of how to restrict access for
+ * your IRC Operators
+ */
+
+/* MAXIMUM LINKS
+ *
+ * This define is useful for leaf nodes and gateways. It keeps you from
+ * connecting to too many places. It works by keeping you from
+ * connecting to more than "n" nodes which you have C:blah::blah:6667
+ * lines for.
+ *
+ * Note that any number of nodes can still connect to you. This only
+ * limits the number that you actively reach out to connect to.
+ *
+ * Leaf nodes are nodes which are on the edge of the tree. If you want
+ * to have a backup link, then sometimes you end up connected to both
+ * your primary and backup, routing traffic between them. To prevent
+ * this, #define MAXIMUM_LINKS 1 and set up both primary and
+ * secondary with C:blah::blah:6667 lines. THEY SHOULD NOT TRY TO
+ * CONNECT TO YOU, YOU SHOULD CONNECT TO THEM.
+ *
+ * Gateways such as the server which connects Australia to the US can
+ * do a similar thing. Put the American nodes you want to connect to
+ * in with C:blah::blah:6667 lines, and the Australian nodes with
+ * C:blah::blah lines. Have the Americans put you in with C:blah::blah
+ * lines. Then you will only connect to one of the Americans.
+ *
+ * This value is only used if you don't have server classes defined, and
+ * a server is in class 0 (the default class if none is set).
+ *
+ */
+
+#define MAXIMUM_LINKS 1
+
+/*
+ * NOTE: defining CMDLINE_CONFIG and installing ircd SUID or SGID is a MAJOR
+ *       security problem - they can use the "-f" option to read any files
+ *       that the 'new' access lets them. Note also that defining this is
+ *       a major security hole if your ircd goes down and some other user
+ *       starts up the server with a new conf file that has some extra
+ *       O-lines. So don't use this unless you're debugging.
+ */
+#define        CMDLINE_CONFIG /* allow conf-file to be specified on command line */
+
+/*
+ * To use m4 as a preprocessor on the ircd.conf file, define M4_PREPROC.
+ * The server will then call m4 each time it reads the ircd.conf file,
+ * reading m4 output as the server's ircd.conf file.
+ */
+#undef M4_PREPROC
+
+/*
+ * If you wish to have the server send 'vital' messages about server
+ * through syslog, define USE_SYSLOG. Only system errors and events critical
+ * to the server are logged although if this is defined with FNAME_USERLOG,
+ * syslog() is used instead of the above file. It is not recommended that
+ * this option is used unless you tell the system administrator beforehand
+ * and obtain their permission to send messages to the system log files.
+ */
+#ifndef _WIN32
+#undef USE_SYSLOG
+#endif
+
+#ifdef USE_SYSLOG
+/*
+ * If you use syslog above, you may want to turn some (none) of the
+ * spurious log messages for KILL/SQUIT off.
+ */
+#undef SYSLOG_KILL     /* log all operator kills to syslog */
+#undef  SYSLOG_SQUIT   /* log all remote squits for all servers to syslog */
+#undef SYSLOG_CONNECT  /* log remote connect messages for other all servs */
+#undef SYSLOG_USERS    /* send userlog stuff to syslog */
+#undef SYSLOG_OPER     /* log all users who successfully become an Op */
+
+/*
+ * If you want to log to a different facility than DAEMON, change
+ * this define.
+ */
+#define LOG_FACILITY LOG_DAEMON
+#endif /* USE_SYSLOG */
+
+/*
+ * IDLE_FROM_MSG
+ *
+ * Idle-time nullified only from privmsg, if undefined idle-time
+ * is nullified from everything except ping/pong.
+ * Added 3.8.1992, kny@cs.hut.fi (nam)
+ */
+#define IDLE_FROM_MSG
+
+/* 
+ * Size of the LISTEN request.  Some machines handle this large
+ * without problem, but not all.  It defaults to 5, but can be
+ * raised if you know your machine handles it.
+ */
+#ifndef LISTEN_SIZE
+#define LISTEN_SIZE 5
+#endif
+
+/*
+ * Max amount of internal send buffering when socket is stuck (bytes)
+ */
+#ifndef MAXSENDQLENGTH
+#define MAXSENDQLENGTH 3000000
+#endif
+/*
+ *  BUFFERPOOL is the maximum size of the total of all sendq's.
+ *  Recommended value is 2 * MAXSENDQLENGTH, for hubs, 5 *.
+ */
+#ifndef BUFFERPOOL
+#define        BUFFERPOOL     (9 * MAXSENDQLENGTH)
+#endif
+
+/*
+ * IRC_UID
+ *
+ * If you start the server as root but wish to have it run as another user,
+ * define IRC_UID to that UID.  This should only be defined if you are running
+ * as root and even then perhaps not.
+ */
+/* #undef      IRC_UID /* */
+/* #undef      IRC_GID /* */
+
+/*
+ * CLIENT_FLOOD
+ *
+ * this controls the number of bytes the server will allow a client to
+ * send to the server without processing before disconnecting the client for
+ * flooding it.  Values greater than 8000 make no difference to the server.
+ */
+#define        CLIENT_FLOOD    8000
+
+/* Define this if you want the server to accomplish ircII standard */
+/* Sends an extra NOTICE in the beginning of client connection     */
+#undef IRCII_KLUDGE
+
+/* 
+ * Define your network service names here.
+ */
+#define ChanServ "ChanServ"
+#define MemoServ "MemoServ"
+#define NickServ "NickServ"
+#define OperServ "OperServ"
+#define HelpServ "HelpServ"
+#define StatServ "StatServ"
+
+/*
+ * How many seconds in between simultaneous nick changes?
+ */
+#define NICK_CHANGE_DELAY      30
+
+/*
+ * How many open targets can one nick have for messaging nicks and
+ * inviting them?
+ */
+
+#define MAXTARGETS             20
+#define TARGET_DELAY           120
+
+/* 
+ * Would you like all clients to see the progress of their connections?
+ */
+
+#define SHOWCONNECTINFO
+
+/*
+ * SOCKS proxy checker
+ *
+ * At the moment this isn't an ideal solution, however it's better
+ * than nothing. Smaller servers shouldn't notice much of a performance
+ * hit, larger servers might have to reduce their Y-lines. In either
+ * case it's advisable to increase the number of FD's you define by
+ * about 10%.
+ *
+ * This determines the port on the local ircd machine that the open
+ * SOCKS server test attempts to connect back to. The default should
+ * be fine except for those unusual situations where the default
+ * port is in use for some reason.
+ *
+ * Undefining this will eliminate the checker from ircd.
+ */
+#define SOCKSPORT 6013
+
+/* Define default Z:line time for SOCKS   -taz */
+#define ZLINE_TIME     300
+
+/*   STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP  */
+
+/* You shouldn't change anything below this line, unless absolutely needed. */
+
+/*
+ * Port where ircd resides. NOTE: This *MUST* be greater than 1024 if you
+ * plan to run ircd under any other uid than root.
+ */
+#define PORTNUM 6667           /* 6667 is default */
+
+/*
+ * Maximum number of network connections your server will allow.  This should
+ * never exceed max. number of open file descrpitors and wont increase this.
+ * Should remain LOW as possible. Most sites will usually have under 30 or so
+ * connections. A busy hub or server may need this to be as high as 50 or 60.
+ * Making it over 100 decreases any performance boost gained from it being low.
+ * if you have a lot of server connections, it may be worth splitting the load
+ * over 2 or more servers.
+ * 1 server = 1 connection, 1 user = 1 connection.
+ * This should be at *least* 3: 1 listen port, 1 dns port + 1 client
+ *
+ * Note: this figure will be too high for most systems. If you get an 
+ * fd-related error on compile, change this to 256.
+ *
+ * Windows users: This should be a fairly high number.  Some operations
+ * will slow down because of this, but it is _required_ because of the way
+ * windows NT(and possibly 95) allocate fd handles. A good number is 16384.
+ */
+#ifndef MAXCONNECTIONS
+#define MAXCONNECTIONS 1024
+#endif
+
+/*
+ * this defines the length of the nickname history.  each time a user changes
+ * nickname or signs off, their old nickname is added to the top of the list.
+ * The following sizes are recommended:
+ * 8MB or less  core memory : 500      (at least 1/4 of max users)
+ * 8MB-16MB     core memory : 500-750  (1/4 -> 1/2 of max users)
+ * 16MB-32MB    core memory : 750-1000 (1/2 -> 3/4 of max users)
+ * 32MB or more core memory : 1000+    (> 3/4 if max users)
+ * where max users is the expected maximum number of users.
+ * (100 nicks/users ~ 25k)
+ * NOTE: this is directly related to the amount of memory ircd will use whilst
+ *      resident and running - it hardly ever gets swapped to disk! You can
+ *      ignore these recommendations- they only are meant to serve as a guide
+ * NOTE: But the *Minimum* ammount should be 100, in order to make nick
+ *       chasing possible for mode and kick.
+ */
+#ifndef NICKNAMEHISTORYLENGTH
+#define NICKNAMEHISTORYLENGTH 2000 
+#endif
+
+/*
+ * Time interval to wait and if no messages have been received, then check for
+ * PINGFREQUENCY and CONNECTFREQUENCY 
+ */
+#define TIMESEC  60            /* Recommended value: 60 */
+
+/*
+ * If daemon doesn't receive anything from any of its links within
+ * PINGFREQUENCY seconds, then the server will attempt to check for
+ * an active link with a PING message. If no reply is received within
+ * (PINGFREQUENCY * 2) seconds, then the connection will be closed.
+ */
+#define PINGFREQUENCY    120   /* Recommended value: 120 */
+
+/*
+ * If the connection to to uphost is down, then attempt to reconnect every 
+ * CONNECTFREQUENCY  seconds.
+ */
+#define CONNECTFREQUENCY 600   /* Recommended value: 600 */
+
+/*
+ * Often net breaks for a short time and it's useful to try to
+ * establishing the same connection again faster than CONNECTFREQUENCY
+ * would allow. But, to keep trying on bad connection, we require
+ * that connection has been open for certain minimum time
+ * (HANGONGOODLINK) and we give the net few seconds to steady
+ * (HANGONRETRYDELAY). This latter has to be long enough that the
+ * other end of the connection has time to notice it broke too.
+ */
+#define HANGONRETRYDELAY 20    /* Recommended value: 20 seconds */
+#define HANGONGOODLINK 300     /* Recommended value: 5 minutes */
+
+/*
+ * Number of seconds to wait for write to complete if stuck.
+ */
+#define WRITEWAITDELAY     15  /* Recommended value: 15 */
+
+/*
+ * Number of seconds to wait for a connect(2) call to complete.
+ * NOTE: this must be at *LEAST* 10.  When a client connects, it has
+ * CONNECTTIMEOUT - 10 seconds for its host to respond to an ident lookup
+ * query and for a DNS answer to be retrieved.
+ */
+#define        CONNECTTIMEOUT  90      /* Recommended value: 90 */
+
+/*
+ * Max time from the nickname change that still causes KILL
+ * automaticly to switch for the current nick of that user. (seconds)
+ */
+#define KILLCHASETIMELIMIT 90   /* Recommended value: 90 */
+
+/*
+ * Max number of channels a user is allowed to join.
+ */
+#define MAXCHANNELSPERUSER  10 /* Recommended value: 10 */
+
+/*
+ * SendQ-Always causes the server to put all outbound data into the sendq and
+ * flushing the sendq at the end of input processing. This should cause more
+ * efficient write's to be made to the network.
+ * There *shouldn't* be any problems with this method.
+ * -avalon
+ */
+#define        SENDQ_ALWAYS
+
+/* ------------------------- END CONFIGURATION SECTION -------------------- */
+#define MOTD MPATH
+#define RULES RPATH
+#define SNOTES ZPATH
+#define        MYNAME SPATH
+#define        CONFIGFILE CPATH
+#define        IRCD_PIDFILE PPATH
+#define GLINE_LOG GPATH
+
+#ifdef __osf__
+#define        OSF
+/* OSF defines BSD to be its version of BSD */
+#undef BSD
+#include <sys/param.h>
+#ifndef BSD
+#define BSD
+#endif
+#endif
+
+#ifdef _SEQUENT_               /* Dynix 1.4 or 2.0 Generic Define.. */
+#undef BSD
+#define SYSV                   /* Also #define SYSV */
+#endif
+
+#ifdef ultrix
+#define        ULTRIX
+#endif
+
+#ifdef __hpux
+#define        HPUX
+#endif
+
+#ifdef sgi
+#define        SGI
+#endif
+
+#ifndef KLINE_TEMP
+#define KLINE_PERM 0
+#define KLINE_TEMP 1
+#define KLINE_AKILL 2
+#define KLINE_EXCEPT 3
+#endif
+
+#ifdef DEBUGMODE
+extern void    debug();
+# define Debug(x) debug x
+# define LOGFILE LPATH
+#else
+# define Debug(x) ;
+# if VMS
+#      define LOGFILE "NLA0:"
+# else
+#      define LOGFILE "/dev/null"
+# endif
+#endif
+
+#ifndef ENABLE_SUMMON
+#  undef LEAST_IDLE
+#endif
+
+#if defined(mips) || defined(PCS)
+#undef SYSV
+#endif
+
+#ifdef MIPS
+#undef BSD
+#define BSD             1       /* mips only works in bsd43 environment */
+#endif
+
+#ifdef sequent                   /* Dynix (sequent OS) */
+#define SEQ_NOFILE    128        /* set to your current kernel impl, */
+#endif                           /* max number of socket connections */
+
+#ifdef _SEQUENT_
+#define        DYNIXPTX
+#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.  -4 allows "safety" margin of 1 and space reserved.
+ */
+#define        MAXCLIENTS      (MAXCONNECTIONS-4)
+
+#ifdef HAVECURSES
+# define DOCURSES
+#else
+# undef DOCURSES
+#endif
+
+#ifdef HAVETERMCAP
+# define DOTERMCAP
+#else
+# undef DOTERMCAP
+#endif
+
+# define stricmp strcasecmp
+# define strnicmp strncasecmp
+
+#if defined(CLIENT_FLOOD)
+#  if  (CLIENT_FLOOD > 8000)
+#    define CLIENT_FLOOD 8000
+#  else
+#    if (CLIENT_FLOOD < 512)
+error CLIENT_FLOOD needs redefining.
+#    endif
+#  endif
+#else
+error CLIENT_FLOOD undefined
+#endif
+#if (NICKNAMEHISTORYLENGTH < 100)
+#  define NICKNAMEHISTORYLENGTH 100
+#endif
+
+/*
+ * Some ugliness for AIX platforms.
+ */
+#ifdef AIX
+# include <sys/machine.h>
+# if BYTE_ORDER == BIG_ENDIAN
+#  define BIT_ZERO_ON_LEFT
+# endif
+# if BYTE_ORDER == LITTLE_ENDIAN
+#  define BIT_ZERO_ON_RIGHT
+# endif
+/*
+ * this one is used later in sys/types.h (or so i believe). -avalon
+ */
+# define BSD_INCLUDES
+#endif
+
+/*
+ * Cleaup for WIN32 platform.
+ */
+#ifdef _WIN32
+# undef FORCE_CORE
+#endif
+/* use cflag longmodes */
+#define USE_LONGMODE
+#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
+
+#endif /* __config_include__ */
+
+
diff --git a/include/dbuf.h b/include/dbuf.h
new file mode 100644 (file)
index 0000000..e54cb5b
--- /dev/null
@@ -0,0 +1,165 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/dbuf.h
+ *   Copyright (C) 1990 Markku Savela
+ *
+ *   This program is free software; you can 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 __dbuf_include__
+#define __dbuf_include__
+
+#ifndef PROTO
+#ifdef __STDC__
+#      define PROTO(x) x
+#else
+#      define PROTO(x) ()
+#endif /* __STDC__ */
+#endif /* ! PROTO */
+
+/*
+** dbuf is a collection of functions which can be used to
+** maintain a dynamic buffering of a byte stream.
+** Functions allocate and release memory dynamically as
+** required [Actually, there is nothing that prevents
+** this package maintaining the buffer on disk, either]
+*/
+
+/*
+** These structure definitions are only here to be used
+** as a whole, *DO NOT EVER REFER TO THESE FIELDS INSIDE
+** THE STRUCTURES*! It must be possible to change the internal
+** implementation of this package without changing the
+** interface.
+*/
+#if !defined(_SEQUENT_)
+typedef struct dbuf
+    {
+       u_int   length; /* Current number of bytes stored */
+       u_int   offset; /* Offset to the first byte */
+       struct  dbufbuf *head;  /* First data buffer, if length > 0 */
+       /* added by mnystrom@mit.edu: */
+       struct  dbufbuf *tail; /* last data buffer, if length > 0 */
+    } dbuf;
+#else
+typedef struct dbuf
+    {
+        uint   length; /* Current number of bytes stored */
+        uint   offset; /* Offset to the first byte */
+        struct  dbufbuf *head;  /* First data buffer, if length > 0 */
+       /* added by mnystrom@mit.edu: */
+       struct  dbufbuf *tail; /* last data buffer, if length > 0 */
+    } dbuf;
+#endif
+/*
+** And this 'dbufbuf' should never be referenced outside the
+** implementation of 'dbuf'--would be "hidden" if C had such
+** keyword...
+** If it was possible, this would compile to be exactly 1 memory
+** page in size. 2048 bytes seems to be the most common size, so
+** as long as a pointer is 4 bytes, we get 2032 bytes for buffer
+** data after we take away a bit for malloc to play with. -avalon
+*/
+typedef struct dbufbuf
+    {
+       struct  dbufbuf *next;  /* Next data buffer, NULL if this is last */
+       char    data[2032];     /* Actual data stored here */
+    } dbufbuf;
+
+/*
+** dbuf_put
+**     Append the number of bytes to the buffer, allocating more
+**     memory as needed. Bytes are copied into internal buffers
+**     from users buffer.
+**
+**     returns > 0, if operation successfull
+**             < 0, if failed (due memory allocation problem)
+*/
+int    dbuf_put PROTO((dbuf *, char *, int));
+                                       /* Dynamic buffer header */
+                                       /* Pointer to data to be stored */
+                                       /* Number of bytes to store */
+
+/*
+** dbuf_get
+**     Remove number of bytes from the buffer, releasing dynamic
+**     memory, if applicaple. Bytes are copied from internal buffers
+**     to users buffer.
+**
+**     returns the number of bytes actually copied to users buffer,
+**             if >= 0, any value less than the size of the users
+**             buffer indicates the dbuf became empty by this operation.
+**
+**             Return 0 indicates that buffer was already empty.
+**
+**             Negative return values indicate some unspecified
+**             error condition, rather fatal...
+*/
+int    dbuf_get PROTO(( dbuf *, char *, int));
+                               /* Dynamic buffer header */
+                               /* Pointer to buffer to receive the data */
+                               /* Max amount of bytes that can be received */
+
+/*
+** dbuf_map, dbuf_delete
+**     These functions are meant to be used in pairs and offer
+**     a more efficient way of emptying the buffer than the
+**     normal 'dbuf_get' would allow--less copying needed.
+**
+**     map     returns a pointer to a largest contiguous section
+**             of bytes in front of the buffer, the length of the
+**             section is placed into the indicated "long int"
+**             variable. Returns NULL *and* zero length, if the
+**             buffer is empty.
+**
+**     delete  removes the specified number of bytes from the
+**             front of the buffer releasing any memory used for them.
+**
+**     Example use (ignoring empty condition here ;)
+**
+**             buf = dbuf_map(&dyn, &count);
+**             <process N bytes (N <= count) of data pointed by 'buf'>
+**             dbuf_delete(&dyn, N);
+**
+**     Note:   delete can be used alone, there is no real binding
+**             between map and delete functions...
+*/
+char *dbuf_map PROTO((dbuf *, int *));
+                                       /* Dynamic buffer header */
+                                       /* Return number of bytes accessible */
+
+int dbuf_delete PROTO((dbuf *, int));
+                                       /* Dynamic buffer header */
+                                       /* Number of bytes to delete */
+
+/*
+** DBufLength
+**     Return the current number of bytes stored into the buffer.
+**     (One should use this instead of referencing the internal
+**     length field explicitly...)
+*/
+#define DBufLength(dyn) ((dyn)->length)
+
+/*
+** DBufClear
+**     Scratch the current content of the buffer. Release all
+**     allocated buffers and make it empty.
+*/
+#define DBufClear(dyn) dbuf_delete((dyn),DBufLength(dyn))
+
+extern int     dbuf_getmsg PROTO((dbuf *, char *, int));
+
+#endif /* __dbuf_include__ */
diff --git a/include/dynconf.h b/include/dynconf.h
new file mode 100644 (file)
index 0000000..e50ecaf
--- /dev/null
@@ -0,0 +1,103 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/dynconf.h
+ *   Copyright (C) 1999 Carsten Munk
+ *
+ *   This program is free software; you can 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 DYNCONF_H
+typedef struct zNetwork                aNetwork;
+struct zNetwork {
+       char            *x_ircnetwork;
+       char            *x_defserv;
+       char            *x_services_name;
+       char            *x_oper_host;
+       char            *x_admin_host;
+       char            *x_locop_host;
+       char            *x_sadmin_host;
+       char            *x_netadmin_host;
+       char            *x_coadmin_host;
+       char            *x_techadmin_host;
+       char            *x_hidden_host;
+       char            *x_netdomain;
+       char            *x_helpchan;
+       char            *x_stats_server;
+       int                     x_halfhub;
+       int                     x_inah;
+       char            *x_net_quit;
+       int                     x_se;
+};
+
+typedef struct zConfiguration aConfiguration;
+struct zConfiguration {
+       long            nospoof_seed01;
+       long            nospoof_seed02;
+       char            *kline_address;
+       char            *include;
+       char            *domainname;
+       char            *domainmask; /* '*' + domainname */
+       int             som;
+       int             mode_x;
+       int             mode_i;
+       int             truehub;
+       int             stop;
+       int             showopers;
+       int             killdiff;
+       int             hide_ulines;
+       int             allow_chatops;
+       int             socksbantime;
+       char            *socksbanmessage;
+       char            *socksquitmessage;      
+       aNetwork        network;
+};
+
+#ifndef DYNCONF_C
+extern aConfiguration iConf;
+#endif
+
+// #define NOSPOOF_SEED01              iConf.nospoof_seed01
+// #define NOSPOOF_SEED02              iConf.nospoof_seed02
+#define KLINE_ADDRESS          iConf.kline_address
+#define INCLUDE                                iConf.include
+#define DOMAINNAMEMASK         "*" DOMAINNAME
+#define MODE_X                         iConf.mode_x
+#define MODE_I                         iConf.mode_i
+#define TRUEHUB                                iConf.truehub
+#define SHOWOPERS                      iConf.showopers
+#define KILLDIFF                       iConf.killdiff
+#define SHOWOPERMOTD                   iConf.som
+#define HIDE_ULINES                    iConf.hide_ulines
+#define ALLOW_CHATOPS          iConf.allow_chatops
+
+#define ircnetwork                     iConf.network.x_ircnetwork
+#define defserv                                iConf.network.x_defserv
+#define SERVICES_NAME          iConf.network.x_services_name
+#define oper_host                      iConf.network.x_oper_host
+#define admin_host                     iConf.network.x_admin_host
+#define locop_host                     iConf.network.x_locop_host
+#define sadmin_host                    iConf.network.x_sadmin_host
+#define netadmin_host          iConf.network.x_netadmin_host
+#define coadmin_host           iConf.network.x_coadmin_host
+#define techadmin_host         iConf.network.x_techadmin_host
+#define hidden_host                    iConf.network.x_hidden_host
+#define netdomain                      iConf.network.x_netdomain
+#define helpchan                       iConf.network.x_helpchan
+#define STATS_SERVER           iConf.network.x_stats_server
+#define iNAH                           iConf.network.x_inah
+#define net_quit                       iConf.network.x_net_quit
+#define STOPSE                         iConf.network.x_se
\ No newline at end of file
diff --git a/include/fdlist.h b/include/fdlist.h
new file mode 100644 (file)
index 0000000..8a1f843
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef _IRCD_DOG3_FDLIST
+#define _IRCD_DOG3_FDLIST
+
+/* $Id$ */
+
+typedef struct fdstruct {
+   int         entry[MAXCONNECTIONS + 2];
+   int         last_entry;
+} fdlist;
+
+void        addto_fdlist(int a, fdlist * b);
+void        delfrom_fdlist(int a, fdlist * b);
+void        init_fdlist(fdlist * b);
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#define LOADCFREQ 5
+#define LOADRECV 35
+#define FDLISTCHKFREQ  2         
+
+#endif /*
+        * _IRCD_DOG3_FDLIST 
+        */
diff --git a/include/h.h b/include/h.h
new file mode 100644 (file)
index 0000000..227530d
--- /dev/null
@@ -0,0 +1,340 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/h.h
+ *   Copyright (C) 1992 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+
+/*
+ * "h.h". - Headers file.
+ *
+ * Most of the externs and prototypes thrown in here to 'cleanup' things.
+ * -avalon
+ */
+#ifndef NO_FDLIST
+#include "fdlist.h"
+#endif
+
+extern time_t  nextconnect, nextdnscheck, nextping;
+extern aClient *client, me, *local[];
+extern aChannel *channel;
+extern struct  stats   *ircstp;
+extern int     bootopt;
+extern  time_t TSoffset;
+/* Prototype added to force errors -- Barubary */
+extern time_t  check_pings(time_t now, int check_kills);
+
+/* Remmed out for win32 compatibility.. as stated of 467leaf win32 port.. */
+
+#ifdef _WIN32
+// extern      void    *hCio;
+#endif
+
+#ifdef SHOWCONNECTINFO
+
+#ifdef SOCKSPORT
+#define BREPORT_DO_SOCKS "NOTICE AUTH :*** Checking for open socks server...\r\n"
+#define BREPORT_GOOD_SOCKS "NOTICE AUTH :*** Secure socks found (good!)...\r\n"
+#define BREPORT_NO_SOCKS "NOTICE AUTH :*** No socks server found (good!)...\r\n"
+#endif
+
+#define BREPORT_DO_DNS "NOTICE AUTH :*** Looking up your hostname...\r\n"
+#define BREPORT_FIN_DNS        "NOTICE AUTH :*** Found your hostname\r\n"
+#define BREPORT_FIN_DNSC "NOTICE AUTH :*** Found your hostname (cached)\r\n"
+#define BREPORT_FAIL_DNS "NOTICE AUTH :*** Couldn't resolve your hostname; using your IP address instead\r\n"
+#define BREPORT_DO_ID  "NOTICE AUTH :*** Checking ident...\r\n"
+#define BREPORT_FIN_ID "NOTICE AUTH :*** Received identd response\r\n"
+#define BREPORT_FAIL_ID        "NOTICE AUTH :*** No ident response; username prefixed with ~\r\n"
+
+extern char REPORT_DO_DNS[128], REPORT_FIN_DNS[128], REPORT_FIN_DNSC[128],
+       REPORT_FAIL_DNS[128], REPORT_DO_ID[128], REPORT_FIN_ID[128],
+        REPORT_FAIL_ID[128];
+#ifdef SOCKSPORT
+extern char REPORT_DO_SOCKS[128], REPORT_GOOD_SOCKS[128],
+        REPORT_NO_SOCKS[128];
+#endif
+
+extern int R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns,
+                R_do_id, R_fin_id, R_fail_id;
+#ifdef SOCKSPORT
+               extern int R_do_socks,
+                R_good_socks, R_no_socks;
+#endif
+#endif
+extern aChannel *find_channel PROTO((char *, aChannel *));
+extern void    remove_user_from_channel PROTO((aClient *, aChannel *));
+/* for services */
+extern void    del_invite PROTO((aClient *, aChannel *));
+extern int     del_silence PROTO((aClient *, char *));
+extern void    send_user_joins PROTO((aClient *, aClient *));
+extern void    clean_channelname PROTO((char *));
+extern int     do_nick_name PROTO((char *));
+extern int     can_send PROTO((aClient *, aChannel *, char *));
+extern int     is_chan_op PROTO((aClient *, aChannel *));
+extern int     is_zombie PROTO((aClient *, aChannel *));
+extern int     has_voice PROTO((aClient *, aChannel *));
+extern int     is_chanowner PROTO((aClient *, aChannel *));
+extern int     count_channels PROTO((aClient *));
+extern  Ban    *is_banned PROTO((aClient *, aClient *, aChannel *));
+extern int     parse_help PROTO((aClient *, char *, char *));
+
+extern void    ircd_log PROTO((char *, ...));
+extern aClient *find_client PROTO((char *, aClient *));
+extern aClient *find_name PROTO((char *, aClient *));
+extern aClient *find_nickserv PROTO((char *, aClient *));
+extern aClient *find_person PROTO((char *, aClient *));
+extern aClient *find_server PROTO((char *, aClient *));
+extern aClient *find_service PROTO((char *, aClient *));
+
+extern int     attach_conf PROTO((aClient *, aConfItem *));
+extern aConfItem *attach_confs PROTO((aClient*, char *, int));
+extern aConfItem *attach_confs_host PROTO((aClient*, char *, int));
+extern int     attach_Iline PROTO((aClient *, struct hostent *, char *));
+extern aConfItem *conf, *find_me PROTO(()), *find_admin PROTO(());
+extern aConfItem *count_cnlines PROTO((Link *));
+extern  aSqlineItem *sqline;
+extern void    det_confs_butmask PROTO((aClient *, int));
+extern int     detach_conf PROTO((aClient *, aConfItem *));
+extern  aSqlineItem *find_sqline_nick PROTO((char *));
+extern aSqlineItem *find_sqline_match PROTO((char *));
+extern aConfItem *det_confs_butone PROTO((aClient *, aConfItem *));
+extern  char *find_diepass();
+extern  char *find_restartpass();
+extern aConfItem *find_conf PROTO((Link *, char*, int));
+extern aConfItem *find_conf_exact PROTO((char *, char *, char *, int));
+extern aConfItem *find_conf_host PROTO((Link *, char *, int));
+extern aConfItem *find_conf_ip PROTO((Link *, char *, char *, int));
+extern aConfItem *find_conf_name PROTO((char *, int));
+extern  aConfItem *find_temp_conf_entry PROTO((aConfItem *, u_int));
+extern  aConfItem *find_conf_servern PROTO((char *));
+extern int     find_kill PROTO((aClient *));
+extern char    *find_zap PROTO((aClient *, int));
+extern int     find_restrict PROTO((aClient *));
+extern int     rehash PROTO((aClient *, aClient *, int));
+extern int     initconf PROTO((int));
+extern void    add_temp_conf();
+extern void    inittoken PROTO(());
+extern void    reset_help PROTO(());
+extern int     find_exception(char *); /* hidden host */
+
+extern char    *MyMalloc PROTO((int)), *MyRealloc PROTO((char *, int));
+extern char    *debugmode, *configfile, *sbrk0;
+extern char    *getfield PROTO((char *));
+extern void    get_sockhost PROTO((aClient *, char *));
+extern char    *rpl_str PROTO((int)), *err_str PROTO((int));
+extern char    *strerror PROTO((int));
+extern int     dgets PROTO((int, char *, int));
+extern char    *inetntoa PROTO((char *));
+
+#ifdef _WIN32
+extern int     dbufalloc, dbufblocks, debuglevel;
+#else
+extern int     dbufalloc, dbufblocks, debuglevel, errno, h_errno;
+#endif
+extern int     highest_fd, debuglevel, portnum, debugtty, maxusersperchannel;
+extern int     readcalls, udpfd, resfd;
+extern aClient *add_connection PROTO((aClient *, int));
+extern int     add_listener PROTO((aConfItem *));
+extern void    add_local_domain PROTO((char *, int));
+extern int     check_client PROTO((aClient *));
+extern int     check_server PROTO((aClient *, struct hostent *, \
+                                   aConfItem *, aConfItem *, int));
+extern int     check_server_init PROTO((aClient *));
+extern void    close_connection PROTO((aClient *));
+extern void    close_listeners PROTO(());
+extern int connect_server PROTO((aConfItem *, aClient *, struct hostent *));
+extern void    get_my_name PROTO((aClient *, char *, int));
+extern int     get_sockerr PROTO((aClient *));
+extern int     inetport PROTO((aClient *, char *, int));
+extern void    init_sys PROTO(());
+
+#ifdef NO_FDLIST
+extern int     read_message PROTO((time_t));
+#else
+extern int      read_message PROTO((time_t, fdlist *));
+#endif
+
+extern void    report_error PROTO((char *, aClient *));
+extern void    set_non_blocking PROTO((int, aClient *));
+extern int     setup_ping PROTO(());
+extern void    summon PROTO((aClient *, char *, char *, char *));
+extern int     unixport PROTO((aClient *, char *, int));
+extern int     utmp_open PROTO(());
+extern int     utmp_read PROTO((int, char *, char *, char *, int));
+extern int     utmp_close PROTO((int));
+
+extern void    start_auth PROTO((aClient *));
+extern void    read_authports PROTO((aClient *));
+extern void    send_authports PROTO((aClient *));
+
+#ifdef SOCKSPORT
+extern void    init_socks PROTO((aClient *));
+extern void    start_socks PROTO((aClient *));
+extern void    send_socksquery PROTO((aClient *));
+extern void    read_socks PROTO((aClient *));
+#endif
+
+extern void    restart PROTO((char *));
+extern void    send_channel_modes PROTO((aClient *, aChannel *));
+extern void    server_reboot PROTO((char *));
+extern void    terminate PROTO(()), write_pidfile PROTO(());
+
+extern int     send_queued PROTO((aClient *));
+/*VARARGS2*/
+// extern      void    sendto_one(char *, ...);
+/*VARARGS4*/
+/* i know this is naughty but :P --stskeeps */
+extern void    sendto_channel_butone(aClient *, aClient *, aChannel *, char *, ...);
+extern void    sendto_channelops_butone(aClient *, aClient *, aChannel *, char *, ...);
+extern void    sendto_channelvoice_butone(aClient *, aClient *, aChannel *, char *, ...);
+/*VARARGS2*/
+extern void    sendto_serv_butone(aClient *, char *, ...);
+/*VARARGS2*/
+extern void    sendto_serv_butone_quit(aClient *, char *, ...);
+extern void    sendto_serv_butone_sjoin(aClient *, char *, ...);
+extern void    sendto_serv_sjoin(aClient *, char *, ...);
+/*VARARGS2*/
+
+extern void    sendto_common_channels(aClient *, char *, ...);
+/*VARARGS3*/
+extern void    sendto_channel_butserv(aChannel *, aClient *, char *, ...);
+/*VARARGS3*/
+extern void    sendto_match_servs(aChannel *, aClient *, char *, ...);
+/*VARARGS5*/
+extern void    sendto_match_butone(aClient *, aClient *, char *, int, char *pattern, ...);
+/*VARARGS3*/
+extern void    sendto_all_butone(aClient *, aClient *, char *, ...);
+/*VARARGS1*/
+extern void    sendto_ops(char *, ...);
+/*VARARGS3*/
+extern void    sendto_ops_butone(aClient *, aClient *, char *, ...);
+/*VARARGS3*/
+extern void    sendto_ops_butme(aClient *, char *, ...);
+/*VARARGS3*/
+extern void    sendto_prefix_one(aClient *, aClient *, const char *, ...);
+/*VARARGS3*/
+extern  void    sendto_failops_whoare_opers(char *, ...);
+/*VARARGS3*/
+extern  void    sendto_failops(char *, ...);
+/*VARARGS3*/
+extern  void    sendto_opers(char *, ...);
+/*VARARGS?*/
+extern void    sendto_umode(int, char *, ...);
+extern void    sendto_conn_hcn(char *, ...);
+extern int     writecalls, writeb[];
+extern int     deliver_it PROTO((aClient *, char *, int));
+
+extern int     check_registered PROTO((aClient *));
+extern int     check_registered_user PROTO((aClient *));
+extern char    *get_client_name PROTO((aClient *, int));
+extern char    *get_client_host PROTO((aClient *));
+extern char    *my_name_for_link PROTO((char *, aConfItem *));
+extern char    *myctime PROTO((time_t)), *date PROTO((time_t));
+extern int     exit_client PROTO((aClient *, aClient *, aClient *, char *));
+extern void    initstats PROTO(()), tstats PROTO((aClient *, char *));
+extern char    *check_string PROTO((char *));
+extern char    *make_nick_user_host PROTO((char *, char *, char *));
+
+extern int     parse PROTO((aClient *, char *, char *, struct Message *));
+extern int     do_numeric PROTO((int, aClient *, aClient *, int, char **));
+extern int hunt_server PROTO((aClient *,aClient *,char *,int,int,char **));
+extern aClient *next_client PROTO((aClient *, char *));
+extern int     m_umode PROTO((aClient *, aClient *, int, char **));
+extern int     m_names PROTO((aClient *, aClient *, int, char **));
+extern int     m_server_estab PROTO((aClient *));
+extern void    send_umode PROTO((aClient *, aClient *, int, int, char *));
+extern void    send_umode_out PROTO((aClient*, aClient *, int));
+
+extern void    free_client PROTO((aClient *));
+extern void    free_link PROTO((Link *));
+extern void    free_ban PROTO((Ban *));
+extern void    free_conf PROTO((aConfItem *));
+extern void    free_class PROTO((aClass *));
+extern void    free_user PROTO((anUser *, aClient *));
+extern int     find_str_match_link PROTO((Link **, char *));
+extern void    free_str_list PROTO ((Link *));
+extern Link    *make_link PROTO(());
+extern Ban     *make_ban PROTO(());
+extern anUser  *make_user PROTO((aClient *));
+extern  aSqlineItem *make_sqline PROTO(());
+extern aConfItem *make_conf PROTO(());
+extern aClass  *make_class PROTO(());
+extern aServer *make_server PROTO(());
+extern aClient *make_client PROTO((aClient *, aClient *));
+extern Link    *find_user_link PROTO((Link *, aClient *));
+extern Link    *find_channel_link PROTO((Link *, aChannel *));
+extern char    *pretty_mask PROTO((char *));
+extern void    add_client_to_list PROTO((aClient *));
+extern void    checklist PROTO(());
+extern void    remove_client_from_list PROTO((aClient *));
+extern void    initlists PROTO(());
+
+extern void    add_class PROTO((int, int, int, int, long));
+extern void    fix_class PROTO((aConfItem *, aConfItem *));
+extern long    get_sendq PROTO((aClient *));
+extern int     get_con_freq PROTO((aClass *));
+extern int     get_client_ping PROTO((aClient *));
+extern int     get_client_class PROTO((aClient *));
+extern int     get_conf_class PROTO((aConfItem *));
+extern void    report_classes PROTO((aClient *));
+
+extern struct  hostent *get_res PROTO((char *));
+extern struct  hostent *gethost_byaddr PROTO((char *, Link *));
+extern struct  hostent *gethost_byname PROTO((char *, Link *));
+extern void    flush_cache PROTO(());
+extern int     init_resolver PROTO((int));
+extern time_t  timeout_query_list PROTO((time_t));
+extern time_t  expire_cache PROTO((time_t));
+extern void    del_queries PROTO((char *));
+
+extern void    clear_channel_hash_table PROTO(());
+extern void    clear_client_hash_table PROTO(());
+extern void    clear_notify_hash_table PROTO(());
+extern int     add_to_client_hash_table PROTO((char *, aClient *));
+extern int     del_from_client_hash_table PROTO((char *, aClient *));
+extern int     add_to_channel_hash_table PROTO((char *, aChannel *));
+extern int     del_from_channel_hash_table PROTO((char *, aChannel *));
+extern int     add_to_notify_hash_table PROTO((char *, aClient *));
+extern int     del_from_notify_hash_table PROTO((char *, aClient *));
+extern int     hash_check_notify PROTO((aClient *, int));
+extern int     hash_del_notify_list PROTO((aClient  *));
+extern void    count_watch_memory PROTO((int *, u_long *));
+extern aNotify *hash_get_notify PROTO((char *));
+extern aChannel *hash_get_chan_bucket PROTO((int));
+extern aChannel *hash_find_channel PROTO((char *, aChannel *));
+extern aClient *hash_find_client PROTO((char *, aClient *));
+extern aClient *hash_find_nickserver PROTO((char *, aClient *));
+extern aClient *hash_find_server PROTO((char *, aClient *));
+
+extern void    add_history PROTO((aClient *));
+extern aClient *get_history PROTO((char *, time_t));
+extern void    initwhowas PROTO(());
+extern void    off_history PROTO((aClient *));
+
+extern int     dopacket PROTO((aClient *, char *, int));
+
+/*VARARGS2*/
+extern void    debug();
+#if defined(DEBUGMODE)
+extern void    send_usage PROTO((aClient *, char *));
+extern void    send_listinfo PROTO((aClient *, char *));
+extern void    count_memory PROTO((aClient *, char *));
+#endif
+
+char *crule_parse PROTO((char *));
+int crule_eval PROTO((char *));
+void crule_free PROTO((char **));
diff --git a/include/hash.h b/include/hash.h
new file mode 100644 (file)
index 0000000..8573d8e
--- /dev/null
@@ -0,0 +1,48 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/hash.h
+ *   Copyright (C) 1991 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ *   $Id$
+ */
+
+#ifndef        __hash_include__
+#define __hash_include__
+
+/* Ditch the stats if not running in debugmode */
+#ifdef DEBUGMODE
+typedef        struct  hashentry {
+       int     hits;
+       int     links;
+       void    *list;
+       } aHashEntry;
+#else /* DEBUGMODE */
+typedef        void    *aHashEntry;
+#endif /* DEBUGMODE */
+
+#ifndef        DEBUGMODE
+#define        HASHSIZE        32003   /* prime number */
+#define        CHANNELHASHSIZE 10007   /* prime number */
+#else
+extern int     HASHSIZE;
+extern int     CHANNELHASHSIZE;
+#endif
+
+#define NOTIFYHASHSIZE 10007   /* prime number  */
+
+#define NullChn        ((aChannel *)0)
+
+#endif /* __hash_include__ */
diff --git a/include/inet.h b/include/inet.h
new file mode 100644 (file)
index 0000000..9b980e3
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ *
+ *     @(#)inet.h      5.4 (Berkeley) 6/1/90
+ */
+
+/* External definitions for functions in inet(3) */
+#include "config.h" /* for system definitions */
+
+#ifdef __alpha
+#define        __u_l   unsigned int
+#else
+#define        __u_l   unsigned long
+#endif
+
+#ifdef __STDC__
+# ifndef _WIN32
+extern __u_l inet_addr(char *);
+extern char *inet_ntoa(char *);
+# endif
+extern __u_l inet_makeaddr(int , int);
+extern __u_l inet_network(char *);
+extern __u_l inet_lnaof(struct in_addr);
+#else
+# ifndef _WIN32
+extern __u_l inet_addr();
+extern char *inet_ntoa();
+# endif
+#ifndef HPUX
+extern __u_l inet_makeaddr();
+#endif
+#endif
+#ifndef  HPUX
+extern __u_l inet_network();
+extern __u_l inet_lnaof();
+#endif
+#undef __u_l
diff --git a/include/license.h b/include/license.h
new file mode 100644 (file)
index 0000000..cefc0a6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *   IRC - Internet Relay Chat, include/license.h
+ *   Copyright (C) 1999 Carsten Munk
+ *
+ *   This program is free software; you can 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.
+ * 
+ *   This file may not be removed from the IRCd package.
+ *   It will be a violation of copyright. This program must always
+ *   stay free and not be sold, or charged. 
+ * 
+ *   $Id$
+ */
+
+/* 
+ * GNU License converted by Techie <stskeeps@tspre.org>
+ *
+*/
+
+static char *Statement[] = {
+" * This file may not be removed from the IRCd package.",
+" * It will be a violation of copyright. This program must always",
+" * stay free and not be charged for, being sold commercially or privately",
+" * Only charge may be for the transport medium like one CD-ROM, floppy",
+" * or other kinds.",
+0};
+
+char *gnulicense[] = {
+"   \2UnrealIRCd License\2",
+"This program is free software; you can 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.",
+"",
+"To see the UnrealIRCd License, please point your browser",
+"at http://www.gnu.org/copyleft/gpl.html or look in the",
+"file LICENSE in the UnrealIRCd dist",
+0
+};
+
diff --git a/include/msg.h b/include/msg.h
new file mode 100644 (file)
index 0000000..7583742
--- /dev/null
@@ -0,0 +1,476 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/msg.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 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        __msg_include__
+#define __msg_include__
+
+/*
+ * The tokens are in the ascii character range of 33-127, and we start
+ * from 33 and just move up.  It would be nice to match then up so they
+ * are slightly related to their string counterpart, but that makes it
+ * too confusing when we want to add another one and need to make sure
+ * we're not using one already used. -Cabal95
+ *
+ * As long as the #defines are kept statically placed, it will be fine.
+ * We don't care/worry about the msgtab[] since it can be dynamic, but
+ * the tokens it uses will still be static according to the messages
+ * they represent.  In other words leave the #defines in order, if you're
+ * going to add something, PUT IT AT THE END.  Do not even look for an
+ * open spot somewhere, as that may lead to one type of message being
+ * sent by server A to server B, but server B thinks its something else.
+ * Remember, skip the : since its got a special use, and I skip the \ too
+ * since it _may_ cause problems, but not sure.  -Cabal95
+ * I'm skipping A and a as well, because some clients and scripts use
+ * these to test if the server has already processed whole queue.
+ * Since the client could request this protocol withhout the script
+ * knowing it, I'm considering that reserved, and TRACE/A is now 'b'.
+ * The normal msgtab should probably process this as special. -Donwulff
+ */
+/*     12/05/1999 - I was wrong - I didnt see the token[2] in struct Message
+       okie 60*60 commands more :P - Sowwy!!! -sts
+       
+ */
+
+#define MSG_PRIVATE    "PRIVMSG"       /* PRIV */
+#define TOK_PRIVATE    "!"             /* 33 */
+#define MSG_WHO                "WHO"           /* WHO  -> WHOC */
+#define TOK_WHO                "\""            /* 34 */
+#define MSG_WHOIS      "WHOIS"         /* WHOI */
+#define TOK_WHOIS      "#"             /* 35 */
+#define MSG_WHOWAS     "WHOWAS"        /* WHOW */
+#define TOK_WHOWAS     "$"             /* 36 */
+#define MSG_USER       "USER"          /* USER */
+#define TOK_USER       "%"             /* 37 */
+#define MSG_NICK       "NICK"          /* NICK */
+#define TOK_NICK       "&"             /* 38 */
+#define MSG_SERVER     "SERVER"        /* SERV */
+#define TOK_SERVER     "'"             /* 39 */
+#define MSG_LIST       "LIST"          /* LIST */
+#define TOK_LIST       "("             /* 40 */
+#define MSG_TOPIC      "TOPIC"         /* TOPI */
+#define TOK_TOPIC      ")"             /* 41 */
+#define MSG_INVITE     "INVITE"        /* INVI */
+#define TOK_INVITE     "*"             /* 42 */
+#define MSG_VERSION    "VERSION"       /* VERS */
+#define TOK_VERSION    "+"             /* 43 */
+#define MSG_QUIT       "QUIT"          /* QUIT */
+#define TOK_QUIT       ","             /* 44 */
+#define MSG_SQUIT      "SQUIT"         /* SQUI */
+#define TOK_SQUIT      "-"             /* 45 */
+#define MSG_KILL       "KILL"          /* KILL */
+#define TOK_KILL       "."             /* 46 */
+#define MSG_INFO       "INFO"          /* INFO */
+#define TOK_INFO       "/"             /* 47 */
+#define MSG_LINKS      "LINKS"         /* LINK */
+#define TOK_LINKS      "0"             /* 48 */
+#define MSG_SUMMON     "SUMMON"        /* SUMM */
+#define TOK_SUMMON     "1"             /* 49 */
+#define MSG_STATS      "STATS"         /* STAT */
+#define TOK_STATS      "2"             /* 50 */
+#define MSG_USERS      "USERS"         /* USER -> USRS */
+#define TOK_USERS      "3"             /* 51 */
+#define MSG_HELP       "HELP"          /* HELP */
+#define MSG_HELPOP     "HELPOP"        /* HELP */
+#define MSG_IRCDHELP "IRCDHELP" /* HELP */
+#define TOK_HELP       "4"             /* 52 */
+#define MSG_ERROR      "ERROR"         /* ERRO */
+#define TOK_ERROR      "5"             /* 53 */
+#define MSG_AWAY       "AWAY"          /* AWAY */
+#define TOK_AWAY       "6"             /* 54 */
+#define MSG_CONNECT    "CONNECT"       /* CONN */
+#define TOK_CONNECT    "7"             /* 55 */
+#define MSG_PING       "PING"          /* PING */
+#define TOK_PING       "8"             /* 56 */
+#define MSG_PONG       "PONG"          /* PONG */
+#define TOK_PONG       "9"             /* 57 */
+#define MSG_OPER       "OPER"          /* OPER */
+#define TOK_OPER       ";"             /* 59 */
+#define MSG_PASS       "PASS"          /* PASS */
+#define TOK_PASS       "<"             /* 60 */
+#define MSG_WALLOPS    "WALLOPS"       /* WALL */
+#define TOK_WALLOPS    "="             /* 61 */
+#define MSG_TIME       "TIME"          /* TIME */
+#define TOK_TIME       ">"             /* 62 */
+#define MSG_NAMES      "NAMES"         /* NAME */
+#define TOK_NAMES      "?"             /* 63 */
+#define MSG_ADMIN      "ADMIN"         /* ADMI */
+#define TOK_ADMIN      "@"             /* 64 */
+#define MSG_NOTICE     "NOTICE"        /* NOTI */
+#define TOK_NOTICE     "B"             /* 66 */
+#define MSG_JOIN       "JOIN"          /* JOIN */
+#define TOK_JOIN       "C"             /* 67 */
+#define MSG_PART       "PART"          /* PART */
+#define TOK_PART       "D"             /* 68 */
+#define MSG_LUSERS     "LUSERS"        /* LUSE */
+#define TOK_LUSERS     "E"             /* 69 */
+#define MSG_MOTD       "MOTD"          /* MOTD */
+#define TOK_MOTD       "F"             /* 70 */
+#define MSG_MODE       "MODE"          /* MODE */
+#define TOK_MODE       "G"             /* 71 */
+#define MSG_KICK       "KICK"          /* KICK */
+#define TOK_KICK       "H"             /* 72 */
+#define MSG_SERVICE    "SERVICE"       /* SERV -> SRVI */
+#define TOK_SERVICE    "I"             /* 73 */
+#define MSG_USERHOST   "USERHOST"      /* USER -> USRH */
+#define TOK_USERHOST   "J"             /* 74 */
+#define MSG_ISON       "ISON"          /* ISON */
+#define TOK_ISON       "K"             /* 75 */
+#define        MSG_REHASH      "REHASH"        /* REHA */
+#define TOK_REHASH     "O"             /* 79 */
+#define        MSG_RESTART     "RESTART"       /* REST */
+#define TOK_RESTART    "P"             /* 80 */
+#define        MSG_CLOSE       "CLOSE"         /* CLOS */
+#define TOK_CLOSE      "Q"             /* 81 */
+#define        MSG_DIE         "DIE"           /* DIE */
+#define TOK_DIE                "R"             /* 82 */
+#define        MSG_HASH        "HASH"          /* HASH */
+#define TOK_HASH       "S"             /* 83 */
+#define        MSG_DNS         "DNS"           /* DNS  -> DNSS */
+#define TOK_DNS                "T"             /* 84 */
+#define MSG_SILENCE    "SILENCE"       /* SILE */
+#define TOK_SILENCE    "U"             /* 85 */
+#define MSG_AKILL      "AKILL"         /* AKILL */
+#define TOK_AKILL      "V"             /* 86 */
+#define MSG_KLINE      "KLINE"         /* KLINE */
+#define TOK_KLINE      "W"             /* 87 */
+#define MSG_UNKLINE     "UNKLINE"       /* UNKLINE */
+#define TOK_UNKLINE    "X"             /* 88 */
+#define MSG_RAKILL     "RAKILL"        /* RAKILL */
+#define TOK_RAKILL     "Y"             /* 89 */
+#define MSG_GNOTICE    "GNOTICE"       /* GNOTICE */
+#define TOK_GNOTICE    "Z"             /* 90 */
+#define MSG_GOPER      "GOPER"         /* GOPER */
+#define TOK_GOPER      "["             /* 91 */
+#define MSG_GLOBOPS    "GLOBOPS"       /* GLOBOPS */
+#define TOK_GLOBOPS    "]"             /* 93 */
+#define MSG_LOCOPS     "LOCOPS"        /* LOCOPS */
+#define TOK_LOCOPS     "^"             /* 94 */
+#define MSG_PROTOCTL   "PROTOCTL"      /* PROTOCTL */
+#define TOK_PROTOCTL   "_"             /* 95 */
+#define MSG_WATCH      "WATCH"         /* WATCH */
+#define TOK_WATCH      "`"             /* 96 */
+#define MSG_TRACE      "TRACE"         /* TRAC */
+#define TOK_TRACE      "b"             /* 97 */
+#define MSG_SQLINE     "SQLINE"        /* SQLINE */
+#define TOK_SQLINE     "c"             /* 98 */
+#define MSG_UNSQLINE   "UNSQLINE"      /* UNSQLINE */
+#define TOK_UNSQLINE   "d"             /* 99 */
+#define MSG_SVSNICK    "SVSNICK"       /* SVSNICK */
+#define TOK_SVSNICK    "e"             /* 100 */
+#define MSG_SVSNOOP    "SVSNOOP"       /* SVSNOOP */
+#define TOK_SVSNOOP    "f"             /* 101 */
+#define MSG_IDENTIFY   "IDENTIFY"      /* IDENTIFY */
+#define TOK_IDENTIFY   "g"             /* 102 */
+#define MSG_SVSKILL    "SVSKILL"       /* SVSKILL */
+#define TOK_SVSKILL    "h"             /* 103 */
+#define MSG_NICKSERV   "NICKSERV"      /* NICKSERV */
+#define MSG_NS         "NS"
+#define TOK_NICKSERV   "i"             /* 104 */
+#define MSG_CHANSERV   "CHANSERV"      /* CHANSERV */
+#define MSG_CS         "CS"
+#define TOK_CHANSERV   "j"             /* 105 */
+#define MSG_OPERSERV   "OPERSERV"      /* OPERSERV */
+#define MSG_OS         "OS"
+#define TOK_OPERSERV   "k"             /* 106 */
+#define MSG_MEMOSERV   "MEMOSERV"      /* MEMOSERV */
+#define MSG_MS         "MS"
+#define TOK_MEMOSERV   "l"             /* 107 */
+#define MSG_SERVICES   "SERVICES"      /* SERVICES */
+#define TOK_SERVICES   "m"             /* 108 */
+#define MSG_SVSMODE    "SVSMODE"       /* SVSMODE */
+#define TOK_SVSMODE    "n"             /* 109 */
+#define MSG_SAMODE     "SAMODE"        /* SAMODE */
+#define TOK_SAMODE     "o"             /* 110 */
+#define MSG_CHATOPS    "CHATOPS"       /* CHATOPS */
+#define TOK_CHATOPS    "p"             /* 111 */
+#define MSG_ZLINE      "ZLINE"         /* ZLINE */
+#define TOK_ZLINE      "q"             /* 112 */
+#define MSG_UNZLINE    "UNZLINE"       /* UNZLINE */                           
+#define TOK_UNZLINE    "r"             /* 113 */
+#define MSG_HELPSERV    "HELPSERV"      /* HELPSERV */
+#define MSG_HS         "HS"
+#define TOK_HELPSERV    "s"             /* 114 */
+#define MSG_RULES       "RULES"         /* RULES */
+#define TOK_RULES       "t"             /* 115 */
+#define MSG_MAP         "MAP"           /* MAP */
+#define TOK_MAP         "u"             /* 117 */
+#define MSG_SVS2MODE    "SVS2MODE"      /* SVS2MODE */
+#define TOK_SVS2MODE   "v"             /* 118 */
+#define MSG_DALINFO     "DALINFO"       /* dalinfo */
+#define TOK_DALINFO     "w"             /* 119 */
+#define MSG_ADMINCHAT   "ADCHAT"        /* Admin chat */
+#define TOK_ADMINCHAT   "x"             /* 120 */
+#define MSG_MKPASSWD   "MKPASSWD"      /* MKPASSWD */
+#define TOK_MKPASSWD   "y"             /* 121 */
+#define MSG_ADDLINE     "ADDLINE"       /* ADDLINE */
+#define TOK_ADDLINE     "z"             /* 122 */
+#define MSG_GLINE      "GLINE"         /* The awesome g-line */
+#define TOK_GLINE      "}"             /* 125 */
+#define MSG_SJOIN      "SJOIN"
+#define TOK_SJOIN      "~"
+#define MSG_SETHOST    "SETHOST"   /* sethost */
+#define TOK_SETHOST    "AA"         /* 127 4ever !;) */
+#define MSG_TECHAT     "TECHAT"    /* techadmin chat */
+#define TOK_TECHAT     "AB"         /* questionmark? */
+#define MSG_NACHAT     "NACHAT"    /* netadmin chat */
+#define TOK_NACHAT     "AC"         /* *beep* */
+#define MSG_SETIDENT   "SETIDENT" /* set ident */
+#define        TOK_SETIDENT    "AD"        /* good old BASIC ;P */
+#define MSG_SETNAME    "SETNAME"   /* set GECOS */
+#define TOK_SETNAME    "AE"                /* its almost unreeaaall... */
+#define MSG_LAG                "LAG"           /* Lag detect */
+#define TOK_LAG                "AF"            /* a or ? */
+#define MSG_SDESC       "SDESC"     /* set description */
+#define TOK_SDESC       "AG"
+#define MSG_STATSERV   "STATSERV" /* alias */
+#define TOK_STATSERV   "AH" 
+#define MSG_KNOCK      "KNOCK"
+#define TOK_KNOCK      "AI"
+#define MSG_CREDITS    "CREDITS"
+#define TOK_CREDITS    "AJ"
+#define MSG_LICENSE    "LICENSE"
+#define TOK_LICENSE    "AK"
+#define MSG_CHGHOST    "CHGHOST"
+#define TOK_CHGHOST    "AL"
+#define MSG_RPING      "RPING"
+#define TOK_RPING      "AM"
+#define MSG_RPONG      "RPONG"
+#define TOK_RPONG      "AN"
+#define MSG_NETINFO    "NETINFO"
+#define TOK_NETINFO    "AO"
+#define MSG_SENDUMODE  "SENDUMODE"
+#define TOK_SENDUMODE  "AP"
+#define MSG_ADDMOTD    "ADDMOTD"
+#define TOK_ADDMOTD    "AQ"
+#define MSG_ADDOMOTD   "ADDOMOTD"
+#define TOK_ADDOMOTD   "AR"
+#define MSG_SVSMOTD    "SVSMOTD"
+#define TOK_SVSMOTD    "AS"
+#define MSG_DUSERS     "DUSERS"
+#define TOK_DUSERS     "AT"
+#define MSG_SMO        "SMO"
+#define TOK_SMO        "AU"
+#define MSG_OPERMOTD   "OPERMOTD"
+#define TOK_OPERMOTD   "AV"
+#define MSG_TSCTL      "TSCTL"
+#define TOK_TSCTL      "AW"
+#define MSG_SVSJOIN    "SVSJOIN"
+#define TOK_SVSJOIN    "AX"
+#define MSG_SAJOIN     "SAJOIN"
+#define TOK_SAJOIN     "AY"
+#define MSG_SVSPART    "SVSPART"
+#define TOK_SVSPART    "AX"
+#define MSG_SAPART     "SAPART"
+#define TOK_SAPART     "AY"
+#define MSG_CHGIDENT   "CHGIDENT"
+#define TOK_CHGIDENT   "AZ"
+#define MSG_SWHOIS     "SWHOIS"
+#define TOK_SWHOIS     "BA"
+#define MSG_SVSO       "SVSO"
+#define TOK_SVSO       "BB"
+#define MSG_SVSFLINE   "SVSFLINE"
+#define TOK_SVSFLINE   "BC"
+#define MSG_TKL                "TKL"
+#define TOK_TKL        "BD"
+#define MSG_VHOST      "VHOST"
+#define TOK_VHOST      "BE"
+#define MSG_BOTMOTD    "BOTMOTD"
+#define TOK_BOTMOTD    "BF"
+#define MSG_REMGLINE   "REMGLINE"      /* remove g-line */
+#define TOK_REMGLINE   "BG"            
+#define MSG_HTM                "HTM"
+#define TOK_HTM                "BH"
+#define MAXPARA        15 
+
+
+extern int m_private(), m_topic(), m_join(), m_part(), m_mode(), m_svsmode();
+extern int m_ping(), m_pong(), m_wallops(), m_kick(), m_svsnick();
+extern int m_nick(), m_error(), m_notice(), m_samode(), m_svsnoop();
+extern int m_invite(), m_quit(), m_kill(), m_svskill(), m_identify();
+extern int m_akill(), m_kline(), m_unkline(), m_rakill(), m_sqline();
+extern int m_zline(), m_unzline();
+extern int m_gnotice(), m_goper(), m_globops(), m_locops(), m_unsqline(), m_chatops();
+extern int m_protoctl();
+extern int m_motd(), m_who(), m_whois(), m_user(), m_list();
+extern int m_server(), m_info(), m_links(), m_summon(), m_stats();
+extern int m_users(), m_version(), m_help();
+extern int m_nickserv(), m_operserv(), m_chanserv(), m_memoserv(), m_helpserv(), m_services(), m_identify();
+extern int m_statserv();
+extern int m_squit(), m_away(), m_connect();
+extern int m_oper(), m_pass(), m_trace();
+extern int m_time(), m_names(), m_admin();
+extern int m_lusers(), m_umode(), m_close();
+extern int m_motd(), m_whowas(), m_silence();
+extern int m_service(), m_userhost(), m_ison(), m_watch();
+extern int m_service(), m_servset(), m_servlist(), m_squery();
+extern int m_rehash(), m_restart(), m_die(), m_dns(), m_hash();
+/*extern int m_noshortn(),m_noshortc(),m_noshortm(),m_noshorto(),m_noshorth();*/
+
+extern int m_gline(), m_remgline(), m_map(), m_svs2mode(), m_admins(), m_dalinfo();
+extern int m_addline(), m_rules(), m_mkpasswd();
+extern int m_sethost(), m_nachat(), m_techat(), m_setident(), m_setname();
+extern int m_lag(), m_sdesc(), m_knock(), m_credits();
+extern int m_license(), m_chghost(), m_rping(), m_rpong();
+extern int m_netinfo(), m_sendumode(), m_addmotd(), m_addomotd();
+extern int m_svsmotd(), m_dusers(), m_opermotd(), m_tsctl();
+extern int m_svsjoin(), m_sajoin(), m_svspart(), m_sapart();
+extern int m_chgident(), m_swhois(), m_svso(), m_svsfline();
+extern int m_tkl(), m_vhost(), m_botmotd(), m_sjoin(), m_htm();
+
+#ifdef MSGTAB
+struct Message *msgmap[256];
+struct Message msgtab[] = {
+  { MSG_PRIVATE, m_private,  0, MAXPARA, 1, TOK_PRIVATE, 0L },
+  { MSG_NICK,    m_nick,     0, MAXPARA, 1, TOK_NICK,    0L },
+  { MSG_NOTICE,  m_notice,   0, MAXPARA, 1, TOK_NOTICE,  0L },
+  { MSG_JOIN,    m_join,     0, MAXPARA, 1, TOK_JOIN,    0L },
+  { MSG_MODE,    m_mode,     0, MAXPARA, 1, TOK_MODE,    0L },
+  { MSG_QUIT,    m_quit,     0, MAXPARA, 1, TOK_QUIT,    0L },
+  { MSG_PART,    m_part,     0, MAXPARA, 1, TOK_PART,    0L },
+  { MSG_TOPIC,   m_topic,    0, MAXPARA, 1, TOK_TOPIC,   0L },
+  { MSG_INVITE,  m_invite,   0, MAXPARA, 1, TOK_INVITE,  0L },
+  { MSG_KICK,    m_kick,     0, MAXPARA, 1, TOK_KICK,    0L },
+  { MSG_WALLOPS, m_wallops,  0, 1,       1, TOK_WALLOPS, 0L },
+  { MSG_PING,    m_ping,     0, MAXPARA, 1, TOK_PING,    0L },
+  { MSG_PONG,    m_pong,     0, MAXPARA, 1, TOK_PONG,    0L },
+  { MSG_ERROR,   m_error,    0, MAXPARA, 1, TOK_ERROR,   0L },
+  { MSG_KILL,    m_kill,     0, MAXPARA, 1, TOK_KILL,    0L },
+  { MSG_PROTOCTL,m_protoctl, 0, MAXPARA, 1, TOK_PROTOCTL,0L },
+  { MSG_USER,    m_user,     0, MAXPARA, 1, TOK_USER,    0L },
+  { MSG_AWAY,    m_away,     0, MAXPARA, 1, TOK_AWAY,    0L },
+  { MSG_ISON,    m_ison,     0, 1,       1, TOK_ISON,    0L },
+  { MSG_WATCH,   m_watch,    0, 1,       1, TOK_WATCH,   0L }, 
+  { MSG_SERVER,  m_server,   0, MAXPARA, 1, TOK_SERVER,  0L },
+  { MSG_SQUIT,   m_squit,    0, MAXPARA, 1, TOK_SQUIT,   0L },
+  { MSG_WHOIS,   m_whois,    0, MAXPARA, 1, TOK_WHOIS,   0L },
+  { MSG_WHO,     m_who,      0, MAXPARA, 1, TOK_WHO,     0L },
+  { MSG_WHOWAS,  m_whowas,   0, MAXPARA, 1, TOK_WHOWAS,  0L },
+  { MSG_LIST,    m_list,     0, MAXPARA, 1, TOK_LIST,    0L },
+  { MSG_NAMES,   m_names,    0, MAXPARA, 1, TOK_NAMES,   0L },
+  { MSG_USERHOST,m_userhost, 0, 1,       1, TOK_USERHOST,0L },
+  { MSG_TRACE,   m_trace,    0, MAXPARA, 1, TOK_TRACE,   0L },
+  { MSG_PASS,    m_pass,     0, MAXPARA, 1, TOK_PASS,    0L },
+  { MSG_LUSERS,  m_lusers,   0, MAXPARA, 1, TOK_LUSERS,  0L },
+  { MSG_TIME,    m_time,     0, MAXPARA, 1, TOK_TIME,    0L },
+  { MSG_OPER,    m_oper,     0, MAXPARA, 1, TOK_OPER,    0L },
+  { MSG_CONNECT, m_connect,  0, MAXPARA, 1, TOK_CONNECT, 0L },
+  { MSG_VERSION, m_version,  0, MAXPARA, 1, TOK_VERSION, 0L },
+  { MSG_STATS,   m_stats,    0, MAXPARA, 1, TOK_STATS,   0L },
+  { MSG_LINKS,   m_links,    0, MAXPARA, 1, TOK_LINKS,   0L },
+  { MSG_ADMIN,   m_admin,    0, MAXPARA, 1, TOK_ADMIN,   0L },
+  { MSG_USERS,   m_users,    0, MAXPARA, 1, TOK_USERS,   0L },
+  { MSG_SVSMODE, m_svsmode,  0, MAXPARA, 1, TOK_SVSMODE, 0L },
+  { MSG_SAMODE,  m_samode,   0, MAXPARA, 1, TOK_SAMODE,  0L },
+  { MSG_SVSKILL, m_svskill,  0, MAXPARA, 1, TOK_SVSKILL, 0L },
+  { MSG_SVSNICK, m_svsnick,  0, MAXPARA, 1, TOK_SVSNICK, 0L },
+  { MSG_SVSNOOP, m_svsnoop,  0, MAXPARA, 1, TOK_SVSNOOP, 0L },
+  { MSG_CHANSERV,m_chanserv, 0, 1,       1, TOK_CHANSERV,0L },
+ /* { MSG_CS,   m_noshortc, 0, 1,       1, TOK_CHANSERV,0L }, */
+  { MSG_NICKSERV,m_nickserv, 0, 1,       1, TOK_NICKSERV,0L },
+ /* { MSG_NS,   m_noshortn, 0, 1,       1, TOK_NICKSERV,0L }, */
+  { MSG_OPERSERV,m_operserv, 0, 1,       1, TOK_OPERSERV,0L },
+ /* { MSG_OS,   m_noshorto, 0, 1,       1, TOK_OPERSERV,0L }, */
+  { MSG_MEMOSERV,m_memoserv, 0, 1,       1, TOK_MEMOSERV,0L },
+  /*{ MSG_MS,   m_noshortm, 0, 1,       1, TOK_MEMOSERV,0L }, */
+  { MSG_HELPSERV,m_helpserv, 0, 1,      1, TOK_HELPSERV,0L },
+ /* { MSG_HS,   m_noshorth, 0, 1,       1, TOK_HELPSERV,0L }, */
+  { MSG_SERVICES,m_services, 0, 1,       1, TOK_SERVICES,0L },
+  { MSG_IDENTIFY,m_identify, 0, 1,       1, TOK_IDENTIFY,0L },
+  { MSG_SUMMON,  m_summon,   0, MAXPARA, 1, TOK_SUMMON,  0L },
+  { MSG_HELP,    m_help,     0, 1,       1, TOK_HELP,    0L },
+  { MSG_HELPOP,  m_help,     0, 1,       1, TOK_HELP,    0L },
+  { MSG_INFO,    m_info,     0, MAXPARA, 1, TOK_INFO,    0L },
+  { MSG_MOTD,    m_motd,     0, MAXPARA, 1, TOK_MOTD,    0L },
+  { MSG_CLOSE,   m_close,    0, MAXPARA, 1, TOK_CLOSE,   0L },
+  { MSG_SILENCE, m_silence,  0, MAXPARA, 1, TOK_SILENCE, 0L },
+  { MSG_AKILL,   m_akill,    0, MAXPARA, 1, TOK_AKILL,   0L },
+  { MSG_SQLINE,  m_sqline,   0, MAXPARA, 1, TOK_SQLINE,  0L },
+  { MSG_UNSQLINE,m_unsqline, 0, MAXPARA, 1, TOK_UNSQLINE,0L },
+  { MSG_KLINE,   m_kline,    0, MAXPARA, 1, TOK_KLINE,   0L },
+  { MSG_UNKLINE, m_unkline,  0, MAXPARA, 1, TOK_UNKLINE, 0L },
+  { MSG_ZLINE,   m_zline,    0, MAXPARA, 1, TOK_ZLINE,   0L },
+  { MSG_UNZLINE, m_unzline,  0, MAXPARA, 1, TOK_UNZLINE, 0L },
+  { MSG_RAKILL,  m_rakill,   0, MAXPARA, 1, TOK_RAKILL,  0L },
+  { MSG_GNOTICE, m_gnotice,  0, MAXPARA, 1, TOK_GNOTICE, 0L },
+  { MSG_GOPER,   m_goper,    0, MAXPARA, 1, TOK_GOPER,   0L },
+  { MSG_GLOBOPS, m_globops,  0, MAXPARA, 1, TOK_GLOBOPS, 0L },
+  { MSG_CHATOPS, m_chatops,  0, 1,       1, TOK_CHATOPS, 0L },
+  { MSG_LOCOPS,  m_locops,   0, 1,       1, TOK_LOCOPS,  0L },
+  { MSG_HASH,    m_hash,     0, MAXPARA, 1, TOK_HASH,    0L },
+  { MSG_DNS,     m_dns,      0, MAXPARA, 1, TOK_DNS,     0L },
+  { MSG_REHASH,  m_rehash,   0, MAXPARA, 1, TOK_REHASH,  0L },
+  { MSG_RESTART, m_restart,  0, MAXPARA, 1, TOK_RESTART, 0L },
+  { MSG_DIE,     m_die,      0, MAXPARA, 1, TOK_DIE,     0L },
+  { MSG_RULES,  m_rules,    0, MAXPARA, 1, TOK_RULES,   0L },
+  { MSG_MAP,    m_map,      0, MAXPARA, 1, TOK_MAP,     0L },
+  { MSG_GLINE,   m_gline,    0, MAXPARA, 1, TOK_GLINE,   0L },
+  { MSG_REMGLINE,m_remgline, 0, MAXPARA, 1, TOK_REMGLINE,0L },
+  { MSG_DALINFO, m_dalinfo,  0, MAXPARA, 1, TOK_DALINFO, 0L },
+  { MSG_SVS2MODE,m_svs2mode, 0, MAXPARA, 1, TOK_SVS2MODE,0L },
+  { MSG_MKPASSWD, m_mkpasswd, 0, MAXPARA, 1, TOK_MKPASSWD, 0L },
+  { MSG_ADDLINE, m_addline,  0, 1, 1, TOK_ADDLINE,   0L },
+  { MSG_ADMINCHAT, m_admins, 0, 1,       1, TOK_ADMINCHAT,    0L },
+  { MSG_SETHOST, m_sethost,  0, MAXPARA, 1, TOK_SETHOST,   0L },
+  { MSG_TECHAT,  m_techat,   0, 1,       1, TOK_TECHAT,    0L },
+  { MSG_NACHAT,  m_nachat,   0, 1,       1, TOK_NACHAT,    0L },
+  { MSG_SETIDENT, m_setident,0, MAXPARA, 1, TOK_SETIDENT,  0L },
+  { MSG_SETNAME, m_setname,  0, 1, 1, TOK_SETNAME,   0L },
+  { MSG_LAG,    m_lag,      0, MAXPARA, 1, TOK_LAG,       0L },
+  { MSG_SDESC,   m_sdesc,    0, 1, 1, TOK_SDESC,     0L },
+  { MSG_STATSERV,m_statserv, 0, 1,       1, TOK_STATSERV,0L },
+  { MSG_KNOCK, m_knock,      0, 2, 1, TOK_KNOCK,     0L },
+  { MSG_CREDITS, m_credits,  0, MAXPARA, 1, TOK_CREDITS,   0L },
+  { MSG_LICENSE, m_license,  0, MAXPARA, 1, TOK_LICENSE,   0L },
+  { MSG_CHGHOST, m_chghost,  0, MAXPARA, 1, TOK_CHGHOST,   0L },
+  { MSG_RPING, m_rping,  0, MAXPARA, 1, TOK_RPING,   0L },
+  { MSG_RPONG, m_rpong,  0, MAXPARA, 1, TOK_RPONG,   0L },
+  { MSG_NETINFO, m_netinfo, 0, MAXPARA, 1, TOK_NETINFO, 0L},
+  { MSG_SENDUMODE, m_sendumode, 0, MAXPARA, 1, TOK_SENDUMODE, 0L},
+  { MSG_SMO, m_sendumode, 0, MAXPARA, 1, TOK_SMO, 0L},
+  { MSG_ADDMOTD, m_addmotd, 0, 1, 1, TOK_ADDMOTD, 0L},
+  { MSG_ADDOMOTD, m_addomotd, 0, 1, 1, TOK_ADDOMOTD, 0L},
+  { MSG_SVSMOTD, m_svsmotd, 0, MAXPARA, 1, TOK_SVSMOTD, 0L},
+  { MSG_DUSERS, m_dusers, 0, MAXPARA, 1, TOK_DUSERS, 0L},
+  { MSG_OPERMOTD, m_opermotd, 0, MAXPARA, 1, TOK_OPERMOTD, 0L},
+  { MSG_TSCTL, m_tsctl, 0, MAXPARA, 1, TOK_TSCTL, 0L},
+  { MSG_SVSJOIN, m_svsjoin, 0, MAXPARA, 1, TOK_SVSJOIN, 0L},
+  { MSG_SAJOIN, m_sajoin, 0, MAXPARA, 1, TOK_SAJOIN,0L},
+  { MSG_SVSPART, m_svspart, 0, MAXPARA, 1, TOK_SVSPART, 0L},
+  { MSG_SAPART, m_sapart, 0, MAXPARA, 1, TOK_SAPART,0L},
+  { MSG_CHGIDENT, m_chgident,0, MAXPARA, 1, TOK_CHGIDENT,0L},
+  { MSG_SWHOIS, m_swhois, 0, MAXPARA, 1, TOK_SWHOIS, 0L},
+  { MSG_SVSO, m_svso, 0, MAXPARA, 1, TOK_SVSO, 0L},
+  { MSG_SVSFLINE, m_svsfline, 0, MAXPARA,1,TOK_SVSFLINE,0L},
+  { MSG_TKL, m_tkl, 0, MAXPARA,1,TOK_TKL,0L},
+  { MSG_VHOST, m_vhost, 0, MAXPARA,1,TOK_VHOST,0L},
+  { MSG_BOTMOTD, m_botmotd, 0, MAXPARA,1,TOK_BOTMOTD,0L},
+  { MSG_SJOIN, m_sjoin, 0, MAXPARA, 1, TOK_SJOIN,0L},
+  { MSG_HTM, m_htm, 0, MAXPARA, 1, TOK_HTM, 0L},
+  { (char *) 0, (int (*)()) 0 , 0, 0, 0, 0, 0L}
+};
+
+#else
+extern struct Message msgtab[];
+extern struct Message *msgmap[256];
+#endif
+#endif /* __msg_include__ */
diff --git a/include/nameser.h b/include/nameser.h
new file mode 100644 (file)
index 0000000..a479577
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 1983, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  $Id$
+ *     @(#)nameser.h   5.24 (Berkeley) 6/1/90
+ */
+
+/*
+ * Define constants based on rfc883
+ */
+#define PACKETSZ       512             /* maximum packet size */
+#define MAXDNAME       256             /* maximum domain name */
+#define MAXCDNAME      255             /* maximum compressed domain name */
+#define MAXLABEL       63              /* maximum length of domain label */
+       /* Number of bytes of fixed size data in query structure */
+#define QFIXEDSZ       4
+       /* number of bytes of fixed size data in resource record */
+#define RRFIXEDSZ      10
+
+/*
+ * Internet nameserver port number
+ */
+#define NAMESERVER_PORT        53
+
+/*
+ * Currently defined opcodes
+ */
+#define QUERY          0x0             /* standard query */
+#define IQUERY         0x1             /* inverse query */
+#define STATUS         0x2             /* nameserver status query */
+/*#define xxx          0x3             /* 0x3 reserved */
+       /* non standard */
+#define UPDATEA                0x9             /* add resource record */
+#define UPDATED                0xa             /* delete a specific resource record */
+#define UPDATEDA       0xb             /* delete all nemed resource record */
+#define UPDATEM                0xc             /* modify a specific resource record */
+#define UPDATEMA       0xd             /* modify all named resource record */
+
+#define ZONEINIT       0xe             /* initial zone transfer */
+#define ZONEREF                0xf             /* incremental zone referesh */
+
+/*
+ * Currently defined response codes
+ */
+#ifdef NOERROR                         /* defined by solaris2 in */
+#undef NOERROR                         /* <sys/stream.h> to be -1 */
+#endif
+#define NOERROR                0               /* no error */
+#define FORMERR                1               /* format error */
+#define SERVFAIL       2               /* server failure */
+#define NXDOMAIN       3               /* non existent domain */
+#define NOTIMP         4               /* not implemented */
+#define REFUSED                5               /* query refused */
+       /* non standard */
+#define NOCHANGE       0xf             /* update failed to change db */
+
+/*
+ * Type values for resources and queries
+ */
+#define T_A            1               /* host address */
+#define T_NS           2               /* authoritative server */
+#define T_MD           3               /* mail destination */
+#define T_MF           4               /* mail forwarder */
+#define T_CNAME                5               /* connonical name */
+#define T_SOA          6               /* start of authority zone */
+#define T_MB           7               /* mailbox domain name */
+#define T_MG           8               /* mail group member */
+#define T_MR           9               /* mail rename name */
+#define T_NULL         10              /* null resource record */
+#define T_WKS          11              /* well known service */
+#define T_PTR          12              /* domain name pointer */
+#define T_HINFO                13              /* host information */
+#define T_MINFO                14              /* mailbox information */
+#define T_MX           15              /* mail routing information */
+#define T_TXT          16              /* text strings */
+       /* non standard */
+#define T_UINFO                100             /* user (finger) information */
+#define T_UID          101             /* user ID */
+#define T_GID          102             /* group ID */
+#define T_UNSPEC       103             /* Unspecified format (binary data) */
+       /* Query type values which do not appear in resource records */
+#define T_AXFR         252             /* transfer zone of authority */
+#define T_MAILB                253             /* transfer mailbox records */
+#define T_MAILA                254             /* transfer mail agent records */
+#define T_ANY          255             /* wildcard match */
+
+/*
+ * Values for class field
+ */
+
+#define C_IN           1               /* the arpa internet */
+#define C_CHAOS                3               /* for chaos net at MIT */
+#define C_HS           4               /* for Hesiod name server at MIT */
+       /* Query class values which do not appear in resource records */
+#define C_ANY          255             /* wildcard match */
+
+/*
+ * Status return codes for T_UNSPEC conversion routines
+ */
+#define CONV_SUCCESS 0
+#define CONV_OVERFLOW -1
+#define CONV_BADFMT -2
+#define CONV_BADCKSUM -3
+#define CONV_BADBUFLEN -4
+
+#ifndef BYTE_ORDER
+#define        LITTLE_ENDIAN   1234    /* least-significant byte first (vax) */
+#define        BIG_ENDIAN      4321    /* most-significant byte first (IBM, net) */
+#define        PDP_ENDIAN      3412    /* LSB first in word, MSW first in long (pdp) */
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(MIPSEL) || \
+    defined(BIT_ZERO_ON_RIGHT) || defined(sequent) || defined(i386) ||\
+    defined(___vax__) || defined(__ns32000__) || defined(__sun386__) ||\
+    defined(__alpha) || defined(_WIN32)
+#define BYTE_ORDER     LITTLE_ENDIAN
+
+#endif
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+    defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+    defined(MIPSEB) || defined(__hpux) || defined(__convex__) || \
+    defined(__pyr__) || defined(__mc68000__) || defined(__sparc__) ||\
+    defined(_IBMR2) || defined (BIT_ZERO_ON_LEFT)
+#define BYTE_ORDER     BIG_ENDIAN
+#endif
+#endif /* BYTE_ORDER */
+
+#ifndef BYTE_ORDER
+/* you must determine what the correct bit order is for your compiler */
+       UNDEFINED_BIT_ORDER;
+#endif
+/*
+ * Structure for query header, the order of the fields is machine and
+ * compiler dependent, in our case, the bits within a byte are assignd 
+ * least significant first, while the order of transmition is most 
+ * significant first.  This requires a somewhat confusing rearrangement.
+ */
+
+typedef struct {
+       u_short id;             /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+                       /* fields in third byte */
+       u_char  qr:1;           /* response flag */
+       u_char  opcode:4;       /* purpose of message */
+       u_char  aa:1;           /* authoritive answer */
+       u_char  tc:1;           /* truncated message */
+       u_char  rd:1;           /* recursion desired */
+                       /* fields in fourth byte */
+       u_char  ra:1;           /* recursion available */
+       u_char  pr:1;   /* primary server required (non standard) */
+       u_char  unused:2;       /* unused bits */
+       u_char  rcode:4;        /* response code */
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+                       /* fields in third byte */
+       u_char  rd:1;           /* recursion desired */
+       u_char  tc:1;           /* truncated message */
+       u_char  aa:1;           /* authoritive answer */
+       u_char  opcode:4;       /* purpose of message */
+       u_char  qr:1;           /* response flag */
+                       /* fields in fourth byte */
+       u_char  rcode:4;        /* response code */
+       u_char  unused:2;       /* unused bits */
+       u_char  pr:1;   /* primary server required (non standard) */
+       u_char  ra:1;           /* recursion available */
+#endif
+                       /* remaining bytes */
+       u_short qdcount;        /* number of question entries */
+       u_short ancount;        /* number of answer entries */
+       u_short nscount;        /* number of authority entries */
+       u_short arcount;        /* number of resource entries */
+} HEADER;
+
+/*
+ * Defines for handling compressed domain names
+ */
+#define INDIR_MASK     0xc0
+
+/*
+ * Structure for passing resource records around.
+ */
+struct rrec {
+       short   r_zone;                 /* zone number */
+       short   r_class;                /* class number */
+       short   r_type;                 /* type number */
+#ifdef __alpha
+       u_int   r_ttl;                  /* time to live */
+#else
+       u_long  r_ttl;                  /* time to live */
+#endif
+       int     r_size;                 /* size of data area */
+       char    *r_data;                /* pointer to data */
+};
+
+extern u_short _getshort();
+#ifdef __alpha
+extern u_int   _getlong();
+#else
+extern u_long  _getlong();
+#endif
+
+/*
+ * Inline versions of get/put short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETSHORT(s, cp) { \
+       (s) = *(cp)++ << 8; \
+       (s) |= *(cp)++; \
+}
+
+#define GETLONG(l, cp) { \
+       (l) = *(cp)++ << 8; \
+       (l) |= *(cp)++; (l) <<= 8; \
+       (l) |= *(cp)++; (l) <<= 8; \
+       (l) |= *(cp)++; \
+}
+
+
+#define PUTSHORT(s, cp) { \
+       *(cp)++ = (s) >> 8; \
+       *(cp)++ = (s); \
+}
+
+/*
+ * Warning: PUTLONG destroys its first argument.
+ */
+#define PUTLONG(l, cp) { \
+       (cp)[3] = l; \
+       (cp)[2] = (l >>= 8); \
+       (cp)[1] = (l >>= 8); \
+       (cp)[0] = l >> 8; \
+       (cp) += sizeof(u_long); \
+}
diff --git a/include/numeric.h b/include/numeric.h
new file mode 100644 (file)
index 0000000..6fc23f5
--- /dev/null
@@ -0,0 +1,307 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/numeric.h
+ *   Copyright (C) 1990 Jarkko Oikarinen
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *   $Id$
+ */
+
+/*
+ * -- Potvin -- Feb 20/98
+ *
+ * Added numerics 600-799 as numeric_replies2[], we ran out
+ */
+
+/*
+ * 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.
+ */
+
+#define        RPL_WELCOME          001
+#define        RPL_YOURHOST         002
+#define        RPL_CREATED          003
+#define        RPL_MYINFO           004
+#define RPL_PROTOCTL        005
+
+/*
+ * Errors are in the range from 400-599 currently and are grouped by what
+ * commands they come from.
+ */
+#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_NOSUCHSERVICE    408
+#define        ERR_NOORIGIN         409
+
+#define ERR_NORECIPIENT      411
+#define ERR_NOTEXTTOSEND     412
+#define ERR_NOTOPLEVEL       413
+#define ERR_WILDTOPLEVEL     414
+
+#define ERR_UNKNOWNCOMMAND   421
+#define        ERR_NOMOTD           422
+#define        ERR_NOADMININFO      423
+#define        ERR_FILEERROR        424
+#define ERR_NOOPERMOTD      425
+#define ERR_NONICKNAMEGIVEN  431
+#define ERR_ERRONEUSNICKNAME 432
+#define ERR_NICKNAMEINUSE    433
+#define ERR_NORULES          434
+#define ERR_SERVICECONFUSED  435
+#define        ERR_NICKCOLLISION    436
+#define ERR_BANNICKCHANGE    437
+#define ERR_NCHANGETOOFAST   438
+#define ERR_TARGETTOOFAST    439
+#define ERR_SERVICESDOWN     440
+
+#define ERR_USERNOTINCHANNEL 441
+#define ERR_NOTONCHANNEL     442
+#define        ERR_USERONCHANNEL    443
+#define ERR_NOLOGIN          444
+#define        ERR_SUMMONDISABLED   445
+#define ERR_USERSDISABLED    446
+
+#define ERR_NOTREGISTERED    451
+
+#define ERR_HOSTILENAME      455
+
+#define ERR_NOHIDING        459
+#define ERR_NOTFORHALFOPS       460
+#define ERR_NEEDMOREPARAMS   461
+#define ERR_ALREADYREGISTRED 462
+#define ERR_NOPERMFORHOST    463
+#define ERR_PASSWDMISMATCH   464
+#define ERR_YOUREBANNEDCREEP 465
+#define ERR_YOUWILLBEBANNED  466
+#define        ERR_KEYSET           467
+#define ERR_ONLYSERVERSCANCHANGE 468
+#define ERR_LINKSET         469
+#define ERR_LINKCHANNEL             470
+#define ERR_CHANNELISFULL    471
+#define ERR_UNKNOWNMODE      472
+#define ERR_INVITEONLYCHAN   473
+#define ERR_BANNEDFROMCHAN   474
+#define        ERR_BADCHANNELKEY    475
+#define        ERR_BADCHANMASK      476
+#define ERR_NEEDREGGEDNICK   477
+#define ERR_BANLISTFULL      478
+#define ERR_LINKFAIL        479
+#define ERR_CANNOTKNOCK                 480
+
+#define ERR_NOPRIVILEGES     481
+#define ERR_CHANOPRIVSNEEDED 482
+#define        ERR_CANTKILLSERVER   483
+#define ERR_ATTACKDENY       484
+#define ERR_KILLDENY        485
+
+#define ERR_NOOPERHOST       491
+#define ERR_NOSERVICEHOST    492
+
+#define ERR_UMODEUNKNOWNFLAG 501
+#define ERR_USERSDONTMATCH   502
+
+#define ERR_SILELISTFULL     511
+#define ERR_TOOMANYWATCH     512
+#define ERR_NEEDPONG         513
+
+#define ERR_NOINVITE            518
+#define ERR_ADMONLY                     519
+#define ERR_OPERONLY            520
+#define ERR_LISTSYNTAX       521
+
+/*
+ * 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_WHOISREGNICK     307
+#define RPL_RULESSTART       308
+#define RPL_ENDOFRULES       309
+#define RPL_WHOISHELPOP      310 /* -Donwulff */
+
+#define RPL_WHOISUSER        311
+#define RPL_WHOISSERVER      312
+#define RPL_WHOISOPERATOR    313
+
+#define RPL_WHOWASUSER       314
+/* rpl_endofwho below (315) */
+#define        RPL_ENDOFWHOWAS      369
+
+#define RPL_WHOISCHANOP      316 /* redundant and not needed but reserved */
+#define RPL_WHOISIDLE        317
+
+#define RPL_ENDOFWHOIS       318
+#define RPL_WHOISCHANNELS    319
+#define RPL_WHOISSPECIAL     320
+#define RPL_LISTSTART        321
+#define RPL_LIST             322
+#define RPL_LISTEND          323
+#define RPL_CHANNELMODEIS    324
+#define RPL_CREATIONTIME     329
+#define RPL_NOTOPIC          331
+#define RPL_TOPIC            332
+#define RPL_TOPICWHOTIME     333
+
+#define RPL_LISTSYNTAX       334
+#define RPL_WHOISBOT        335
+#define RPL_INVITING         341
+#define        RPL_SUMMONING        342
+
+#define RPL_VERSION          351
+
+#define RPL_WHOREPLY         352
+#define RPL_ENDOFWHO         315
+#define RPL_NAMREPLY         353
+#define RPL_ENDOFNAMES       366
+#define RPL_INVITELIST      346
+#define RPL_ENDOFINVITELIST  347
+
+#define RPL_EXLIST          348
+#define RPL_ENDOFEXLIST      349
+#define RPL_KILLDONE         361
+#define        RPL_CLOSING          362
+#define RPL_CLOSEEND         363
+#define RPL_LINKS            364
+#define RPL_ENDOFLINKS       365
+/* rpl_endofnames above (366) */
+#define RPL_BANLIST          367
+#define RPL_ENDOFBANLIST     368
+/* rpl_endofwhowas above (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_WHOISHOST        378
+#define RPL_WHOISMODES       379
+#define RPL_YOUREOPER        381
+#define RPL_REHASHING        382
+#define RPL_YOURESERVICE     383
+#define RPL_MYPORTIS         384
+#define RPL_NOTOPERANYMORE   385
+
+#define RPL_TIME             391
+#define        RPL_USERSSTART       392
+#define        RPL_USERS            393
+#define        RPL_ENDOFUSERS       394
+#define        RPL_NOUSERS          395
+
+#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_TRACESERVICE     207
+#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_STATSQLINE       217
+#define RPL_STATSYLINE       218
+#define RPL_ENDOFSTATS       219
+#define RPL_STATSBLINE      220
+
+#define RPL_UMODEIS          221
+#define RPL_SQLINE_NICK      222
+#define RPL_STATSGLINE          223
+#define RPL_STATSTLINE          224
+#define RPL_SERVICEINFO      231
+#define RPL_RULES            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
+#define        RPL_STATSSLINE       245
+#define RPL_STATSXLINE      247
+#define RPL_STATSULINE       248       
+#define        RPL_STATSDEBUG       249
+#define RPL_STATSCONN        250
+
+#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_LOCALUSERS       265
+#define RPL_GLOBALUSERS      266
+
+#define RPL_SILELIST         271
+#define RPL_ENDOFSILELIST    272
+
+#define RPL_STATSDLINE       275
+
+#define RPL_HELPHDR         290
+#define RPL_HELPOP          291
+#define RPL_HELPTLR         292
+#define RPL_HELPHLP         293
+#define RPL_HELPFWD         294
+#define RPL_HELPIGN         295
+
+/*
+ * New /MAP format.
+ */
+#define RPL_MAP              006
+#define RPL_MAPMORE          610
+#define RPL_MAPEND           007
+
+/*
+ * Numberic replies from server commands.
+ * These are also in the range 600-799.
+ */
+
+#define RPL_LOGON            600
+#define RPL_LOGOFF           601
+#define RPL_WATCHOFF         602
+#define RPL_WATCHSTAT        603
+#define RPL_NOWON            604
+#define RPL_NOWOFF           605
+#define RPL_WATCHLIST        606
+#define RPL_ENDOFWATCHLIST   607
+#define RPL_DUMPING                     640
+#define RPL_DUMPRPL                     641
+#define RPL_EODUMP           642
diff --git a/include/relinfo.h b/include/relinfo.h
new file mode 100644 (file)
index 0000000..43909cd
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * Relinfo.h
+ *
+ * If anyone makes another release or a hybrid of Unreal
+ * PLEASE CHANGE RELEASEID2 to the current time(NULL) (date +%s)
+ * if another hybrid please change releaseprefix
+ * if a unreal special edtion please select an IDTAG for it
+ * - Stskeeps - 
+*/
+
+#include "stamp.h"
+#define RELEASEPREFIX "unrealircd"
+#define RELEASEIDTAG "000"
+#define RELEASEID RELEASEPREFIX "[" RELEASESTUFF "(" RELEASEID2 "/" RELEASEIDTAG ")]"
diff --git a/include/res.h b/include/res.h
new file mode 100644 (file)
index 0000000..67548a1
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * irc2.7.2/ircd/res.h (C)opyright 1992 Darren Reed.
+ * $Id$
+ */
+#ifndef        __res_include__
+#define        __res_include__
+
+#define        RES_INITLIST    1
+#define        RES_CALLINIT    2
+#define RES_INITSOCK   4
+#define RES_INITDEBG   8
+#define RES_INITCACH    16
+
+#define MAXPACKET      1024
+#define MAXALIASES     35
+#define MAXADDRS       35
+
+#define        AR_TTL          600     /* TTL in seconds for dns cache entries */
+
+struct hent {
+       char    *h_name;        /* official name of host */
+       char    *h_aliases[MAXALIASES]; /* alias list */
+       int     h_addrtype;     /* host address type */
+       int     h_length;       /* length of address */
+       /* list of addresses from name server */
+       struct  in_addr h_addr_list[MAXADDRS];
+#define        h_addr  h_addr_list[0]  /* address, for backward compatiblity */
+};
+
+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;
+#ifndef _WIN32
+       struct  hent he;
+#else
+       struct  hostent *he;
+       char    locked;
+#endif
+       } ResRQ;
+
+typedef        struct  cache {
+       time_t  expireat;
+       time_t  ttl;
+#ifndef _WIN32
+       struct  hostent he;
+#else
+       struct  hostent *he;
+#endif
+       struct  cache   *hname_next, *hnum_next, *list_next;
+       } aCache;
+
+typedef struct cachetable {
+       aCache  *num_list;
+       aCache  *name_list;
+       } CacheTable;
+
+#define ARES_CACSIZE   101
+
+#define        MAXCACHED       81
+
+#endif /* __res_include__ */
diff --git a/include/resolv.h b/include/resolv.h
new file mode 100644 (file)
index 0000000..a7fdaec
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1983, 1987, 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *  $Id$
+ *     @(#)resolv.h    5.10.1 (Berkeley) 6/1/90
+ */
+
+/*
+ * Resolver configuration file.
+ * Normally not present, but may contain the address of the
+ * inital name server(s) to query and the domain search list.
+ */
+
+#ifndef        _PATH_RESCONF
+#define _PATH_RESCONF        "/etc/resolv.conf"
+#endif
+
+/*
+ * Global defines and variables for resolver stub.
+ */
+#define        MAXNS           3               /* max # name servers we'll track */
+#define        MAXDFLSRCH      3               /* # default domain levels to try */
+#define        MAXDNSRCH       6               /* max # domains in search path */
+#define        LOCALDOMAINPARTS 2              /* min levels in name that is "local" */
+#define MAXSERVICES    2               /* max # of services to search */
+
+#define        RES_TIMEOUT     5               /* min. seconds between retries */
+
+struct state {
+       int     retrans;                /* retransmition time interval */
+       int     retry;                  /* number of times to retransmit */
+       long    options;                /* option flags - see below. */
+       int     nscount;                /* number of name servers */
+       struct  sockaddr_in nsaddr_list[MAXNS]; /* address of name server */
+#define        nsaddr  nsaddr_list[0]          /* for backward compatibility */
+       unsigned short  id;                     /* current packet id */
+       char    defdname[MAXDNAME];     /* default domain */
+       char    *dnsrch[MAXDNSRCH+1];   /* components of domain to search */
+       unsigned short  order[MAXSERVICES+1];   /* search service order */
+};
+
+#define RES_SERVICE_NONE       0
+#define RES_SERVICE_BIND       1
+#define RES_SERVICE_LOCAL      2
+
+/*
+ * Resolver options
+ */
+#define RES_INIT       0x0001          /* address initialized */
+#define RES_DEBUG      0x0002          /* print debug messages */
+#define RES_AAONLY     0x0004          /* authoritative answers only */
+#define RES_USEVC      0x0008          /* use virtual circuit */
+#define RES_PRIMARY    0x0010          /* query primary server only */
+#define RES_IGNTC      0x0020          /* ignore trucation errors */
+#define RES_RECURSE    0x0040          /* recursion desired */
+#define RES_DEFNAMES   0x0080          /* use default domain name */
+#define RES_STAYOPEN   0x0100          /* Keep TCP socket open */
+#define RES_DNSRCH     0x0200          /* search up local domain tree */
+
+#define RES_DEFAULT    (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH)
+
+extern struct state _res;
+extern char *p_cdname(), *p_rr(), *p_type(), *p_class(), *p_time();
+
diff --git a/include/resource.h b/include/resource.h
new file mode 100644 (file)
index 0000000..fc7ab1e
--- /dev/null
@@ -0,0 +1,59 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by GENERIC.RC
+// $Id$
+#define IDC_USERID                      1051
+#define IDC_REALNAME                    1052
+#define IDC_PNICK                       1053
+#define IDC_ANICK                       1054
+#define IDC_SERVERLIST                  1057
+#define IDC_NEWSERVER                   1058
+#define IDC_EDITSERVER                  1059
+#define IDC_IRCDCONF                    1059
+#define IDC_DELSERVER                   1060
+#define IDC_SHOW_GLOBOPS                1060
+#define IDC_SHOW_WALLOPS                1061
+#define IDC_SHOW_HELPOPS                1062
+#define IDC_SHOW_SERVNOTICE             1063
+#define IDC_INFOTEXT                    1063
+#define IDM_OPEN                        40001
+#define IDM_SAVE                        40002
+#define IDM_SAVEAS                      40003
+#define IDM_EXIT                        40004
+#define IDM_ABOUT                       40005
+#define IDM_WINDOWCHILD                 40006
+#define IDM_REHASH                      40007
+#define IDM_OPTIONS                     40008
+#define        IDM_CREDITS                                             40009
+#define IDM_DF                                                 40010
+#define IDM_LICENSE                                            40011
+#define IDM_DBGOFF                      41099
+#define IDM_DBGFATAL                    41100
+#define IDM_DBGERROR                    41101
+#define IDM_DBGNOTICE                   41103
+#define IDM_DBGDNS                      41104
+#define IDM_DBGINFO                     41105
+#define IDM_DBGNUM                      41106
+#define IDM_DBGSEND                     41107
+#define IDM_DBGDEBUG                    41108
+#define IDM_DBGMALLOC                   41109
+#define IDM_DBGLIST                     41110
+#define IDM_POPUP                       50000
+#define IDC_STATIC                      -1
+#define IDM_IRCDRULES                                  65530
+#define IDM_IRCDMOTD                                   65531
+#define IDC_VERSION                     65532
+#define IDM_SETUP                       65536
+#define IDM_IRCDCONF                    65535
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC                     1
+#define _APS_NEXT_RESOURCE_VALUE        113
+#define _APS_NEXT_COMMAND_VALUE         40011
+#define _APS_NEXT_CONTROL_VALUE         1064
+#define _APS_NEXT_SYMED_VALUE           104
+#endif
+#endif
diff --git a/include/sjoin.h b/include/sjoin.h
new file mode 100644 (file)
index 0000000..525371b
--- /dev/null
@@ -0,0 +1,65 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/sjoin.h
+ *   (C) Carsten Munk 2000
+ *   Contains code from StarChat IRCd, (C) their respective authors
+ *
+ *   This program is free software; you can 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$
+ */
+
+
+typedef struct  SynchList aSynchList;
+
+/* SJOIN synch structure */
+struct SynchList {
+        char            nick[NICKLEN];
+        int             deop;
+        int             devoice;
+       int             dehalf;
+       int             deown;
+       int             deprot;
+        int             op;
+        int             voice;
+       int             half;
+       int             own;
+       int             prot;
+        aSynchList      *next, *prev;
+};
+
+aSynchList *SJSynchList = NULL;
+
+aSynchList *make_synchlist()
+{
+    Reg1 aSynchList *synchptr;
+
+    synchptr = (aSynchList *) MyMalloc(sizeof(aSynchList));
+
+    synchptr->nick[0] = 0;
+    synchptr->deop = synchptr->dehalf = synchptr->deown = synchptr->deprot = 0;
+    synchptr->devoice = 0;
+    synchptr->op = 0;
+    synchptr->voice = synchptr->half = synchptr->own = synchptr->prot = 0;
+    synchptr->prev = synchptr->next = NULL;
+
+    return synchptr;
+}
+
+void free_synchlist(synchptr)
+    aSynchList *synchptr;
+{
+    MyFree((char *) synchptr);
+}
+
diff --git a/include/sock.h b/include/sock.h
new file mode 100644 (file)
index 0000000..4a82459
--- /dev/null
@@ -0,0 +1,75 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/sock.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 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$
+ *
+ * $Log$
+ * Revision 1.1.1.1  2000/01/30 12:16:33  stskeeps
+ * Begin of CVS at cvs.unreal.sourceforge.net
+ *
+ *
+ * Revision 1.1.1.1  1999/09/01 23:20:37  stskeeps
+ *
+ * Revision 1.2  1999/07/22 14:09:26  stskeeps
+ * *** empty log message ***
+ *
+ * Revision 1.1.1.1  1999/07/22 13:56:40  stskeeps
+ * 16:56 22-07-99 techie
+ * - Started on using CVS to develop Unreal
+ *
+ *
+ * Revision 1.1.1.1  1999/07/21 10:48:18  stskeeps
+ * 12:47 GMT+2 21 July 1999 - Techie
+ * Starting Unreal with CVS.. 
+ *
+ * Revision 1.2  1997/12/29 07:17:35  wd
+ * df4.6.2
+ * ee CHANGES for updates
+ * -wd
+ *
+ * Revision 1.1.1.1  1997/08/22 17:23:01  donwulff
+ * Original import from the "deadlined" version.
+ *
+ * Revision 1.1.1.1  1996/11/18 07:53:41  explorer
+ * ircd 4.3.3 -- about time
+ *
+ * Revision 1.1.1.1.4.1  1996/09/16 02:45:38  donwulff
+ * *** empty log message ***
+ *
+ * Revision 6.1  1991/07/04  21:04:35  gruner
+ * Revision 2.6.1 [released]
+ *
+ * Revision 6.0  1991/07/04  18:05:04  gruner
+ * frozen beta revision 2.6.1
+ *
+ */
+
+#ifndef FD_ZERO
+#define FD_ZERO(set)      (((set)->fds_bits[0]) = 0)
+#define FD_SET(s1, set)   (((set)->fds_bits[0]) |= 1 << (s1))
+#define FD_ISSET(s1, set) (((set)->fds_bits[0]) & (1 << (s1)))
+#define FD_SETSIZE        30
+#endif
+
+#ifdef RCVTIMEO
+#define SO_RCVTIMEO     0x1006          /* receive timeout */
+#endif
+
diff --git a/include/stamp.h b/include/stamp.h
new file mode 100644 (file)
index 0000000..4dce1bb
--- /dev/null
@@ -0,0 +1,4 @@
+/* Auto created release stamping */
+#define RELEASEID2 "951777936"
+#define RELEASESTUFF "draconic"
+
diff --git a/include/struct.h b/include/struct.h
new file mode 100644 (file)
index 0000000..afcdaed
--- /dev/null
@@ -0,0 +1,1082 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/struct.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 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        __struct_include__
+#define __struct_include__
+
+#include "config.h"
+#include "common.h"
+#include "sys.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+#ifdef STDDEFH
+# include <stddef.h>
+#endif
+
+#ifdef USE_SYSLOG
+# include <syslog.h>
+# ifdef SYSSYSLOGH
+#  include <sys/syslog.h>
+# endif
+#endif
+#ifdef pyr
+#include <sys/time.h>
+#endif
+
+typedef struct  t_fline aFline;
+typedef struct  t_crline aCRline;
+typedef struct  t_vhline aVHline;
+typedef struct t_kline aTKline;
+typedef struct  t_vhost aVhost;
+typedef struct  t_hush aHush;
+
+typedef struct  SqlineItem aSqlineItem;
+typedef        struct  ConfItem aConfItem;
+typedef struct Notify  aNotify;
+typedef        struct  Client  aClient;
+typedef        struct  Channel aChannel;
+typedef        struct  User    anUser;
+typedef        struct  Server  aServer;
+typedef        struct  SLink   Link;
+typedef struct SBan    Ban;
+typedef        struct  SMode   Mode;
+typedef struct ListOptions     LOpts;
+typedef struct  FloodOpt  aFloodOpt;
+typedef struct  CloneItem aClone;
+
+#ifdef NEED_U_INT32_T
+typedef unsigned int  u_int32_t; /* XXX Hope this works! */
+#endif
+
+#ifndef VMSP
+#include "class.h"
+#include "dbuf.h"      /* THIS REALLY SHOULDN'T BE HERE!!! --msa */
+#endif
+
+#define        HOSTLEN         63      /* Length of hostname.  Updated to         */
+                               /* comply with RFC1123                     */
+
+#define        NICKLEN         30      /* Necessary to put 9 here instead of 10
+                               ** if s_msg.c/m_nick has been corrected.
+                               ** This preserves compatibility with old
+                               ** servers --msa
+                               */
+#define        USERLEN         10
+#define        REALLEN         50
+#define        TOPICLEN        307
+/* DAL MADE ME PUT THIS IN THE FIEND:  --Russell
+ * This number will be expanded to 200 in the near future
+ */
+#define        CHANNELLEN      32
+#define        PASSWDLEN       32      /* orig. 20, changed to 32 for nickpasswords */
+#define        KEYLEN          23
+#define LINKLEN                32
+#define        BUFSIZE         512             /* WARNING: *DONT* CHANGE THIS!!!! */
+#define        MAXRECIPIENTS   20
+#define        MAXKILLS        20
+#define        MAXBANS         60
+#define        MAXBANLENGTH    1024
+#define        MAXSILES        5
+#define        MAXSILELENGTH   128
+/*
+ * Watch it - Don't change this unless you also change the ERR_TOOMANYWATCH
+ * and PROTOCOL_SUPPORTED settings.
+ */
+#define MAXWATCH       128
+
+#define        USERHOST_REPLYLEN       (NICKLEN+HOSTLEN+USERLEN+5)
+
+#ifdef USE_SERVICES
+#include "service.h"
+#endif
+
+/* NOTE: this must be down here so the stuff from struct.h IT uses works */
+#include "whowas.h"
+
+
+/*
+** 'offsetof' is defined in ANSI-C. The following definition
+** is not absolutely portable (I have been told), but so far
+** it has worked on all machines I have needed it. The type
+** should be size_t but...  --msa
+*/
+#ifndef offsetof
+#define        offsetof(t,m) (int)((&((t *)0L)->m))
+#endif
+
+#define        elementsof(x) (sizeof(x)/sizeof(x[0]))
+
+/*
+** 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_OPER       32
+#define        BOOT_AUTODIE    64
+
+#define        STAT_LOG        -6      /* logfile for -x */
+#define        STAT_MASTER     -5      /* Local ircd master before identification */
+#define        STAT_CONNECTING -4
+#define        STAT_HANDSHAKE  -3
+#define        STAT_ME         -2
+#define        STAT_UNKNOWN    -1
+#define        STAT_SERVER     0
+#define        STAT_CLIENT     1
+#define        STAT_SERVICE    2       /* Services not implemented yet */
+
+/*
+ * status macros.
+ */
+#define        IsRegisteredUser(x)     ((x)->status == STAT_CLIENT)
+#define        IsRegistered(x)         ((x)->status >= STAT_SERVER)
+#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 || \
+                                (x)->status == STAT_MASTER)
+#define        IsServer(x)             ((x)->status == STAT_SERVER)
+#define        IsClient(x)             ((x)->status == STAT_CLIENT)
+#define        IsLog(x)                ((x)->status == STAT_LOG)
+#define IsService(x)           0
+
+#define        SetMaster(x)            ((x)->status = STAT_MASTER)
+#define        SetConnecting(x)        ((x)->status = STAT_CONNECTING)
+#define        SetHandshake(x)         ((x)->status = STAT_HANDSHAKE)
+#define        SetMe(x)                ((x)->status = STAT_ME)
+#define        SetUnknown(x)           ((x)->status = STAT_UNKNOWN)
+#define        SetServer(x)            ((x)->status = STAT_SERVER)
+#define        SetClient(x)            ((x)->status = STAT_CLIENT)
+#define        SetLog(x)               ((x)->status = STAT_LOG)
+#define        SetService(x)           ((x)->status = STAT_SERVICE)
+
+#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_BLOCKED    0x0008 /* socket is in a blocked condition */
+#define        FLAGS_UNIX       0x0010 /* socket is in the unix domain, not inet */
+#define        FLAGS_CLOSING    0x0020 /* set when closing to suppress errors */
+#define        FLAGS_LISTEN     0x0040 /* used to mark clients which we listen() on */
+#define        FLAGS_CHKACCESS  0x0080 /* ok to check clients access if set */
+#define        FLAGS_DOINGDNS   0x0100 /* client is waiting for a DNS response */
+#define        FLAGS_AUTH       0x0200 /* client is waiting on rfc931 response */
+#define        FLAGS_WRAUTH     0x0400 /* set if we havent writen to ident server */
+#define        FLAGS_LOCAL      0x0800 /* set for local clients */
+#define        FLAGS_GOTID      0x1000 /* successful ident lookup achieved */
+#define        FLAGS_DOID       0x2000 /* I-lines say must use ident return */
+#define        FLAGS_NONL       0x4000 /* No \n in buffer */
+#define FLAGS_TS8       0x8000 /* Why do you want to know? */
+#define FLAGS_ULINE    0x10000 /* User/server is considered U-lined */
+#define FLAGS_SQUIT    0x20000 /* Server has been /squit by an oper */
+#define FLAGS_PROTOCTL 0x40000 /* Received a PROTOCTL message */
+#define FLAGS_PING      0x80000
+#define FLAGS_ASKEDPING 0x100000
+#define FLAGS_NETINFO   0x200000
+#define FLAGS_HYBNOTICE 0x400000
+#ifdef SOCKSPORT
+#define FLAGS_SOCKS     0x800000
+#define FLAGS_WRSOCKS   0x1000000
+#define FLAGS_GOTSOCKS  0x2000000
+#endif
+#define FLAGS_HUSHED    0x4000000
+#define FLAGS_MAP       0x80000000 /* Show this entry in /map */
+
+/* Dec 26th, 1997 - added flags2 when I ran out of room in flags -DuffJ 
+
+/* Dec 26th, 1997 - having a go at
+ * splitting flags into flags and umodes
+ * -DuffJ
+ */
+
+#define        UMODE_INVISIBLE  0x0001 /* makes user invisible */
+#define        UMODE_OPER       0x0002 /* Operator */
+#define        UMODE_WALLOP     0x0004 /* send wallops to them */
+#define UMODE_FAILOP    0x0008 /* Shows some global messages */
+#define UMODE_HELPOP    0x0010 /* Help system operator */
+#define UMODE_REGNICK   0x0020 /* Nick set by services as registered */
+#define UMODE_SADMIN    0x0040 /* Services Admin */
+#define UMODE_ADMIN     0x0080 /* Admin */
+#define        UMODE_SERVNOTICE 0x0100 /* server notices such as kill */
+#define        UMODE_LOCOP      0x0200 /* Local operator -- SRB */
+#define UMODE_KILLS     0x0400 /* Show server-kills... */
+#define UMODE_CLIENT    0x0800 /* Show client information */
+#define UMODE_FLOOD     0x1000 /* Receive flood warnings */
+#define UMODE_CHATOP    0x2000 /* can receive chatops */
+#define UMODE_SERVICES   0x4000 /* services */
+#define UMODE_HIDE      0x8000 /* Hide from Nukes */
+#define UMODE_NETADMIN  0x10000 /* Network Admin */
+#define UMODE_EYES      0x20000 /* Mode to see server stuff */
+#define UMODE_TECHADMIN 0x40000 /* Tech Admin */
+#define UMODE_COADMIN   0x80000 /* Co Admin */
+#define UMODE_WHOIS    0x100000 /* gets notice on /whois */
+#define UMODE_KIX      0x200000 /* usermode +q */
+#define UMODE_BOT       0x400000 /* User is a bot */
+#define UMODE_CODER    0x800000 /* User is a network coder */
+#define UMODE_FCLIENT  0x1000000 /* recieve client on far connects.. */
+#define UMODE_HIDING   0x2000000 /* Totally invisible .. */
+#define UMODE_AGENT    0x4000000 /* Is an IRCd Agent local only */
+#define        UMODE_VICTIM   0x8000000 /* Intentional Victim */
+#define UMODE_DEAF     0x10000000
+#define UMODE_HIDEOPER 0x20000000 /* Hide oper mode */
+#define UMODE_SETHOST  0x40000000 /* used sethost */
+
+#define        SEND_UMODES     (UMODE_INVISIBLE|UMODE_OPER|UMODE_WALLOP|UMODE_FAILOP|UMODE_HELPOP|UMODE_REGNICK|UMODE_SADMIN|UMODE_NETADMIN|UMODE_TECHADMIN|UMODE_COADMIN|UMODE_ADMIN|UMODE_SERVICES|UMODE_HIDE|UMODE_EYES|UMODE_WHOIS|UMODE_KIX|UMODE_BOT|UMODE_CODER|UMODE_FCLIENT|UMODE_HIDING|UMODE_AGENT|UMODE_DEAF|UMODE_VICTIM|UMODE_HIDEOPER|UMODE_SETHOST)
+#define        ALL_UMODES      (SEND_UMODES|UMODE_SERVNOTICE|UMODE_LOCOP|UMODE_KILLS|UMODE_CLIENT|UMODE_FLOOD|UMODE_CHATOP|UMODE_SERVICES|UMODE_EYES|UMODE_AGENT)
+#define        FLAGS_ID        (FLAGS_DOID|FLAGS_GOTID)
+
+#define PROTO_NOQUIT   0x1     /* Negotiated NOQUIT protocol */
+#define PROTO_TOKEN    0x2     /* Negotiated TOKEN protocol */
+#define PROTO_SJOIN    0x4     /* Negotiated SJOIN protocol */
+#define PROTO_NICKv2   0x8     /* Negotiated NICKv2 protocol */
+#define PROTO_SJOIN2   0x10    /* Negotiated SJOIN2 protocol */
+/*
+ * flags macros.
+ */
+#define IsVictim(x)             ((x)->umodes & UMODE_VICTIM)
+#define IsDeaf(x)               ((x)->umodes & UMODE_DEAF)
+#define IsKillsF(x)            ((x)->umodes & UMODE_KILLS)
+#define IsClientF(x)           ((x)->umodes & UMODE_CLIENT)
+#define IsFloodF(x)            ((x)->umodes & UMODE_FLOOD)
+#define IsEyes(x)              ((x)->umodes & UMODE_EYES)
+#define IsWhois(x)             ((x)->umodes & UMODE_WHOIS)
+#define IsKix(x)               ((x)->umodes & UMODE_KIX)
+#define IsHelpOp(x)            ((x)->umodes & UMODE_HELPOP)
+#define IsAdmin(x)             ((x)->umodes & UMODE_ADMIN)
+#define IsHiding(x)            ((x)->umodes & UMODE_HIDING)
+#define IsNetAdmin(x)          ((x)->umodes & UMODE_NETADMIN)
+#define IsTechAdmin(x)         ((x)->umodes & UMODE_TECHADMIN)
+#define IsCoAdmin(x)           ((x)->umodes & UMODE_COADMIN)
+#define IsSAdmin(x)            ((x)->umodes & UMODE_SADMIN)
+#define SendFailops(x)         ((x)->umodes & UMODE_FAILOP)
+#define SendChatops(x)         ((x)->umodes & UMODE_CHATOP)
+#define        IsOper(x)               ((x)->umodes & UMODE_OPER)
+#define        IsLocOp(x)              ((x)->umodes & UMODE_LOCOP)
+#define IsAgent(x)         ((x)->umodes & UMODE_AGENT)
+#define        IsInvisible(x)          ((x)->umodes & UMODE_INVISIBLE)
+#define IsServices(x)          ((x)->umodes & UMODE_SERVICES)
+#define        IsAnOper(x)             ((x)->umodes & (UMODE_OPER|UMODE_LOCOP))
+#define IsARegNick(x)          ((x)->umodes & (UMODE_REGNICK))
+#define IsRegNick(x)           ((x)->umodes & UMODE_REGNICK)
+#define        IsPerson(x)             ((x)->user && IsClient(x))
+#define IsPasser(x)            ((x)->user & UMODE_PASSER)
+#define        IsPrivileged(x)         (IsAnOper(x) || IsServer(x))
+#define        SendWallops(x)          ((x)->umodes & UMODE_WALLOP)
+#define        SendServNotice(x)       ((x)->umodes & UMODE_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 GotProtoctl(x)         ((x)->flags & FLAGS_PROTOCTL)
+#define IsBlocked(x)           ((x)->flags & FLAGS_BLOCKED)
+#define GotNetInfo(x)          ((x)->flags & FLAGS_NETINFO)
+#define SetNetInfo(x)          ((x)->flags |= FLAGS_NETINFO)
+
+#define IsHushed(x)            ((x)->flags & FLAGS_HUSHED)
+#define SetHushed(x)           ((x)->flags |= FLAGS_HUSHED)
+#define ClearHushed(x)         ((x)->flags &= ~FLAGS_HUSHED)
+
+#define IsHybNotice(x)         ((x)->flags & FLAGS_HYBNOTICE)
+#define SetHybNotice(x)         ((x)->flags |= FLAGS_HYBNOTICE)
+#define IsHidden(x)             ((x)->umodes & UMODE_HIDE)
+#define IsHideOper(x)          ((x)->umodes & UMODE_HIDEOPER)
+
+#ifdef NOSPOOF
+#define        IsNotSpoof(x)           ((x)->nospoof == 0)
+#else
+#define IsNotSpoof(x)           (1)
+#endif
+
+#define SetKillsF(x)           ((x)->umodes |= UMODE_KILLS)
+#define SetClientF(x)          ((x)->umodes |= UMODE_CLIENT)
+#define SetFloodF(x)           ((x)->umodes |= UMODE_FLOOD)
+#define SetHelpOp(x)           ((x)->umodes |= UMODE_HELPOP)
+#define        SetOper(x)              ((x)->umodes |= UMODE_OPER)
+#define        SetLocOp(x)             ((x)->umodes |= UMODE_LOCOP)
+#define SetAgent(x)            ((x)->umodes |= UMODE_AGENT)
+#define SetAdmin(x)            ((x)->umodes |= UMODE_ADMIN)
+#define SetSAdmin(x)           ((x)->umodes |= UMODE_SADMIN)
+#define SetNetAdmin(x)         ((x)->umodes |= UMODE_NETADMIN)
+#define SetTechAdmin(x)                ((x)->umodes |= UMODE_TECHADMIN)
+#define SetCoAdmin(x)          ((x)->umodes |= UMODE_COADMIN)
+#define        SetInvisible(x)         ((x)->umodes |= UMODE_INVISIBLE)
+#define SetEyes(x)             ((x)->umodes |= UMODE_EYES)
+#define        SetWallops(x)           ((x)->umodes |= UMODE_WALLOP)
+#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 SetBlocked(x)          ((x)->flags |= FLAGS_BLOCKED)
+#define        DoingAuth(x)            ((x)->flags & FLAGS_AUTH)
+#ifdef SOCKSPORT
+#define DoingSocks(x)           ((x)->flags & FLAGS_SOCKS)
+#endif
+#define        NoNewLine(x)            ((x)->flags & FLAGS_NONL)
+#define SetRegNick(x)          ((x)->umodes & UMODE_REGNICK)
+#define SetHidden(x)            ((x)->umodes |= UMODE_HIDE)
+#define SetHideOper(x)      ((x)->umodes |= UMODE_HIDEOPER)
+
+#define ClearAdmin(x)          ((x)->umodes &= ~UMODE_ADMIN)
+#define ClearNetAdmin(x)       ((x)->umodes &= ~UMODE_NETADMIN)
+#define ClearTechAdmin(x)      ((x)->umodes &= ~UMODE_TECHADMIN)
+#define ClearCoAdmin(x)                ((x)->umodes &= ~UMODE_COADMIN)
+#define ClearSAdmin(x)         ((x)->umodes &= ~UMODE_SADMIN)
+#define ClearKillsF(x)         ((x)->umodes &= ~UMODE_KILLS)
+#define ClearClientF(x)                ((x)->umodes &= ~UMODE_CLIENT)
+#define ClearFloodF(x)         ((x)->umodes &= ~UMODE_FLOOD)
+#define ClearEyes(x)           ((x)->umodes &= ~UMODE_EYES)
+#define ClearHelpOp(x)         ((x)->umodes &= ~UMODE_HELPOP)
+#define ClearFailops(x)                ((x)->umodes &= ~UMODE_FAILOP)
+#define ClearChatops(x)                ((x)->umodes &= ~UMODE_CHATOP)
+#define        ClearOper(x)            ((x)->umodes &= ~UMODE_OPER)
+#define ClearAgent(x)          ((x)->umodes &= ~UMODE_AGENT)
+#define        ClearInvisible(x)       ((x)->umodes &= ~UMODE_INVISIBLE)
+#define ClearServices(x)       ((x)->umodes &= ~UMODE_SERVICES)
+#define        ClearWallops(x)         ((x)->umodes &= ~UMODE_WALLOP)
+#define        ClearDNS(x)             ((x)->flags &= ~FLAGS_DOINGDNS)
+#define        ClearAuth(x)            ((x)->flags &= ~FLAGS_AUTH)
+#define        ClearAccess(x)          ((x)->flags &= ~FLAGS_CHKACCESS)
+#define ClearBlocked(x)                ((x)->flags &= ~FLAGS_BLOCKED)
+#define ClearHidden(x)          ((x)->umodes &= ~UMODE_HIDE)
+#define ClearHideOper(x)    ((x)->umodes &= ~UMODE_HIDEOPER)
+
+#ifdef SOCKSPORT
+#define ClearSocks(x) ((x)->flags &= ~FLAGS_SOCKS)
+#endif
+
+/*
+ * ProtoCtl options
+ */
+#define DontSendQuit(x)                ((x)->proto & PROTO_NOQUIT)
+#define IsToken(x)             ((x)->proto & PROTO_TOKEN)
+#define SupportSJOIN(x)                ((x)->proto & PROTO_SJOIN)
+#define SupportNICKv2(x)       ((x)->proto & PROTO_NICKv2)
+#define SupportSJOIN2(x)       ((x)->proto & PROTO_SJOIN2)
+
+#define SetSJOIN(x)            ((x)->proto |= PROTO_SJOIN)
+#define SetNoQuit(x)           ((x)->proto |= PROTO_NOQUIT)
+#define SetToken(x)            ((x)->proto |= PROTO_TOKEN)
+#define SetNICKv2(x)           ((x)->proto |= PROTO_NICKv2)
+#define SetSJOIN2(x)           ((x)->proto |= PROTO_SJOIN2)
+
+#define ClearSJOIN(x)          ((x)->proto &= ~PROTO_SJOIN)
+#define ClearNoQuit(x)         ((x)->proto &= ~PROTO_NOQUIT)
+#define ClearToken(x)          ((x)->proto &= ~PROTO_TOKEN)
+#define ClearNICKv2(x)         ((x)->proto &= ~PROTO_NICKv2)
+#define ClearSJOIN2(x)         ((x)->proto &= ~PROTO_SJOIN2)
+
+/*
+ * defined operator access levels
+ */
+#define OFLAG_REHASH   0x00000001  /* Oper can /rehash server */
+#define OFLAG_DIE      0x00000002  /* Oper can /die the server */
+#define OFLAG_RESTART  0x00000004  /* Oper can /restart the server */
+#define OFLAG_HELPOP   0x00000010  /* Oper can send /HelpOps */
+#define OFLAG_GLOBOP   0x00000020  /* Oper can send /GlobOps */
+#define OFLAG_WALLOP   0x00000040  /* Oper can send /WallOps */
+#define OFLAG_LOCOP    0x00000080  /* Oper can send /LocOps */
+#define OFLAG_LROUTE   0x00000100  /* Oper can do local routing */
+#define OFLAG_GROUTE   0x00000200  /* Oper can do global routing */
+#define OFLAG_LKILL    0x00000400  /* Oper can do local kills */
+#define OFLAG_GKILL    0x00000800  /* Oper can do global kills */
+#define OFLAG_KLINE    0x00001000  /* Oper can /kline users */
+#define OFLAG_UNKLINE  0x00002000  /* Oper can /unkline users */
+#define OFLAG_LNOTICE  0x00004000  /* Oper can send local serv notices */
+#define OFLAG_GNOTICE  0x00008000  /* Oper can send global notices */
+#define OFLAG_ADMIN    0x00010000  /* Admin */
+#define OFLAG_UMODEC   0x00020000  /* Oper can set umode +c */
+#define OFLAG_UMODEF   0x00040000  /* Oper can set umode +f */
+#define OFLAG_ZLINE    0x00080000  /* Oper can use /zline and /unzline */
+#define OFLAG_EYES      0x00100000  /* Oper auto gets +e */
+#define OFLAG_NETADMIN  0x00200000  /* netadmin gets +N */
+#define OFLAG_TECHADMIN 0x00400000  /* tech admin gets +T */
+#define OFLAG_COADMIN  0x00800000  /* co admin gets +C */
+#define OFLAG_SADMIN   0x01000000  /* services admin gets +a */
+#define OFLAG_WHOIS     0x02000000  /* gets auto +W on oper up */
+#define OFLAG_HIDE      0x04000000  /* gets auto +x on oper up */
+#define OFLAG_AGENT    0x08000000  /* Is an IRCd Agent */
+#define OFLAG_AFOUNDER  0x10000000
+#define OFLAG_COFOUND   0x20000000
+#define OFLAG_WMASTER  0x40000000
+#define OFLAG_INVISIBLE 0x80000000
+#define OFLAG_LOCAL    (OFLAG_REHASH|OFLAG_HELPOP|OFLAG_GLOBOP|OFLAG_WALLOP|OFLAG_LOCOP|OFLAG_LROUTE|OFLAG_LKILL|OFLAG_KLINE|OFLAG_UNKLINE|OFLAG_LNOTICE|OFLAG_UMODEC|OFLAG_UMODEF)
+#define OFLAG_GLOBAL   (OFLAG_LOCAL|OFLAG_GROUTE|OFLAG_GKILL|OFLAG_GNOTICE)
+#define OFLAG_ISGLOBAL (OFLAG_GROUTE|OFLAG_GKILL|OFLAG_GNOTICE)
+
+
+#define OPCanZline(x)   ((x)->oflag & OFLAG_ZLINE)
+#define OPCanRehash(x) ((x)->oflag & OFLAG_REHASH)
+#define OPCanDie(x)    ((x)->oflag & OFLAG_DIE)
+#define OPCanRestart(x)        ((x)->oflag & OFLAG_RESTART)
+#define OPCanHelpOp(x) ((x)->oflag & OFLAG_HELPOP)
+#define OPCanGlobOps(x)        ((x)->oflag & OFLAG_GLOBOP)
+#define OPCanWallOps(x)        ((x)->oflag & OFLAG_WALLOP)
+#define OPCanLocOps(x) ((x)->oflag & OFLAG_LOCOP)
+#define OPCanLRoute(x) ((x)->oflag & OFLAG_LROUTE)
+#define OPCanGRoute(x) ((x)->oflag & OFLAG_GROUTE)
+#define OPCanLKill(x)  ((x)->oflag & OFLAG_LKILL)
+#define OPCanGKill(x)  ((x)->oflag & OFLAG_GKILL)
+#define OPCanKline(x)  ((x)->oflag & OFLAG_KLINE)
+#define OPCanUnKline(x)        ((x)->oflag & OFLAG_UNKLINE)
+#define OPCanLNotice(x)        ((x)->oflag & OFLAG_LNOTICE)
+#define OPCanGNotice(x)        ((x)->oflag & OFLAG_GNOTICE)
+#define OPIsAdmin(x)   ((x)->oflag & OFLAG_ADMIN)
+#define OPIsSAdmin(x)  ((x)->oflag & OFLAG_SADMIN)
+#define OPIsNetAdmin(x) ((x)->oflag & OFLAG_NETADMIN)
+#define OPIsTechAdmin(x) ((x)->oflag & OFLAG_TECHADMIN)
+#define OPIsCoAdmin(x) ((x)->oflag & OFLAG_COADMIN)
+#define OPCanUModeC(x) ((x)->oflag & OFLAG_UMODEC)
+#define OPCanUModeF(x) ((x)->oflag & OFLAG_UMODEF)
+#define OPIsEyes(x)    ((x)->oflag & OFLAG_EYES)
+#define OPIsWhois(x)    ((x)->oflag & OFLAG_WHOIS)
+
+#define OPSetRehash(x) ((x)->oflag |= OFLAG_REHASH)
+#define OPSetDie(x)    ((x)->oflag |= OFLAG_DIE)
+#define OPSetRestart(x)        ((x)->oflag |= OFLAG_RESTART)
+#define OPSetHelpOp(x) ((x)->oflag |= OFLAG_HELPOP)
+#define OPSetGlobOps(x)        ((x)->oflag |= OFLAG_GLOBOP)
+#define OPSetWallOps(x)        ((x)->oflag |= OFLAG_WALLOP)
+#define OPSetLocOps(x) ((x)->oflag |= OFLAG_LOCOP)
+#define OPSetLRoute(x) ((x)->oflag |= OFLAG_LROUTE)
+#define OPSetGRoute(x) ((x)->oflag |= OFLAG_GROUTE)
+#define OPSetLKill(x)  ((x)->oflag |= OFLAG_LKILL)
+#define OPSetGKill(x)  ((x)->oflag |= OFLAG_GKILL)
+#define OPSetKline(x)  ((x)->oflag |= OFLAG_KLINE)
+#define OPSetUnKline(x)        ((x)->oflag |= OFLAG_UNKLINE)
+#define OPSetLNotice(x)        ((x)->oflag |= OFLAG_LNOTICE)
+#define OPSetGNotice(x)        ((x)->oflag |= OFLAG_GNOTICE)
+#define OPSSetAdmin(x) ((x)->oflag |= OFLAG_ADMIN)
+#define OPSSetSAdmin(x)        ((x)->oflag |= OFLAG_SADMIN)
+#define OPSSetNetAdmin(x) ((x)-> oflag |= OFLAG_NETADMIN)
+#define OPSSetTechAdmin(x) ((x)-> oflag |= OFLAG_TECHADMIN)
+#define OPSSetCoAdmin(x) ((x)->oflag |= OFLAG_COADMIN)
+#define OPSetUModeC(x) ((x)->oflag |= OFLAG_UMODEC)
+#define OPSetUModeF(x) ((x)->oflag |= OFLAG_UMODEF)
+#define OPSetEyes(x)   ((x)->oflag |= OFLAG_EYES)
+#define OPSetZLine(x)  ((x)->oflag |= OFLAG_ZLINE)
+#define OPSetWhois(x)   ((x)->oflag |= OFLAG_WHOIS)
+#define OPSetPasser(x)  ((x)->oflag |= OFLAG_ISPASSER)
+#define OPClearRehash(x)       ((x)->oflag &= ~OFLAG_REHASH)
+#define OPClearDie(x)          ((x)->oflag &= ~OFLAG_DIE)  
+#define OPClearRestart(x)      ((x)->oflag &= ~OFLAG_RESTART)
+#define OPClearHelpOp(x)       ((x)->oflag &= ~OFLAG_HELPOP)
+#define OPClearGlobOps(x)      ((x)->oflag &= ~OFLAG_GLOBOP)
+#define OPClearWallOps(x)      ((x)->oflag &= ~OFLAG_WALLOP)
+#define OPClearLocOps(x)       ((x)->oflag &= ~OFLAG_LOCOP)
+#define OPClearLRoute(x)       ((x)->oflag &= ~OFLAG_LROUTE)
+#define OPClearGRoute(x)       ((x)->oflag &= ~OFLAG_GROUTE)
+#define OPClearLKill(x)                ((x)->oflag &= ~OFLAG_LKILL)
+#define OPClearGKill(x)                ((x)->oflag &= ~OFLAG_GKILL)
+#define OPClearKline(x)                ((x)->oflag &= ~OFLAG_KLINE)
+#define OPClearUnKline(x)      ((x)->oflag &= ~OFLAG_UNKLINE)
+#define OPClearLNotice(x)      ((x)->oflag &= ~OFLAG_LNOTICE)
+#define OPClearGNotice(x)      ((x)->oflag &= ~OFLAG_GNOTICE)
+#define OPClearPasser(x)    ((x)->oflag &= ~OFLAG_PASSER)
+#define OPClearAdmin(x)                ((x)->oflag &= ~OFLAG_ADMIN)
+#define OPClearSAdmin(x)       ((x)->oflag &= ~OFLAG_SADMIN)
+#define OPClearNetAdmin(x)     ((x)->oflag &= ~OFLAG_NETADMIN)
+#define OPClearTechAdmin(x)    ((x)->oflag &= ~OFLAG_TECHADMIN)
+#define OPClearCoAdmin(x)      ((x)->oflag &= ~OFLAG_COADMIN)
+#define OPClearUModeC(x)       ((x)->oflag &= ~OFLAG_UMODEC)
+#define OPClearUModeF(x)       ((x)->oflag &= ~OFLAG_UMODEF)
+#define OPClearEyes(x)         ((x)->oflag &= ~OFLAG_EYES)
+#define OPClearZLine(x)                ((x)->oflag &= ~OFLAG_ZLINE)
+#define OPClearWhois(x)         ((x)->oflag &= ~OFLAG_WHOIS)
+/*
+ * defined debugging levels
+ */
+#define        DEBUG_FATAL  0
+#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 */
+
+/*
+ * defines for curses in client
+ */
+#define        DUMMY_TERM      0
+#define        CURSES_TERM     1
+#define        TERMCAP_TERM    2
+
+struct  SqlineItem     {
+       unsigned int    status;
+       char *sqline;
+       char *reason;
+       struct  SqlineItem *next;
+};
+
+struct ConfItem        {
+       unsigned int    status; /* If CONF_ILLEGAL, delete when no clients */
+       int     clients;        /* Number of *LOCAL* clients using this */
+       struct  in_addr ipnum;  /* ip number of host field */
+       char    *host;
+       char    *passwd;
+       char    *name;
+       int     port;
+       time_t  hold;   /* Hold action until this time (calendar time) */
+       int     tmpconf;
+#ifndef VMSP
+       aClass  *class;  /* Class of connection */
+#endif
+       struct  ConfItem *next;
+};
+
+#define        CONF_ILLEGAL            0x80000000
+#define        CONF_MATCH              0x40000000
+#define        CONF_QUARANTINED_SERVER 0x0001
+#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_SERVICE            0x0800
+#define        CONF_LEAF               0x1000
+#define        CONF_LISTEN_PORT        0x2000
+#define        CONF_HUB                0x4000
+#define        CONF_UWORLD             0x8000
+#define CONF_QUARANTINED_NICK  0x10000
+#define CONF_ZAP               0x20000
+#define CONF_CONFIG             0x100000
+#define CONF_CRULEALL           0x200000
+#define CONF_CRULEAUTO          0x400000
+#define CONF_MISSING           0x800000
+#define CONF_SADMIN            0x1000000
+#define CONF_DRPASS            0x2000000   /* DIE/RESTART pass - NikB */
+#define CONF_EXCEPT            0x4000000   /* K:Line exception */
+#define CONF_TLINE             0x8000000   /* T:Line */
+#define CONF_SOCKSEXCEPT       0x10000000
+#define        CONF_OPS                (CONF_OPERATOR | CONF_LOCOP)
+#define        CONF_SERVER_MASK        (CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER)
+#define        CONF_CLIENT_MASK        (CONF_CLIENT | CONF_SERVICE | CONF_OPS | \
+                                CONF_SERVER_MASK)
+#define CONF_CRULE              (CONF_CRULEALL | CONF_CRULEAUTO)
+#define CONF_QUARANTINE                (CONF_QUARANTINED_SERVER|CONF_QUARANTINED_NICK)
+
+#define        IsIllegal(x)    ((x)->status & CONF_ILLEGAL)
+#define IsTemp(x)      ((x)->tmpconf)
+
+/*
+ * Client structures
+ */
+struct User    {
+       struct  User    *nextu;
+       Link    *channel;       /* chain of channel pointer blocks */
+       Link    *invited;       /* chain of invite pointer blocks */
+       Link    *silence;       /* chain of silence pointer blocks */
+       char    *away;          /* pointer to away message */
+       time_t  last;
+       u_int32_t servicestamp;  /* Services' time stamp variable */
+       int     refcnt;         /* Number of times this block is referenced */
+       int     joined;         /* number of channels joined */
+       char    username[USERLEN+1];
+       char    realhost[HOSTLEN+1];
+       char    virthost[HOSTLEN+1];
+    char       server[HOSTLEN+1];
+       char    *swhois;        /* special whois thing */
+    aClient *serv;
+
+#ifdef LIST_DEBUG
+       aClient *bcptr;
+#endif
+};
+
+struct Server  {
+       struct  Server  *nexts;
+       anUser  *user;          /* who activated this connection */
+       char    up[HOSTLEN+1];  /* uplink for this server */
+       char    by[NICKLEN+1];
+       aConfItem *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 */
+        u_short prot;           /* Major protocol */
+#ifdef LIST_DEBUG
+       aClient *bcptr;
+#endif
+};
+
+struct t_vhost {
+       char    *usermask;
+       char    *hostmask;
+       char    *login;
+       char    *password;
+       char    *virthost;
+       aVhost  *next;
+       aVhost  *prev;
+};
+
+struct t_hush {
+       char    *nuhmask;
+       char    *setby;
+       time_t  set_at;
+       time_t expire_at;
+       aHush *next;
+       aHush *prev;    
+};
+
+/* tkl:
+ *   TKL_KILL|TKL_GLOBAL       = Global K:Line (G:Line)
+ *   TKL_ZAP|TKL_GLOBAL                = Global Z:Line (ZLINE)
+ *   TKL_KILL                  = Timed local K:Line
+ *   TKL_ZAP                   = Local Z:Line
+ */
+#define TKL_KILL       0x0001
+#define TKL_ZAP                0x0002
+#define TKL_GLOBAL     0x0004
+
+
+struct t_kline {
+       int     type;
+       char    *usermask;
+       char    *hostmask;
+       char    *reason;
+       char    *setby;
+       time_t  expire_at;
+       time_t  set_at;
+       aTKline *next;
+       aTKline *prev;  
+};
+
+struct t_fline {
+       char *mask;
+       char *reason;
+       int  type;
+       aFline *next;
+       aFline *prev;
+};
+
+struct t_crline {
+       char *channel;
+       int  type;
+       aCRline *next, *prev;
+};
+
+struct t_vhline {
+       char    *login;
+       char    *password;
+       char    *vhost;
+       int     type;
+       aVHline *next, *prev;
+};
+
+struct Client  {
+       struct  Client *next, *prev, *hnext;
+       anUser  *user;          /* ...defined, if this is a User */
+       aServer *serv;          /* ...defined, if this is a server */
+        int     tag;            /* tag */
+       int     iown;           /* 1 if mine, 0 if not */
+#ifdef USE_SERVICES
+       aService *service;
+#endif
+       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 */
+       time_t  nextnick;       /* Time the next nick change will be allowed */
+       time_t  nexttarget;     /* Time until a change in targets is allowed */
+       u_char targets[MAXTARGETS]; /* Hash values of current targets */        
+       long    flags;          /* client flags */
+       long    umodes;         /* client usermodes */
+       aClient *from;          /* == self, if Local Client, *NEVER* NULL! */
+       int     fd;             /* >= 0, for local clients */
+       int     hopcount;       /* number of servers to this 0 = local */
+        int     curruser;       /* Number of users on this server */
+       short   status;         /* Client type */
+       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 */
+       char    virthost[HOSTLEN+1]; /* hidden host */
+       aClient *srvptr;        /* Server introducing this.  May be &me */
+       Link    *history;       /* Whowas linked list */
+       /*
+       ** 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).
+       */
+       int     count;          /* Amount of data in buffer */
+       char    buffer[BUFSIZE]; /* Incoming message buffer */
+       short   lastsq;         /* # of 2k blocks when sendqueued called last*/
+       dbuf    sendQ;          /* Outgoing message queue--if socket full */
+       dbuf    recvQ;          /* Hold for data incoming yet to be parsed */
+#ifdef NOSPOOF
+       u_int32_t       nospoof;        /* Anti-spoofing random number */
+#endif
+       long    oflag;          /* Operator access flags -Cabal95 */
+       long    proto;          /* ProtoCtl options */
+       long    sendM;          /* Statistics: protocol messages send */
+       long    sendK;          /* Statistics: total k-bytes send */
+       long    receiveM;       /* Statistics: protocol messages received */
+#ifndef NO_FDLIST
+        long    lastrecvM;         /* to check for activity --Mika */
+        int     priority;             
+#endif
+       long    receiveK;       /* Statistics: total k-bytes received */
+       u_short sendB;          /* counters to count upto 1-k lots of bytes */
+       u_short receiveB;       /* sent and received. */
+       aClient *acpt;          /* listening client which we accepted from */
+       Link    *confs;         /* Configuration record associated */
+       int     authfd;         /* fd for rfc931 authentication */
+#ifdef SOCKSPORT
+       int     socksfd;
+#endif
+       struct  in_addr ip;     /* keep real ip# too */
+       u_short port;           /* and the remote port# too :-) */
+       struct  hostent *hostp;
+       u_short notifies;       /* Keep track of count of notifies */
+       Link    *notify;        /* Links to clients notify-structures */
+       LOpts   *lopt;          /* Saved /list options */
+#ifdef pyr
+       struct  timeval lw;
+#endif
+       char    sockhost[HOSTLEN+1]; /* This is the host name from the socket
+                                    ** and after which the connection was
+                                    ** accepted.
+                                    */
+       char    passwd[PASSWDLEN+1];
+#ifdef DEBUGMODE
+       time_t  cputime;
+#endif
+};
+
+#define        CLIENT_LOCAL_SIZE sizeof(aClient)
+#define        CLIENT_REMOTE_SIZE offsetof(aClient,count)
+
+/*
+ * statistics 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  is_cbs; /* bytes sent to clients */
+       unsigned short  is_cbr; /* bytes received to clients */
+       unsigned short  is_sbs; /* bytes sent to servers */
+       unsigned short  is_sbr; /* bytes received to servers */
+       unsigned long   is_cks; /* k-bytes sent to clients */
+       unsigned long   is_ckr; /* k-bytes received to clients */
+       unsigned long   is_sks; /* k-bytes sent to servers */
+       unsigned long   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 ListOptions {
+       LOpts   *next;
+       Link    *yeslist, *nolist;
+       int     starthash;
+       short int       showall;
+       unsigned short  usermin;
+       int     usermax;
+       time_t  currenttime;
+       time_t  chantimemin;
+       time_t  chantimemax;
+       time_t  topictimemin;
+       time_t  topictimemax;
+};
+
+/* mode structure for channels */
+struct SMode   {
+#ifndef USE_LONGMODE
+       unsigned int    mode;
+#else
+       long    mode;
+#endif
+       int     limit;
+       char    key[KEYLEN+1];
+       char    link[LINKLEN+1];
+        /* x:y */
+       int     msgs; /* x */
+       int     per;  /* y */
+       int     kmode; /* mode  0 = kick  1 = ban */
+};
+
+/* Message table structure */
+
+struct Message {
+       char    *cmd;
+       int     (* func)();
+       unsigned int    count;
+       int     parameters;
+       char    flags;
+               /* bit 0 set means that this command is allowed to be used
+                * only on the average of once per 2 seconds -SRB */
+       u_char  token[2]; /* Cheat for tokenized value */
+       unsigned long   bytes;
+#ifdef DEBUGMODE
+       unsigned long   lticks;
+       unsigned long   rticks;
+#endif
+};
+
+/* Used for notify-hash buckets... -Donwulff */
+
+struct Notify {
+       aNotify *hnext;
+       time_t  lasttime;
+       Link    *notify;
+       char    nick[1];
+};
+
+/* general link structure used for chains */
+
+struct SLink   {
+       struct  SLink   *next;
+       int       flags;
+       aFloodOpt *flood;
+       union {
+               aClient *cptr;
+               aChannel *chptr;
+               aConfItem *aconf;
+               aNotify *nptr;
+               aName *whowas;
+               char    *cp;
+                struct {
+                  char *banstr;
+                  char *who;
+                  time_t when;
+                } ban;
+       } value;
+};
+
+struct SBan    {
+       struct  SBan    *next;
+       char *banstr;
+       char *who;
+       time_t when;
+};
+
+struct DSlink {
+        struct  DSlink  *next;
+        struct  DSlink  *prev;
+        union {
+                aClient *cptr;
+                aChannel *chptr;
+                aConfItem *aconf;
+                char    *cp;
+        } value;
+};
+
+/* channel structure */
+
+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;
+       int     users;
+       Link    *members;
+       Link    *invites;
+       Link    *blist;
+       Ban     *banlist;
+       Ban     *exlist; /* exceptions */
+       char    chname[1];
+};
+
+/*
+** Channel Related macros follow
+*/
+
+/* Channel related flags */
+
+#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 */
+/* Bans are stored in separate linked list, so phase this out? */
+#define        CHFL_BAN        0x0020 /* ban channel flag */
+#define CHFL_CHANOWNER         0x0040 /* channel owner */
+#define CHFL_CHANPROT          0x0080 /* chan op protection */
+#define CHFL_HALFOP            0x0100 /* halfop */
+#define CHFL_EXCEPT            0x0200 /* phase this out ? +e */
+
+#define        CHFL_OVERLAP    (CHFL_CHANOWNER|CHFL_CHANPROT|CHFL_CHANOP|CHFL_VOICE|CHFL_HALFOP)
+
+/* Channel 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_TOPICLIMIT         0x0020
+#define MODE_CHANOWNER         0x0040
+#define MODE_CHANPROT          0x0080
+#define        MODE_HALFOP                     0x0100
+#define MODE_EXCEPT                    0x0200
+#define        MODE_BAN                        0x0400
+#define        MODE_INVITEONLY         0x0800
+#define        MODE_NOPRIVMSGS         0x1000
+#define        MODE_KEY                        0x2000
+#define        MODE_LIMIT                      0x4000
+#define MODE_RGSTR                     0x8000
+#define MODE_RGSTRONLY                         0x10000
+#define MODE_LINK                      0x20000
+#define MODE_NOCOLOR           0x40000
+#define MODE_OPERONLY          0x80000
+#define MODE_ADMONLY                   0x100000
+#define MODE_NOKICKS                   0x200000
+#define MODE_STRIP             0x400000
+#define MODE_NOKNOCK           0x800000
+#define MODE_NOINVITE                  0x1000000
+#define MODE_FLOODLIMIT                0x2000000
+#define MODE_NOHIDING          0x4000000
+#define is_halfop is_half_op
+/*
+ * mode flags which take another parameter (With PARAmeterS)
+ */
+#define        MODE_WPARAS     (MODE_HALFOP|MODE_CHANOP|MODE_VOICE|MODE_CHANOWNER|MODE_CHANPROT|MODE_BAN|MODE_KEY|MODE_LINK|MODE_LIMIT|MODE_EXCEPT)
+/*
+ * Undefined here, these are used in conjunction with the above modes in
+ * the source.
+#define        MODE_DEL       0x200000000
+#define        MODE_ADD       0x400000000
+ */
+
+#define        HoldChannel(x)          (!(x))
+/* name invisible */
+#define        SecretChannel(x)        ((x) && ((x)->mode.mode & MODE_SECRET))
+/* channel not shown but names are */
+#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        IsChannelName(name) ((name) && (*(name) == '#' || *(name) == '&' || *(name) == '+'))
+#define IsModelessChannel(name) ((name) && (*(name) == '+'))
+
+#define IsMember(blah,chan) ((blah && blah->user && \
+                find_channel_link((blah->user)->channel, chan)) ? 1 : 0)
+
+struct s_gline {
+       char   name[128];
+       char   sname[128];
+       char   host[128];
+       char   reason[128];
+       char   timemsg[128];
+       long   expire_at;
+       long   set_at;
+};
+
+struct FloodOpt {
+       int     nmsg;
+       time_t  lastmsg;
+};
+
+/* Misc macros */
+
+#define        BadPtr(x) (!(x) || (*(x) == '\0'))
+
+#define        isvalid(c) (((c) >= 'A' && (c) <= '~') || isdigit(c) || (c) == '-')
+
+#define        MyConnect(x)                    ((x)->fd >= 0)
+#define        MyClient(x)                     (MyConnect(x) && IsClient(x))
+#define        MyOper(x)                       (MyConnect(x) && IsOper(x))
+
+#define TStime() (time(NULL)+TSoffset)
+
+/* Lifted somewhat from Undernet code --Rak */
+
+#define IsSendable(x)          (DBufLength(&x->sendQ) < 2048)
+#define DoList(x)              ((x)->lopt)
+
+/* String manipulation macros */
+
+/* strncopynt --> strncpyzt to avoid confusion, sematics changed
+   N must be now the number of bytes in the array --msa */
+#define        strncpyzt(x, y, N) do{(void)strncpy(x,y,N);x[N-1]='\0';}while(0)
+#define        StrEq(x,y)      (!strcmp((x),(y)))
+
+/* used in SetMode() in channel.c and m_umode() in s_msg.c */
+
+#define        MODE_NULL      0
+#define        MODE_ADD       0x40000000
+#define        MODE_DEL       0x20000000
+
+/* 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 */
+
+/* used when sending to #mask or $mask */
+
+#define        MATCH_SERVER  1
+#define        MATCH_HOST    2
+
+/* used for async dns values */
+
+#define        ASYNC_NONE      (-1)
+#define        ASYNC_CLIENT    0
+#define        ASYNC_CONNECT   1
+#define        ASYNC_CONF      2
+#define        ASYNC_SERVER    3
+
+/* misc variable externs */
+
+extern char    *version, *infotext[], *dalinfotext[], *unrealcredits[];
+extern char    *generation, *creation;
+extern  char   *gnulicense[];
+/* misc defines */
+
+#define        FLUSH_BUFFER    -2
+#define        UTMP            "/etc/utmp"
+#define        COMMA           ","
+
+#endif /* __struct_include__ */
diff --git a/include/sys.h b/include/sys.h
new file mode 100644 (file)
index 0000000..c768e9d
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *   IRC - Internet Relay Chat, include/sys.h
+ *   Copyright (C) 1990 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$
+ */
+
+#ifndef        __sys_include__
+#define __sys_include__
+#ifdef ISC202
+#include <net/errno.h>
+#else
+# ifndef _WIN32
+#include <sys/errno.h>
+# else
+#include <errno.h>
+# endif
+#endif
+
+#include "setup.h"
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#else
+#include <stdarg.h>
+#endif
+
+#ifdef UNISTDH
+#include <unistd.h>
+#endif
+#ifdef STDLIBH
+#include <stdlib.h>
+#endif
+
+#ifdef STRINGSH
+#include <strings.h>
+#else
+# ifdef        STRINGH
+# include <string.h>
+# endif
+#endif
+
+#ifndef GOT_STRCASECMP
+#define        strcasecmp      mycmp
+#define        strncasecmp     myncmp
+#endif
+
+#ifdef NOINDEX
+#define   index   strchr
+#define   rindex  strrchr
+/*
+extern char    *index PROTO((char *, char));
+extern char    *rindex PROTO((char *, char));
+*/
+#endif
+#ifdef NOBCOPY
+#define bcopy(x,y,z)   memcpy(y,x,z)
+#define bcmp(x,y,z)    memcmp(x,y,z)
+#define bzero(p,s)     memset(p,0,s)
+#endif
+
+#ifdef AIX
+#include <sys/select.h>
+#endif
+#if defined(HPUX )|| defined(AIX) || defined(_WIN32)
+#include <time.h>
+#ifdef AIX
+#include <sys/time.h>
+#endif
+#else
+#include <sys/time.h>
+#endif
+
+#if !defined(DEBUGMODE)
+# ifndef _WIN32
+#  define MyFree(x)    if ((x) != NULL) free(x)
+# else
+#  define MyFree(x)       if ((x) != NULL) GlobalFree(x)
+# endif
+#else
+#define        free(x)         MyFree(x)
+#endif
+
+#ifdef NEXT
+#define VOIDSIG int    /* whether signal() returns int of void */
+#else
+#define VOIDSIG void   /* whether signal() returns int of void */
+#endif
+
+#ifdef SOL20
+#define OPT_TYPE char  /* opt type for get/setsockopt */
+#else
+#define OPT_TYPE void
+#endif
+
+/*
+ * Different name on NetBSD, FreeBSD, and BSDI
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__bsdi__) || defined(__linux__) || defined(__APPLE__)
+#define dn_skipname  __dn_skipname
+#endif
+
+#ifndef _WIN32
+extern VOIDSIG dummy();
+#endif
+
+#ifdef DYNIXPTX
+#define        NO_U_TYPES
+typedef unsigned short n_short;         /* short as received from the net */
+typedef unsigned long   n_long;         /* long as received from the net */
+typedef unsigned long   n_time;         /* ms since 00:00 GMT, byte rev */
+#define _NETINET_IN_SYSTM_INCLUDED
+#endif
+
+#ifdef NO_U_TYPES
+typedef        unsigned char   u_char;
+typedef        unsigned short  u_short;
+typedef        unsigned long   u_long;
+typedef        unsigned int    u_int;
+#endif
+
+#ifdef _WIN32
+#define MYOSNAME "Win32"
+#endif
+
+#endif /* __sys_include__ */
diff --git a/include/userload.h b/include/userload.h
new file mode 100644 (file)
index 0000000..bf16ba0
--- /dev/null
@@ -0,0 +1,54 @@
+/****************************************************************************
+ *  Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
+ *  Written 2/93.  Originally grafted into irc2.7.2g 4/93.
+ *
+ *   IRC - Internet Relay Chat, ircd/userload.h
+ *   Copyright (C) 1990 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$ */
+
+/* This needs to be defined for the counts to be correct--it should be the
+ * default anyway, as opers shouldn't be superior to lusers except where
+ * absolutely necessary, and here it isn't necessary.                       */
+#ifndef SHOW_INVISIBLE_LUSERS
+#define SHOW_INVISIBLE_LUSERS
+#endif
+
+struct current_load_struct {
+  u_short client_count, local_count, conn_count;
+  u_long  entries;
+};  
+
+extern struct current_load_struct current_load_data;
+
+struct load_entry {
+  struct  load_entry *prev;
+  u_short client_count, local_count, conn_count;
+#ifdef DEBUGMODE
+  u_short cpu_usage;
+#endif
+  long    time_incr;
+};
+
+extern struct load_entry *load_list_head, *load_list_tail,
+                         *load_free_head, *load_free_tail;
+
+
+extern void initload PROTO ((void));
+extern void update_load PROTO ((void));
+extern void calc_load PROTO ((aClient *, char *));
diff --git a/include/version.h b/include/version.h
new file mode 100644 (file)
index 0000000..be26381
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+**
+** version.h
+** UnrealIRCd
+** $Id$
+*/
+#ifndef __versioninclude
+#define __versioninclude 1
+
+#include "relinfo.h"
+/* 
+ * Mark of settings
+ */
+#ifdef DEBUGMODE
+#define DEBUGMODESET "+(debug)"
+#else
+#define DEBUGMODESET ""
+#endif
+/**/
+#ifdef DEBUG
+#define DEBUGSET "(Debug)"
+#else
+#define DEBUGSET ""
+#endif 
+/**/
+#define COMPILEINFO DEBUGMODESET DEBUGSET
+#ifndef WEBTV
+#define XTRAINFO ""
+#else
+#define XTRAINFO "(WebTV)"
+#endif
+/*
+ * Version Unreal3.0
+ */
+#define UnrealProtocol                 2300
+#define PATCH1                 "3"
+#define PATCH2                 ".0"
+#define PATCH3                 "-Morrigan"
+#define PATCH4                 "(fix)"
+#define PATCH5                 ""
+#define PATCH6                 ""
+#define PATCH7                 ""
+#define PATCH8                 COMPILEINFO
+#define PATCH9                 XTRAINFO
+
+#ifndef _WIN32
+#define BASE_VERSION "Unreal"
+#else
+#define BASE_VERSION "UnrealIRCd/32 v"
+#endif
+
+#define VERSIONONLY            PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7
+
+#endif /* __versioninclude */ 
diff --git a/include/whowas.h b/include/whowas.h
new file mode 100644 (file)
index 0000000..7d747de
--- /dev/null
@@ -0,0 +1,120 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/whowas.h
+ *   Copyright (C) 1990  Markku Savela
+ *
+ *   This program is free software; you can 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$
+ *
+ * $Log$
+ * Revision 1.1.1.1  2000/01/30 12:16:34  stskeeps
+ * Begin of CVS at cvs.unreal.sourceforge.net
+ *
+ *
+ * Revision 1.1.1.1  1999/09/01 23:20:37  stskeeps
+ *
+ * Revision 1.1.1.1  1999/07/22 13:56:41  stskeeps
+ * 16:56 22-07-99 techie
+ * - Started on using CVS to develop Unreal
+ *
+ *
+ * Revision 1.1.1.1  1999/07/21 10:48:18  stskeeps
+ * 12:47 GMT+2 21 July 1999 - Techie
+ * Starting Unreal with CVS.. 
+ *
+ *
+ * Revision 1.2  1997/12/29 07:17:35  wd
+ * df4.6.2
+ * ee CHANGES for updates
+ * -wd
+ *
+ * Revision 1.1.1.1  1997/08/22 17:23:01  donwulff
+ * Original import from the "deadlined" version.
+ *
+ * Revision 1.1.1.1  1996/11/18 07:53:42  explorer
+ * ircd 4.3.3 -- about time
+ *
+ * Revision 1.1.1.1.4.1  1996/09/16 02:45:41  donwulff
+ * *** empty log message ***
+ *
+ * Revision 6.1  1991/07/04  21:04:39  gruner
+ * Revision 2.6.1 [released]
+ *
+ * Revision 6.0  1991/07/04  18:05:08  gruner
+ * frozen beta revision 2.6.1
+ *
+ */
+
+#ifndef        __whowas_include__
+#define __whowas_include__
+
+#ifndef PROTO
+#if __STDC__
+#      define PROTO(x) x
+#else
+#      define PROTO(x) ()
+#endif /* __STDC__ */
+#endif /* ! PROTO */
+
+/*
+** WHOWAS structure moved here from whowas.c
+*/
+typedef struct aname {
+       anUser  *ww_user;
+       aClient *ww_online;
+       time_t  ww_logout;
+        long    ww_umodes;
+       char    ww_nick[NICKLEN+1];
+       char    ww_info[REALLEN+1];
+} aName;
+
+/*
+** add_history
+**     Add the currently defined name of the client to history.
+**     usually called before changing to a new name (nick).
+**     Client must be a fully registered user (specifically,
+**     the user structure must have been allocated).
+*/
+void   add_history PROTO((aClient *));
+
+/*
+** off_history
+**     This must be called when the client structure is about to
+**     be released. History mechanism keeps pointers to client
+**     structures and it must know when they cease to exist. This
+**     also implicitly calls AddHistory.
+*/
+void   off_history PROTO((aClient *));
+
+/*
+** get_history
+**     Return the current client that was using the given
+**     nickname within the timelimit. Returns NULL, if no
+**     one found...
+*/
+aClient        *get_history PROTO((char *, time_t));
+                                       /* Nick name */
+                                       /* Time limit in seconds */
+
+int    m_whowas PROTO((aClient *, aClient *, int, char *[]));
+
+/*
+** for debugging...counts related structures stored in whowas array.
+*/
+void   count_whowas_memory PROTO((int *, int *, u_long *));
+
+#endif /* __whowas_include__ */
diff --git a/include/win32/settings.h b/include/win32/settings.h
new file mode 100644 (file)
index 0000000..e49c020
--- /dev/null
@@ -0,0 +1,3 @@
+#define SPATH "."
+#define DPATH "."
+#define DOMAINNAME "irc.net"
\ No newline at end of file
diff --git a/include/win32/setup.h b/include/win32/setup.h
new file mode 100644 (file)
index 0000000..e255d0e
--- /dev/null
@@ -0,0 +1,49 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/win32/setup.h
+ *   Copyright (C) 1999 Carsten Munk
+ *
+ *   This program is free software; you can 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 __setup_include__
+#define __setup_include__
+#undef  PARAMH
+#undef  UNISTDH
+#define STRINGH
+#undef  STRINGSH
+#define STDLIBH
+#undef  STDDEFH
+#undef  SYSSYSLOGH
+#define NOINDEX
+#define NOBCOPY
+#define NEED_STRERROR
+#define NEED_STRTOKEN
+#undef  NEED_STRTOK
+#undef  NEED_INET_ADDR
+#undef  NEED_INET_NTOA
+#define NEED_INET_NETOF
+#define GETTIMEOFDAY
+#undef  LRAND48
+#define MALLOCH <malloc.h>
+#undef  NBLOCK_POSIX
+#undef  POSIX_SIGNALS
+#undef  TIMES_2
+#undef  GETRUSAGE_2
+
+#define NO_U_TYPES
+#define NEED_U_INT32_T
+#endif
diff --git a/ircd b/ircd
new file mode 100755 (executable)
index 0000000..aaa3fc6
--- /dev/null
+++ b/ircd
@@ -0,0 +1,79 @@
+#!/bin/sh
+# IRCD Script v3.0
+# $Id$ 
+#
+DIR=`pwd`
+DATE=`date +"%a, %b %e %Y"`
+TIME=`date +"%H:%M:%S %Z"`
+IRCDPID="ircd.pid"
+BACKUP="ircd.bak"
+
+if [ -r $IRCDPID ]; then
+mv -f $IRCDPID $BACKUP
+src/ircd
+sleep 1
+if [ ! -r $IRCDPID ]; then
+mv -f $BACKUP $IRCDPID
+echo "|--------------------------------------------|"
+echo "|              **** ERROR ****               |"
+echo "|             Possible problems:             |"
+echo "| (1) IRCd already running.                  |"
+echo "| (2) The correct IP was not placed in the   |"
+echo "|     M:line of the ircd.conf.               |"
+echo "| (3) DPATH or SPATH's are incorrect. Run    |"
+echo "|     ./Config to correct that.              |"
+echo "| (4) Someone else is running an ircd on the |"
+echo "|     default port you chose in ircd.conf.   |"
+echo "|********************************************|"
+echo "| If you can't get Unreal IRCd to work - go  |"
+echo "| to /server irc.flirt.org and join          |"
+echo "| #UnrealIRCd or mail us at                  |"
+echo "|    unreal-support@lists.sourceforge.net    |"
+echo "|                                            |"
+echo "|--------------------------------------------|"
+exit
+else
+echo "|----------------------------------------"
+echo "| UnrealIRCD successfully loaded."
+echo "| Directory: $DIR"
+echo "| Date: $DATE"
+echo "| Time: $TIME"
+PID=`cat ircd.pid`
+echo "| Process ID: $PID"
+echo "|----------------------------------------"
+rm -f $BACKUP
+  fi
+else
+src/ircd
+sleep 2
+if [ ! -r $IRCDPID ]; then
+echo "|--------------------------------------------|"
+echo "|              **** ERROR ****               |"
+echo "|             Possible problems:             |"
+echo "| (1) IRCd already running.                  |"
+echo "| (2) The correct IP was not placed in the   |"
+echo "|     M:line of the ircd.conf.               |"
+echo "| (3) DPATH or SPATH's are incorrect. Run    |"
+echo "|     ./Config to correct that.              |"
+echo "| (4) Someone else is running an ircd on the |"
+echo "|     default port you chose in ircd.conf.   |"
+echo "|********************************************|"
+echo "| If you can't get Unreal IRCd to work - go  |"
+echo "| to /server irc.global-irc.net and join     |"
+echo "| #Global - Try ask in the channel or /msg   |"
+echo "| Stskeeps/Techie(me!) or else-- email me at |"
+echo "|  stskeeps@tspre.org                        |"
+echo "|--------------------------------------------|"
+
+exit
+else
+echo "|----------------------------------------"
+echo "| UnrealIRCD successfully loaded."
+echo "| Directory: $DIR"
+echo "| Date: $DATE"
+echo "| Time: $TIME"
+PID=`cat ircd.pid`
+echo "| Process ID: $PID"
+echo "|----------------------------------------"
+  fi
+fi
diff --git a/ircdcron/ircd.cron b/ircdcron/ircd.cron
new file mode 100755 (executable)
index 0000000..209e327
--- /dev/null
@@ -0,0 +1 @@
+0,10,20,30,40,50 * * * *   /home/mydir-to/ircdcron/ircdchk >/dev/null 2>&1
diff --git a/ircdcron/ircdchk b/ircdcron/ircdchk
new file mode 100755 (executable)
index 0000000..11383d1
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+#
+# UnrealIRCD Crontab v2.1
+# $Id$
+#
+# This is a script suitable for use in a crontab.  It checks to make sure
+# your ircd is running.  YOU NEED A SEPARATE CRON JOB FOR EACH IRCD.  If your
+# ircd isn't found, it'll try to start it back up.
+#
+# You'll need to edit this script for your ircd.
+#
+# To check for your ircd every 10 minutes, put the following line in your
+# crontab:
+#    0,10,20,30,40,50 * * * *   /home/mydir/ircdchk
+# And if you don't want to get email from crontab when it checks you ircd,
+# put the following in your crontab:
+#    0,10,20,30,40,50 * * * *   /home/mydir/ircdchk >/dev/null 2>&1
+#
+# change this to the mail address to mail output to:
+MAIL=me
+# change this to the directory you run your ircd from:
+dir="../"
+
+# change this to the name of your ircd's file in that directory:
+ircdexe="ircd"
+
+# I wouldn't touch this if I were you.
+ircdname="ircd.pid"
+
+########## you probably don't need to change anything below here ##########
+
+cd $dir
+if test -r $ircdname; then
+  # there is a pid file -- is it current?
+  ircdpid=`cat $ircdname`
+  if `kill -CHLD $ircdpid >/dev/null 2>&1`; then
+    # it's still going
+    # back out quietly
+    exit 0
+  fi
+  echo "UnrealIRCd Crontab notice:"
+  echo ""
+  echo "Stale $ircdname file (erasing it)"
+  rm -f $ircdname
+fi
+echo ""
+echo "Couldn't find the ircd running.  Reloading it..."
+echo ""
+./$ircdexe
diff --git a/ircdreg b/ircdreg
new file mode 100755 (executable)
index 0000000..3ee7166
--- /dev/null
+++ b/ircdreg
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $Id$
+
+lynx http://unreal.sourceforge.net/register.html
diff --git a/killircd b/killircd
new file mode 100755 (executable)
index 0000000..9cf35a1
--- /dev/null
+++ b/killircd
@@ -0,0 +1,29 @@
+#!/bin/sh
+# Kill Script v2.0
+# Created by Potvin
+# $Id$
+DIR=`pwd`
+DATE=`date +"%a, %b %e %Y"`
+TIME=`date +"%H:%M:%S %Z"`
+IRCDPID="ircd.pid"
+
+if [ ! -r $IRCDPID ]; then
+clear
+echo "|--------------------------------------------|"
+echo "|              **** ERROR ****               |"
+echo "|             Possible problems:             |"
+echo "| (1) $IRCDPID not found                     |"
+echo "| (2) The IRCd is not running                |"
+echo "|--------------------------------------------|"
+else
+PID=`cat $IRCDPID`
+kill -9 $PID >/dev/null 2>&1
+rm -f $IRCDPID
+echo "|----------------------------------------"
+echo "| UnrealIRCD successfully shutdown."
+echo "| Directory: $DIR"
+echo "| Date: $DATE"
+echo "| Time: $TIME"
+echo "| Process ID: $PID"
+echo "|----------------------------------------"
+fi
diff --git a/makeconf b/makeconf
new file mode 100755 (executable)
index 0000000..b89ff08
--- /dev/null
+++ b/makeconf
@@ -0,0 +1,543 @@
+#!/bin/sh
+# $Id$
+# Defaults
+#
+TIME=`date +"%H:%M:%S %Z"`
+DATE=`date +"%a, %b %e %Y"`
+IRCDCONF="ircd.conf"
+SERVNAME="Server.IRC.net"
+COMMENT="IRC server!"
+ADMIN="Admin-name"
+ADMNICK="Admin"
+ADMADDR="admin@no.where.com"
+OPERNAME="admin"
+OPERADDR="*@*"
+OPERPASS="password"
+PORT="6667"
+OPRT="default"
+LINKPASS="linkpass"
+VIRTUAL="1.2.3.4"
+ENCRYPT="Yes"
+FLAGS="OAZHWe"
+RESTARTPASS="restartpass"
+DIEPASS="diepass"
+SERVICES="Services.ShadowNet.Org"
+
+# these are so I can use stuff like $1 without it replacing it...like by
+# using $dlrsgn$uno for $1
+dlrsgn="$"
+uno="1"
+dos="2"
+
+# remove the temp file if it exists
+rm -f mkconf.tmp
+
+# make a quick script for replacing one line with another
+
+cat > repl_str << __EOF__
+sed -e "s@^$dlrsgn$uno\(.*\)@$dlrsgn$dos" $IRCDCONF > mkconf.tmp
+cp mkconf.tmp $IRCDCONF
+rm mkconf.tmp
+__EOF__
+
+# mark repl_str as an executable
+chmod +x repl_str
+rm -f repl_str
+# Checking out how to specify not to make a new line with the current OS
+c=''
+n=''
+2>/dev/null
+if [ "`eval echo -n 'a'`" = "-n a" ]; then
+       c='\c'
+else
+       n='-n'
+fi
+
+# If Settings exist, load the info, otherwise tell them to run Config.
+
+if [ -r Settings ]; then
+       . Settings
+else
+       echo "Hmm, you need to run Config first!"
+       echo "Type ./Config"
+       echo "If you have run Config, make sure you are in the directory"
+       echo "you ran it from."
+       exit 1
+fi
+
+CONF=$IRCDCONF
+
+if [ -r "$CONF" ]; then
+       echo "$IRCDCONF found"
+       echo " "
+       echo "   I don't suggest running this with the conf file already"
+       echo "existing, since you will lose all the data in your conf file."
+       echo "This script is just for creating one. If you want to recreate"
+       echo "a conf file, type 'recreate'."
+       echo $n " [exit] -> $c"
+       read cc
+
+       if [ "$cc" != "recreate" ]; then
+               echo " "
+               echo "   OK, do you want to edit $IRCDCONF using an editor?"
+               echo "If so, specify the editor you want to use. Otherwise,"
+               echo "type 'exit'."
+               EDITFND="not found"
+
+                if [ -r /usr/bin/pico ]; then
+                        EDITFND="pico"
+                fi
+
+                if [ -r /usr/bin/joe ]; then
+                        EDITFND="joe"
+                fi
+
+               if [ -r /usr/bin/vi ]; then
+                       EDITFND="vi"
+               fi
+
+               if [ -r /usr/bin/vim ]; then
+                       EDITFND="vim"
+               fi
+
+               while [ "c" = "c" ]; do
+                       echo $n " [$EDITFND] -> $c"
+                       read EDITOR
+
+                       if [ -z "$EDITOR" ]; then
+                               EDITOR="$EDITFND"
+                       fi
+
+                       if [ "$EDITOR" = "exit" ]; then
+                               echo "Have a nice day."
+                               exit 1
+                       fi
+
+                       if [ -f $EDITOR ]; then
+                               $EDITOR $CONF
+                               exit 1
+                       fi
+
+                       if [ -f /usr/bin/$EDITOR ]; then
+                               /usr/bin/$EDITOR $CONF
+                               exit 1
+                       fi
+
+                       echo "   Editor not found. Specify a valid editor or"
+                       echo "type 'exit' to quit this script."
+               done
+
+       fi
+
+       mv $CONF "$CONF.saved"
+       rm $CONF
+       echo "$IRCDCONF has been renamed to ircd.conf.saved"
+else
+       echo "$IRCDCONF is not found. (good)"
+fi
+
+clear
+echo "|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|"
+echo "| Welcome to the $IRCDCONF generator. |"
+echo "|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=|"
+echo " "
+echo "What will your server name be? (ie: $SERVNAME)"
+echo $n " [$SERVNAME] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       SERVNAME="$cc"
+fi
+
+echo " "
+echo "What is your IRC server's IP? (ie: $VIRTUAL)"
+echo "Use * to bind to all interfaces"
+echo $n " [$VIRTUAL] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+        VIRTUAL="$cc"
+fi
+
+echo " "
+echo "Server comment? (ie: Main Hub Server)"
+echo $n " [$COMMENT] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       COMMENT="$cc"
+fi
+
+echo " "
+echo "Main port? (ie: 6667)"
+echo $n " [$PORT] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       PORT="$cc"
+fi
+
+echo " "
+echo "What is your real name? (ie: John Doe)"
+echo $n " [$ADMIN] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       ADMIN="$cc"
+fi
+
+echo " "
+echo "What is your IRC nickname? (ie: JD)"
+echo $n " [$ADMNICK] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       ADMNICK="$cc"
+fi
+
+echo " "
+echo "What is your e-mail address? (ie: john@doe.com)"
+echo $n " [$ADMADDR] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       ADMADDR="$cc"
+fi
+
+echo " "
+OPERNAME="$ADMNICK"
+echo "What will your opername be for your O:line? (ie: johndoe)"
+echo $n " [$OPERNAME] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       OPERNAME="$cc"
+fi
+
+echo " "
+echo "What oper flags do you want to have? (ie: OAWZ)"
+echo "Some flags to choose from:"
+echo "  o = local oper"
+echo "  O = global oper"
+echo "  N = network administrator"
+echo "  A = server administrator"
+echo "  C = co administrator"
+echo "  T = technical administrator"
+echo "  read unrealircd.doc for more info about O:line flags)"
+echo $n " [$FLAGS] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       FLAGS="$cc"
+fi
+
+        echo " "
+        ENCRYPT=""
+        ENCRYPT="bad"
+        while [ "$ENCRYPT" = "bad" ]; do
+                echo "Do you use encrypted oper passwords?"
+                echo $n " [Yes] -> $c"
+                read cc
+                if [ -z "$cc" ]; then
+                        cc="Yes"
+                fi
+                case "$cc" in
+                        [Yy]*)
+                                ENCRYPT="Yes"
+                                ;;
+                        [Nn]*)
+                                ENCRYPT="No"
+                                ;;
+                        *)
+                                echo "Please specify yes or no."
+                                ENCRYPT="bad"
+                                ;;
+                esac
+        done
+
+if [ "$ENCRYPT" = "Yes" ] ; then
+echo "Compile the file called mkpasswd.c in the 'crypt' directory"
+echo "Then run it (./mkpasswd) and input the passwd to be encrypted"
+echo "Then copy the output into the passwd slot in the O:line"
+echo "NOTE: You can encrypt on irc via /mkpasswd <passwd>"
+fi
+
+echo " "
+echo "What will your /oper password be? (ie: snoopy67)"
+echo $n " [$OPERPASS] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       OPERPASS="$cc"
+fi
+
+echo " "
+echo "What is your user@host mask on IRC? (ie: *@*.toronto.globalserve.net)"
+echo $n " [$OPERADDR] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+       OPERADDR="$cc"
+fi
+
+echo " "
+echo "What do you want your die password to be?"
+echo $n " [$DIEPASS] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+        DIEPASS="$cc"
+fi
+
+echo " "
+echo "What do you want your restart password to be?"
+echo $n " [$RESTARTPASS] -> $c"
+read cc
+if [ ! -z "$cc" ]; then
+        RESTARTPASS="$cc"
+fi
+
+echo " "
+echo "If your running services, or linking to a network that has"
+echo "services, please state the services servername."
+echo "If you are running a non-services network, just type 'next'"
+echo $n " [$SERVICES] -> $c"
+read cc
+
+#if [ ! -z "$cc" ]; then
+#        SERVICES="$cc"
+#fi
+
+if [ "$cc" = "next" ]; then
+        SERVICES="No.Services.Selected"
+elif [ ! -z "$cc" ]; then
+        SERVICES="$cc"
+fi
+
+cat > $CONF << __EOF__
+########################
+#
+# Filename:  $IRCDCONF
+#  Created:  $DATE - $TIME
+#
+########################
+
+############ Server Info ############
+M:$SERVNAME:$VIRTUAL:$COMMENT:$PORT
+#####################################
+
+############ Administrator Information #############
+A:$ADMIN:$ADMNICK:$ADMADDR
+####################################################
+
+############ Y-lines #############
+# Client Y:lines
+Y:1:90:0:$MAXCONNECTIONS:100000
+# Server Y:lines
+Y:50:300:600:1:1000000
+##################################
+
+############ I/Access Lines #############
+I:*@*::*@*::1
+#########################################
+
+############ X:LINE Die/Restart Password ############
+X:$DIEPASS:$RESTARTPASS
+#####################################################
+
+## O-line (O:hostmask:password:opername:flags:1) ##
+O:$OPERADDR:$OPERPASS:$OPERNAME:$FLAGS:1
+###################################################
+
+__EOF__
+
+
+echo " "
+echo "   Would you like to configure any servers for linking?"
+echo "Type the servername, or type 'done' when finished."
+echo $n " [done] -> $c"
+read cc
+
+if [ -z "$cc" ]; then
+       cc="done"
+fi
+
+while [ "$cc" != "done" ]; do
+       THESERV="$cc"
+
+       SHOST="none"
+       while [ "$SHOST" = "none" ]; do
+               echo " "
+               echo "Hostname or ip for the other server? Must be specified."
+               echo $n " [] -> $c"
+               read SHOST
+       done    
+
+       echo " "
+       echo "Password to send to the other server?"
+       echo $n " [$LINKPASS] -> $c"
+       read CLP
+       if [ -z "$CLP" ]; then
+               CLP="$LINKPASS"
+       fi
+
+       echo " "
+       AUTOPORT=""
+       AUTOCONN="bad"
+       while [ "$AUTOCONN" = "bad" ]; do
+               echo " "
+               echo "Should we autconnect to this server?"
+               echo $n " [Yes] -> $c"
+               read cc
+               if [ -z "$cc" ]; then
+                       cc="Yes"
+               fi
+               case "$cc" in
+                       [Yy]*)
+                               AUTOCONN="yes"
+                               echo "What port should we autoconnect to?"
+                               echo $n " [7029] -> $c"
+                               read AUTOPORT
+                               if [ -z "$AUTOPORT" ]; then
+                                       AUTOPORT="7029"
+                               fi
+                               ;;
+                       [Nn]*)
+                               AUTOCONN="no"
+                               ;;
+                       *)
+                               echo "Please specify yes or no."
+                               AUTOCONN="bad"
+                               ;;
+               esac
+       done
+
+       echo " "
+       HUB="bad"
+       while [ "$HUB" = "bad" ]; do
+               echo " "
+               echo "Will this server be a hub?"
+               echo $n " [Yes] -> $c"
+               read cc
+               if [ -z "$cc" ]; then
+                       cc="Yes"
+               fi
+               case "$cc" in
+                       [Yy]*)
+                               HUB="Yes"
+                               ;;
+                       [Nn]*)
+                               HUB="no"
+                               ;;
+                       *)
+                               echo "Please specify yes or no."
+                               HUB="bad"
+                               ;;
+               esac
+       done
+
+       if [ "$HUB" = "Yes" ]; then
+               echo "############ HUB LINES #############" >> $CONF
+               echo "H:*:*:$THESERV" >> $CONF
+               echo "####################################" >> $CONF
+               echo "" >> $CONF
+       fi
+
+        echo "############ C/N LINES #############" >> $CONF
+        echo "C:$SHOST:$CLP:$THESERV:$AUTOPORT:50" >> $CONF
+        echo "N:$SHOST:$CLP:$THESERV::50" >> $CONF
+        echo "####################################" >> $CONF
+       echo "" >> $CONF
+
+       echo " "
+       echo "Type the servername, or type 'done' when finished."
+       echo $n " [done] -> $c"
+       read cc
+       if [ -z "$cc" ]; then
+               cc="done"
+       fi
+done
+
+cat >> $CONF << __EOF__
+############ Uline for Services ############
+U:$SERVICES:*:*
+############################################
+
+############ Q-Lined NickNames ############
+Q::Reserved for services:*C*h*a*n*S*e*r*v*
+Q::Reserved for services:*N*i*c*k*S*e*r*v*
+Q::Reserved for services:*M*e*m*o*S*e*r*v*
+Q::Reserved for services:*H*e*l*p*S*e*r*v*
+Q::Reserved for services:*O*p*e*r*S*e*r*v*
+Q::Reserved for services:*I*n*f*o*S*e*r*v*
+Q::Reserved for Administrator:*Admin*
+Q::Reserved for ircops:*IRC*op*
+Q::Reserved for ircops:*Oper*
+Q::Bug in mIRC:Status
+###########################################
+
+############ PORT LINES #############
+__EOF__
+
+cc="blank"
+echo " "
+echo " "
+echo "   Would you like any extra ports, other than 6667? Enter them here."
+echo "Type 'done' when you are finished. Type 'default' to use 6665-6669/7000."
+while [ "$cc" != "done" ]; do
+       echo $n " [$OPRT] -> $c"
+       read cc
+       if [ -z "$cc" ]; then
+               cc="$OPRT"
+       fi
+       if [ "$cc" = "default" ]; then
+               echo "P:$VIRTUAL:*:*:6660" >> $CONF
+               echo "P:$VIRTUAL:*:*:6661" >> $CONF
+               echo "P:$VIRTUAL:*:*:6662" >> $CONF
+               echo "P:$VIRTUAL:*:*:6663" >> $CONF
+               echo "P:$VIRTUAL:*:*:6664" >> $CONF
+                echo "P:$VIRTUAL:*:*:6665" >> $CONF
+                echo "P:$VIRTUAL:*:*:6666" >> $CONF
+                echo "P:$VIRTUAL:*:*:6668" >> $CONF
+                echo "P:$VIRTUAL:*:*:6669" >> $CONF
+                echo "P:$VIRTUAL:*:*:7000" >> $CONF
+               echo "P:$VIRTUAL:*:*:7029" >> $CONF
+               echo "#####################################" >> $CONF
+               cc="done"
+       fi
+       if [ "$cc" != "done" ]; then
+               if [ $cc = "$PORT" ]; then
+                       echo "  No, $PORT is already defined in the M:line,"
+                       echo "please use a port other than $PORT."
+               else
+                       echo "P:$VIRTUAL:*:*:$cc" >> $CONF
+               fi
+       fi
+       case "$OPRT" in
+               6660) OPRT="done"
+                       ;;
+               6661) OPRT="6660"
+                       ;;
+               6662) OPRT="6661"
+                       ;;
+               6663) OPRT="6662"
+                       ;;
+               6664) OPRT="6663"
+                       ;;
+               6665) OPRT="6664"
+                       ;;
+               6666) OPRT="6665"
+                       ;;
+               6669) OPRT="6666"
+                       ;;
+               6668) OPRT="6669"
+                       ;;
+               6667) OPRT="6668"
+                       ;;
+               *) OPRT="done"
+                       ;;
+       esac
+done
+
+# Make it so ONLY the one who created the conf can read or write.
+chmod 700 $IRCDCONF
+
+cat << __EOF__
+
+
+    OK, $IRCDCONF has been generated according to what you specified.
+Make sure you double check for errors in $IRCDCONF. We recommend that
+you take a look at your $IRCDCONF right now. Thanks for using UnrealIRCd
+
+__EOF__
+               echo "Have a nice day."
+               echo ""
+               exit 1
diff --git a/makefile.win32 b/makefile.win32
new file mode 100644 (file)
index 0000000..5ee2e7a
--- /dev/null
@@ -0,0 +1,177 @@
+#
+# Win32Gui Config File .. By DrBin
+#
+CC=cl
+# Here you put your settings
+FD_SETSIZE=/D FD_SETSIZE=16384
+NS_ADDRESS=/D NS_ADDRESS="\"nospoof@dal.net\""
+CFLAGS=/MT /O2 /G5 /I ./INCLUDE /Fosrc/ /nologo $(FD_SETSIZE) $(NS_ADDRESS) /D _WIN32GUI /D NOSPOOF=1 /c
+INCLUDES=./include/struct.h ./include/config.h ./include/sys.h \
+ ./include/common.h ./include/version.h ./include/h.h ./include/numeric.h \
+ ./include/msg.h ./include/setup.h ./include/dynconf.h
+LINK=link.exe
+LFLAGS=kernel32.lib user32.lib gdi32.lib shell32.lib wsock32.lib \
+ oldnames.lib libcmt.lib comctl32.lib /nodefaultlib /nologo /out:WIRCD2.EXE
+OBJ_FILES=SRC/CHANNEL.OBJ SRC/USERLOAD.OBJ SRC/SEND.OBJ SRC/BSD.OBJ \
+ SRC/S_CONF.OBJ SRC/FDLIST.OBJ SRC/DBUF.OBJ SRC/RES.OBJ \
+ SRC/CLOAK.OBJ SRC/HASH.OBJ SRC/PARSE.OBJ SRC/IRCD.OBJ \
+ SRC/S_NUMERIC.OBJ SRC/WHOWAS.OBJ SRC/RES_COMP.OBJ SRC/S_AUTH.OBJ \
+ SRC/HELP.OBJ SRC/S_MISC.OBJ SRC/MATCH.OBJ SRC/CRULE.OBJ \
+ SRC/S_DEBUG.OBJ SRC/RES_INIT.OBJ SRC/SUPPORT.OBJ SRC/LIST.OBJ \
+ SRC/S_ERR.OBJ SRC/PACKET.OBJ SRC/CLASS.OBJ SRC/S_BSD.OBJ \
+ SRC/MD5.OBJ SRC/S_SERV.OBJ SRC/S_USER.OBJ SRC/WIN32GUI.OBJ \
+ SRC/VERSION.OBJ SRC/win32/WIN32.RES SRC/S_UNREAL.OBJ SRC/DYNCONF.OBJ \
+ SRC/S_SOCKS.OBJ SRC/S_KLINE.OBJ SRC/S_EXTRA.OBJ
+RC=rc.exe
+
+ALL: WIRCD.EXE CHKCONF.EXE
+        @echo Please, please REMEMBER to add those U lines!
+        @echo Read the file READTHIS.NOW formore info
+
+CLEAN:
+        -@erase src\*.exe 2>NUL
+        -@erase src\*.obj 2>NUL
+        -@erase src\win32.res 2>NUL
+        -@erase src\version.c 2>NUL
+        -@erase src\win32\*.obj 2>NUL
+        -@erase .\*.exe 2>NUL
+
+#include/setup.h:
+#        @echo Hmm...doesn't look like you've run Config...
+#        @echo Doing so now.
+#        @config.exe
+
+#src/version.c: dummy
+#        @config.exe -v
+
+src/version.obj: src/win32/version.c
+        $(CC) $(CFLAGS) src/win32/version.c
+
+./WIRCD.EXE: $(OBJ_FILES) src/win32/version.obj
+        $(LINK) $(LFLAGS) $(OBJ_FILES)
+
+./CHKCONF.EXE: ./include/struct.h ./include/config.h ./include/sys.h \
+                 ./include/common.h ./src/crule.c ./src/match.c ./src/chkconf.c
+        $(CC) /nologo /I ./include /D CR_CHKCONF /Fosrc/chkcrule.obj /c src/crule.c
+        $(CC) /nologo /I ./include /D CR_CHKCONF /Fosrc/chkmatch.obj /c src/match.c
+        $(CC) /nologo /I ./include /D CR_CHKCONF /Fosrc/chkconf.obj /c src/chkconf.c
+        $(LINK) /nologo /out:./chkconf.exe src/chkconf.obj src/chkmatch.obj \
+                src/chkcrule.obj
+
+src/parse.obj: src/parse.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/parse.c
+
+src/bsd.obj: src/bsd.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/bsd.c
+
+src/dbuf.obj: src/dbuf.c $(INCLUDES) ./include/dbuf.h
+        $(CC) $(CFLAGS) src/dbuf.c
+
+src/packet.obj: src/packet.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/packet.c
+
+src/fdlist.obj: src/fdlist.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/fdlist.c
+
+src/dynconf.obj: src/dynconf.c $(INCLUDES) ./include/dbuf.h \
+                ./include/channel.h ./include/whowas.h
+        $(CC) $(CFLAGS) src/dynconf.c
+
+src/send.obj: src/send.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/send.c
+
+src/match.obj: src/match.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/match.c
+
+src/support.obj: src/support.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/support.c
+
+src/channel.obj: src/channel.c $(INCLUDES) ./include/channel.h
+        $(CC) $(CFLAGS) src/channel.c
+
+src/class.obj: src/class.c $(INCLUDES) ./include/class.h
+        $(CC) $(CFLAGS) src/class.c
+
+src/ircd.obj: src/ircd.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/ircd.c
+
+src/list.obj: src/list.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/list.c
+
+src/res.obj: src/res.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/res.c
+
+src/s_bsd.obj: src/s_bsd.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_bsd.c
+
+src/s_auth.obj: src/s_auth.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_auth.c
+
+src/s_conf.obj: src/s_conf.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_conf.c
+
+src/s_debug.obj: src/s_debug.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_debug.c
+
+src/s_err.obj: src/s_err.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_err.c
+
+src/s_kline.obj: src/s_kline.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_kline.c
+
+src/s_misc.obj: src/s_misc.c $(INCLUDES) ./include/dbuf.h
+        $(CC) $(CFLAGS) src/s_misc.c
+
+src/s_socks.obj: src/s_socks.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/s_socks.c
+
+src/s_user.obj: src/s_user.c $(INCLUDES) ./include/dbuf.h \
+                ./include/channel.h ./include/whowas.h
+        $(CC) $(CFLAGS) src/s_user.c
+
+src/s_extra.obj: src/s_extra.c $(INCLUDES) ./include/dbuf.h \
+                ./include/channel.h ./include/whowas.h
+        $(CC) $(CFLAGS) src/s_extra.c
+
+src/s_unreal.obj: src/s_unreal.c $(INCLUDES) ./include/dbuf.h \
+                ./include/channel.h ./include/whowas.h
+        $(CC) $(CFLAGS) src/s_unreal.c
+
+src/s_serv.obj: src/s_serv.c $(INCLUDES) ./include/dbuf.h ./include/whowas.h
+        $(CC) $(CFLAGS) src/s_serv.c
+
+src/s_numeric.obj: src/s_numeric.c $(INCLUDES) ./include/dbuf.h
+        $(CC) $(CFLAGS) src/s_numeric.c
+
+src/whowas.obj: src/whowas.c $(INCLUDES) ./include/dbuf.h ./include/whowas.h
+        $(CC) $(CFLAGS) src/whowas.c
+
+src/hash.obj: src/hash.c $(INCLUDES) ./include/hash.h
+        $(CC) $(CFLAGS) src/hash.c
+
+src/crule.obj: src/crule.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/crule.c
+
+src/win32gui.obj: src/win32/win32gui.c $(INCLUDES) ./src/win32/resource.h
+#./include/resource.h
+        $(CC) $(CFLAGS) src/win32/win32gui.c
+
+src/res_comp.obj: src/res_comp.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/res_comp.c
+
+src/res_init.obj: src/res_init.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/res_init.c
+
+src/help.obj: src/help.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/help.c
+
+src/md5.obj: src/md5.c $(INCLUDES)
+        $(CC) $(CFLAGS) src/md5.c
+
+src/win32/win32.res: src/win32/win32gui.rc
+        $(RC) /l 0x409 /fosrc/win32/win32.res /i ./include /i ./src \
+              /d NDEBUG src/win32/win32gui.rc
+
+dummy:
+
+
diff --git a/networks/972-scripterz.network b/networks/972-scripterz.network
new file mode 100644 (file)
index 0000000..cfff2f0
--- /dev/null
@@ -0,0 +1,71 @@
+ver2^2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <day> <month> <year> <hh:dd> GMT
+#  Author:       <nick> (<real name>)
+#  E-Mail:       <email>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: 972-Scripterz
+Set ircnetwork ....: 972-Scripterz
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.972-Scripterz.org
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: services.972-Scripterz.org
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: ircop.972-Scripterz.org
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: admin.972-Scripterz.org
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: locop.972-Scripterz.org
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: serviceop.972-Scripterz.org
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: netadmin.972-Scripterz.org
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: coadmin.972-Scripterz.org
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.972-Scripterz.org
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: sz
+# This is the domain of the IRC network
+Set netdomain .....: 972-Scripterz.org
+# This is where people can go for help
+Set helpchan ......: #972-Scripterz
+# This is the name of the stats server
+Set STATS_SERVER ..: stats.972-Scripters.org
+# -- Not in use--
+Set HUB ...........: 0
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: sz
diff --git a/networks/altirc.network b/networks/altirc.network
new file mode 100644 (file)
index 0000000..912ac68
--- /dev/null
@@ -0,0 +1,71 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <11> <09> <1999> <14:32> GMT
+#  Author:       <Kerjin> Steve>)
+#  E-Mail:       <kerjin@alternativenet.org>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: AltNet IRC
+Set ircnetwork ....: AltNet IRC
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.alternativenet.org
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: services.alternativenet.org
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: ircop.alternativenet.org
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: admin.alternativenet.org
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: locop.alternativenet.org
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: serviceop.alternativenet.org
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: netadmin.alternativenet.org
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: coadmin.alternativenet.org
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.alternativenet.org
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: altirc
+# This is the domain of the IRC network
+Set netdomain .....: alternativenet.org
+# This is where people can go for help
+Set helpchan ......: #AltNetHelp
+# This is the name of the stats server
+Set STATS_SERVER ..: statistics.alternativenet.org
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 1
+# -- Not in use but still here --
+Set net_quit ......: alt
diff --git a/networks/bunker7.network b/networks/bunker7.network
new file mode 100644 (file)
index 0000000..b450b76
--- /dev/null
@@ -0,0 +1,29 @@
+ver^2.2
+#
+# Bunker7.net Network Configuration File
+# -----------------------------------------
+#  Added-at:     17 August 1999 12:34 CT
+#  Author:       Rogue
+#  E-Mail:       rogue@bunker7.net
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: bunker7
+Set ircnetwork ....: bunker7
+Set defserv .......: irc.bunker7.net
+Set SERVICES_NAME .: services.bunker7.net
+Set oper_host .....: global.bunker7.net
+Set admin_host ....: admin.bunker7.net
+Set locop_host ....: local.bunker7.net
+Set sadmin_host ...: sadm.bunker7.net
+Set netadmin_host .: netadmin.bunker7.net
+Set coadmin_host ..: coadmin.bunker7.net
+Set techadmin_host : techadmin.bunker7.net
+Set hidden_host ...: bunker7
+Set netdomain .....: bunker7.net
+Set helpchan ......: #bunker7
+Set STATS_SERVER ..: stats.bunker7.net
+Set HUB ...........: 1
+Set iNAH ..........: 0
+Set net_quit ......: B7
diff --git a/networks/digitalirc.network b/networks/digitalirc.network
new file mode 100644 (file)
index 0000000..6529cea
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <day> <month> <year> <hh:dd> GMT
+#  Author:       Curt|s
+#  E-Mail:       <email>
+#  $Id$
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: DigitalIRC.Net
+Set ircnetwork ....: DigitalIRC.Net
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.digitalirc.net
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: Services.DigitalIRC.Net
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: Oper.DigitalIRC.Net
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: Admin.DigitalIRC.Net
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: LocOper.DigitalIRC.Net
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: ServicesOp.DigitalIRC.Net
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: NetAdmin.DigitalIRC.Net
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: NetAdmin.DigitalIRC.Net
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : Tech.DigitalIRC.Net
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: NN
+# This is the domain of the IRC network
+Set netdomain .....: DigtialIRC.Net
+#This is where people can go for help
+Set helpchan ......: #Digitalirc
+# This is the name of the stats server
+Set STATS_SERVER ..: Statistics.DigitalIRC.com
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: ic
diff --git a/networks/dragonwings.network b/networks/dragonwings.network
new file mode 100644 (file)
index 0000000..78c142d
--- /dev/null
@@ -0,0 +1,29 @@
+ver^2.2
+#
+# DragonWings.org Network Configuration File
+# -----------------------------------------
+#  Added-at:     14 July 1999 00:00 GMT
+#  Author:       Stskeeps (Carsten Munk)
+#  E-Mail:       stskeeps@global-irc.net
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: DragonWings
+Set ircnetwork ....: DragonWings
+Set defserv .......: irc.dragonwings.org
+Set SERVICES_NAME .: saturn.dragonwings.org
+Set oper_host .....: ircop.dragonwings.org
+Set admin_host ....: admin.dragonwings.org
+Set locop_host ....: locop.dragonwings.org
+Set sadmin_host ...: serviceop.dragonwings.org
+Set netadmin_host .: netadmin.dragonwings.org
+Set coadmin_host ..: coadmin.dragonwings.org
+Set techadmin_host : techadmin.dragonwings.org
+Set hidden_host ...: dw
+Set netdomain .....: dragonwings.org
+Set helpchan ......: #DragonWings
+Set STATS_SERVER ..: stats.dragonwings.org
+Set HUB ...........: 1
+Set iNAH ..........: 0
+Set net_quit ......: DW
diff --git a/networks/fireirc.network b/networks/fireirc.network
new file mode 100644 (file)
index 0000000..4edd5e2
--- /dev/null
@@ -0,0 +1,30 @@
+\r
+#\r
+# FireIRC Network Configuration File\r
+# -----------------------------------------\r
+#  Added-at:     14 July 1999 00:00 GMT\r
+#  Author:       MasterSatan (Erik Kerr)\r
+#  E-Mail:       Kerrfarm@bright.net\r
+#\r
+# -----------------------------------------\r
+#     \r
+\r
+\r
+Network >..........: FireIRC\r
+Set ircnetwork ....: FireIRC\r
+Set defserv .......: irc.FireIRC.Net\r
+Set SERVICES_NAME .: services.FireIRC.Net\r
+Set oper_host .....: ircOP.FireIRC.Net\r
+Set admin_host ....: Admin.FireIRC.Net\r
+Set locop_host ....: localOP.FireIRC.Net\r
+Set sadmin_host ...: serviceOP.FireIRC.Net\r
+Set netadmin_host .: NetADMIN.FireIRC.Net\r
+Set coadmin_host ..: CoADMIN.FireIRC.Net\r
+Set techadmin_host : TechAdmin.FireIRC.Net\r
+Set hidden_host ...: FireIRC\r
+Set netdomain .....: FireIRC.Net\r
+Set helpchan ......: #Services\r
+Set STATS_SERVER ..: stats.FireIRC.Net\r
+Set HUB ...........: 1\r
+Set iNAH ..........: 0\r
+Set net_quit ......: FI    
\ No newline at end of file
diff --git a/networks/global-irc.network b/networks/global-irc.network
new file mode 100644 (file)
index 0000000..94a91a9
--- /dev/null
@@ -0,0 +1,29 @@
+ver^2.2
+#
+# Global-IRC.net Network Configuration File
+# -----------------------------------------
+#  Added-at:     14 July 1999 00:00 GMT
+#  Author:       Stskeeps (Carsten Munk)
+#  E-Mail:       stskeeps@global-irc.net
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: Global-IRC
+Set ircnetwork ....: Global-IRC
+Set defserv .......: irc.global-irc.net
+Set SERVICES_NAME .: services.global-irc.net
+Set oper_host .....: ircop.global-irc.net
+Set admin_host ....: admin.global-irc.net
+Set locop_host ....: locop.global-irc.net
+Set sadmin_host ...: serviceop.global-irc.net
+Set netadmin_host .: netadmin.global-irc.net
+Set coadmin_host ..: coadmin.global-irc.net
+Set techadmin_host : techadmin.global-irc.net
+Set hidden_host ...: global
+Set netdomain .....: global-irc.net
+Set helpchan ......: #Global
+Set STATS_SERVER ..: stats.global-irc.net
+Set HUB ...........: 1
+Set iNAH ..........: 0
+Set net_quit ......: GI
diff --git a/networks/infinity.network b/networks/infinity.network
new file mode 100644 (file)
index 0000000..4957fdb
--- /dev/null
@@ -0,0 +1,29 @@
+ver^2.2
+#
+# Global-IRC.net Network Configuration File
+# -----------------------------------------
+#  Added-at:     14 July 1999 00:00 GMT
+#  Author:       Stskeeps (Carsten Munk)
+#  E-Mail:       stskeeps@global-irc.net
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: Infinity-IRC.org
+Set ircnetwork ....: Infinity-IRC.org
+Set defserv .......: irc.infinity-irc.org
+Set SERVICES_NAME .: services.infinity-irc.org
+Set oper_host .....: IRCop.Infinity-IRC.org
+Set admin_host ....: IRCop-Admin.Infinity-IRC.org
+Set locop_host ....: LOCop.Infinity-IRC.org
+Set sadmin_host ...: IRCop-ServiceAdmin.Infinity-IRC.org
+Set netadmin_host .: IRCop-NetAdmin.Infinity-IRC.org
+Set coadmin_host ..: IRCop-CoAdmin.Infinity-IRC.org
+Set techadmin_host : IRCop-TechAdmin.Infinity-IRC.org
+Set hidden_host ...: Infinity
+Set netdomain .....: Infinity-IRC.org
+Set helpchan ......: #Infinity
+Set STATS_SERVER ..: stats.infinity-irc.org
+Set HUB ...........: 1
+Set iNAH ..........: 1
+Set net_quit ......: IN
diff --git a/networks/megairc.network b/networks/megairc.network
new file mode 100644 (file)
index 0000000..5c334b2
--- /dev/null
@@ -0,0 +1,31 @@
+ver^2.2
+#
+# MegaIRC.net Network Configuration File
+# -----------------------------------------
+#  Added-at:     1 August 1999 00:00 GMT
+#  Author:       NonMortal (Luke Slotwinski)
+#  E-Mail:       NonMortal@MegaIRC.Com
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: MegaIRC
+Set ircnetwork ....: MegaIRC
+Set defserv .......: irc.MegaIRC.Net
+Set SERVICES_NAME .: Services.MegaIRC.Net
+Set oper_host .....: Ircop.MegaIRC.Net
+Set admin_host ....: Server-Admin.MegaIRC.Net
+Set locop_host ....: Local-Ircop.MegaIRC.Net
+Set sadmin_host ...: SOP.MegaIRC.Net
+Set netadmin_host .: NetAdmin.MegaIRC.Net
+Set coadmin_host ..: Server-CoAdmin.MegaIRC.Net
+Set techadmin_host : TechAdmin.MegaIRC.Net
+Set hidden_host ...: mega
+Set netdomain .....: MegaIRC.Net
+Set helpchan ......: #helpdesk
+Set STATS_SERVER ..: Stats.MegaIRC.Net
+Set HUB ...........: 1
+Set iNAH ..........: 1
+Set net_quit ......: MI
+# To protect people from using normal edition Unreal to link to MegaIRC
+Set STOPSE ........: 1
diff --git a/networks/mp3fans.network b/networks/mp3fans.network
new file mode 100644 (file)
index 0000000..a0cfcfe
--- /dev/null
@@ -0,0 +1,29 @@
+ver^2.2
+#
+# Mp3Fans.net Network Configuration File
+# -----------------------------------------
+#  Added-at:     14 July 1999 00:00 GMT
+#  Author:       Stskeeps (Carsten Munk)
+#  E-Mail:       stskeeps@global-irc.net
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: Mp3FansNet
+Set ircnetwork ....: Mp3FansNet
+Set defserv .......: irc.mp3fans.net
+Set SERVICES_NAME .: services.mp3fans.net
+Set oper_host .....: ircop.mp3fans.net
+Set admin_host ....: admin.mp3fans.net
+Set locop_host ....: locop.mp3fans.net
+Set sadmin_host ...: serviceop.mp3fans.net
+Set netadmin_host .: netadmin.mp3fans.net
+Set coadmin_host ..: coadmin.mp3fans.net
+Set techadmin_host : techadmin.mp3fans.net
+Set hidden_host ...: mpx
+Set netdomain .....: mp3fans.net
+Set helpchan ......: #Mp3Fans
+Set STATS_SERVER ..: stats.mp3fans.net
+Set HUB ...........: 1
+Set iNAH ..........: 0
+Set net_quit ......: m3
diff --git a/networks/neohorizon.network b/networks/neohorizon.network
new file mode 100644 (file)
index 0000000..b00efe1
--- /dev/null
@@ -0,0 +1,70 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     23 August 1999 <18:00> GMT
+#  Author:       codemastr <codemastr@elite-hacker.cx>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: NeoHorizon
+Set ircnetwork ....: NeoHorizon
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.nhn.net
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: services.nhn.net
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: IRCop.nhn.net
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: Admin.nhn.net
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: Locop.nhn.net
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: ServicesOP.nhn.net
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: NetAdmin.nhn.net
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: Co-Admin.nhn.net
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.nhn.net
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: Neo
+# This is the domain of the IRC network
+Set netdomain .....: nhn.net
+# This is where people can go for help
+Set helpchan ......: #neohorizon
+# This is the name of the stats server
+Set STATS_SERVER ..: stats.nhn.net
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 1
+# -- Not in use but still here --
+Set net_quit ......: NH
diff --git a/networks/networks.ndx b/networks/networks.ndx
new file mode 100644 (file)
index 0000000..aad4094
--- /dev/null
@@ -0,0 +1,24 @@
+# Networks index file - do not touch please 
+networks/global-irc.network ......: Global-IRC (http://www.global-irc.net)
+networks/mp3fans.network .........: Mp3Fans.Net (http://www.mp3fans.net)
+networks/roxnet.network ..........: ROXnet (http://www.rox.za.net)
+networks/dragonwings.network .....: DragonWings (http://www.dragonwings.org)
+networks/megairc.network .........: MegaIRC (http://www.megairc.net)
+networks/neohorizon.network ......: NeoHorizon (http://www.nhn.net)
+networks/spynet.network ..........: SpyNet (http://www.spynet.org)
+networks/nevernet.network ........: NeverNET (http://www.nevernet.net)
+networks/altirc.network ..........: AlternativeNet IRC (http://www.
+networks/bunker7.network .........: Bunker7 (http://www.bunker7.net)
+networks/realchat.network ........: RealChat.org (http://www.realchat.org)
+networks/newmilennium.network ....: NewMilennium (http://www.newmilennium.net)
+networks/solarxtreme.network .....: SolarXTreme (http://www.solarxtreme.net)
+networks/ss.network ..............: StarSpace (http://www.starspace.net)
+networks/uzaynet.network .........: UzayNet (http://www.uzaynet.nu)
+networks/infinity.network ........: Infinity-IRC.org (http://www.infinity-irc.org)
+networks/tspre.network ...........: TSpre (http://www.tspre.org)
+networks/solargalaxy.network .....: SolarGalaxy (http://www.solargalaxy.net)
+networks/digitalirc.network ......: DigitalIRC (http://www.digitalirc.net)
+networks/fireirc.network .........: FireIRC (http://www.fireirc.net)
+networks/stormdancing.network ....: StormDancing (http://www.stormdancing.net)
+networks/972-scripterz.network ...: 972-scripterz
+networks/v64net.network ..........: v64
\ No newline at end of file
diff --git a/networks/nevernet.network b/networks/nevernet.network
new file mode 100644 (file)
index 0000000..5e834eb
--- /dev/null
@@ -0,0 +1,72 @@
+ver^2.2
+
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <day> <month> <year> <hh:dd> GMT
+#  Author:       <nick> (<real name>)
+#  E-Mail:       <email>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: NeverNET
+Set ircnetwork ....: NeverNET
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: IRC.NeverNET.Net
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: Services.NeverNET.Net
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: Opers.NeverNET.Net
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: Admins.NeverNET.Net
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: Opers.NeverNET.Net
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: Services.NeverNET.Net
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: Nevermore.NeverNET.Net
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: NetAdmins.NeverNET.Net
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : Tech.NeverNET.Net
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: NN
+# This is the domain of the IRC network
+Set netdomain .....: NeverNET.Net
+#This is where people can go for help
+Set helpchan ......: #NeverNET
+# This is the name of the stats server
+Set STATS_SERVER ..: Stats.NeverNET.Net
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: ic
diff --git a/networks/newmilennium.network b/networks/newmilennium.network
new file mode 100644 (file)
index 0000000..e89a917
--- /dev/null
@@ -0,0 +1,26 @@
+ver^2.2
+#
+# newmilennium.net Network Configuration File
+# Made by: Dave Ellsworth (MasterJedi)
+# E-Mail: mj@planetz.net
+# ---------------------------------------
+
+
+Network >..........: NewMilennium
+Set ircnetwork ....: NewMilennium
+Set defserv .......: irc.NewMilennium.net
+Set SERVICES_NAME .: Services.NewMilennium.net
+Set oper_host .....: ircop.newmilennium.net
+Set admin_host ....: admin.newmilennium.net
+Set locop_host ....: locop.newmilennium.net
+Set sadmin_host ...: serviceop.newmilennium.net
+Set netadmin_host .: netadmin.newmilennium.net
+Set coadmin_host ..: coadmin.newmilennium.net
+Set techadmin_host : techadmin.newmilennium.net
+Set hidden_host ...: newmilennium
+Set netdomain .....: newmilennium.net
+Set helpchan ......: #newmilennium
+Set STATS_SERVER ..: stats.newmilennium.net
+Set HUB ...........: 1
+Set iNAH ..........: 1
+Set net_quit ......: SN
diff --git a/networks/realchat.network b/networks/realchat.network
new file mode 100644 (file)
index 0000000..9dc627b
--- /dev/null
@@ -0,0 +1,70 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     14 August 1999 16:34 GMT
+#  Author:       Sandman
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: RealChat.Org
+Set ircnetwork ....: RealChat.Org
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.RealChat.Org
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: Services.RealChat.Org
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: Oper.RealChat.Org
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: Admins.RealChat.Org
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: LocalOper.RealChat.Org
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: servicesOper.RealChat.Org
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: NetAdmin.RealChat.Org
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: CoAdmin.RealChat.Org
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : TechAdmin.RealChat.Org
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: realchat
+# This is the domain of the IRC network
+Set netdomain .....: RealChat.Org
+# This is where people can go for help
+Set helpchan ......: #services
+# This is the name of the stats server
+Set STATS_SERVER ..: stats.realchat.org
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: RC
diff --git a/networks/roxnet.network b/networks/roxnet.network
new file mode 100644 (file)
index 0000000..e561c7b
--- /dev/null
@@ -0,0 +1,30 @@
+ver^2.2
+#
+# ROXnet (irc.rox.za.net) Network Configuration File
+# --------------------------------------------------
+#  Added-at:     14 July 1999 00:00 GMT
+#  Author:       Stskeeps (Carsten Munk)
+#  E-Mail:       stskeeps@roxnet.org
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: ROXnet
+Set ircnetwork ....: ROXnet
+Set defserv .......: irc.roxnet.org
+Set SERVICES_NAME .: services.roxnet.org
+Set oper_host .....: ircop.roxnet.org
+Set admin_host ....: admin.roxnet.org
+Set locop_host ....: locop.roxnet.org
+Set sadmin_host ...: csops.roxnet.org
+Set netadmin_host .: netadmin.roxnet.org
+Set coadmin_host ..: coadmin.roxnet.org
+Set techadmin_host : techadmin.roxnet.org
+Set hidden_host ...: rox
+Set netdomain .....: roxnet.org
+Set helpchan ......: #ROXnet
+Set STATS_SERVER ..: stats.roxnet.org
+Set HUB ...........: 1
+Set iNAH ..........: 0
+Set net_quit ......: Rox
+
diff --git a/networks/solargalaxy.network b/networks/solargalaxy.network
new file mode 100644 (file)
index 0000000..8020909
--- /dev/null
@@ -0,0 +1,36 @@
+ver^2.2
+Network >..........: SolarGalaxy
+
+Set ircnetwork ....: SolarGalaxy
+
+Set defserv .......: Irc.SolarGalaxy.Net
+
+Set SERVICES_NAME .: Services.SolarGalaxy.Net
+
+Set oper_host .....: IRCop.SolarGalaxy.Net
+
+Set admin_host ....: Admin.SolarGalaxy.Net
+
+Set locop_host ....: Locop.SolarGalaxy.Net
+
+Set sadmin_host ...: ServiceOp.SolarGalaxy.Net
+
+Set netadmin_host .: NetAdmin.SolarGalaxy.Net
+
+Set coadmin_host ..: CoAdmin.SolarGalaxy.Net
+
+Set techadmin_host : TechAdmin.SolarGalaxy.Net
+
+Set hidden_host ...: solargalaxy
+
+Set netdomain .....: SolarGalaxy.Net
+
+Set helpchan ......: #SolarGalaxy
+
+Set STATS_SERVER ..: Stats.SolarGalaxy.Net
+
+Set HUB ...........: 1
+
+Set iNAH ..........: 1
+
+Set net_quit ......: sg
diff --git a/networks/solarxtreme.network b/networks/solarxtreme.network
new file mode 100644 (file)
index 0000000..8f83f6b
--- /dev/null
@@ -0,0 +1,69 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration
+# files Just follow the instructions and it will prolly work ;) 0 = No   1
+# = Yes -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both
+# fields
+Network >..........: SolarXTreme 
+Set ircnetwork ....: SolarXTreme 
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.solarxtreme.net
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: Services.SolarXTreme.Net
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: IRCop.SolarXTreme.Net
+
+# This is the virtual hostname Server Admins will get if iNAH option is
+# enabled on oper up
+Set admin_host ....: Admin.SolarXTreme.Net
+
+# This is the virtual hostname Local IRCops will get if iNAH option is
+# enabled on oper up
+
+Set locop_host ....: LocOp.SolarXTreme.Net     
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: ServicesOp.SolarXTreme.Net
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: NetAdmin.SolarXTreme.Net
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: CoAdmin.SolarXTreme.Net
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : TechAdmin.SolarXTreme.Net
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: solar
+# This is the domain of the IRC network
+Set netdomain .....: solarxtreme.net
+# This is where people can go for help
+Set helpchan ......: #SolarHelp
+# This is the name of the stats server
+Set STATS_SERVER ..: Stats.SolarXTreme.Net
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 1
+# -- Not in use but still here --
+Set net_quit ......: ic
+
diff --git a/networks/spynet.network b/networks/spynet.network
new file mode 100644 (file)
index 0000000..2a33f0f
--- /dev/null
@@ -0,0 +1,28 @@
+ver^2.2
+# SpyNet Network Configuration File
+# -----------------------------------------
+#  Added-at:     23 August 1999 18:00 GMT
+#  Author:       Son|c
+#  E-Mail:       stskeeps@global-irc.net
+#  $Id$
+# -----------------------------------------
+#
+
+Network >..........: SpyNet
+Set ircnetwork ....: SpyNet
+Set defserv .......: irc.SpyNet.Org
+Set SERVICES_NAME .: Services.SpyNet.Org
+Set oper_host .....: IRCops.SpyNet.Org
+Set admin_host ....: Admin.SpyNet.Org
+Set locop_host ....: LocalOper.SpyNet.Org
+Set sadmin_host ...: Sops.SpyNet.Org
+Set netadmin_host .: NetAdmin.SpyNet.Org
+Set coadmin_host ..: CoAdmin.SpyNet.Org
+Set techadmin_host : TechAdmin.SpyNet.Org
+Set hidden_host ...: Spy
+Set netdomain .....: SpyNet.Org
+Set helpchan ......: #SpyNet
+Set STATS_SERVER ..: stats.SpyNet.Org
+Set HUB ...........: 0
+Set iNAH ..........: 0
+Set net_quit ......: SN
diff --git a/networks/ss.network b/networks/ss.network
new file mode 100644 (file)
index 0000000..cb88352
--- /dev/null
@@ -0,0 +1,58 @@
+ver^2.2
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: StarSpace
+Set ircnetwork ....: StarSpace
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: IRC.StarSpace.Net
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: Services.StarSpace.Net
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: Global.StarSpace.Net
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: Admin.StarSpace.Net
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: Local.StarSpace.Net
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: ServOp.StarSpace.Net
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: NetAdmin.StarSpace.Net
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: CoAdmin.StarSpace.Net
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : TechAdmin.StarSpace.Net
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: starspace
+# This is the domain of the IRC network
+Set netdomain .....: StarSpace.Net
+# This is where people can go for help
+Set helpchan ......: #OperHelp
+# This is the name of the stats server
+Set STATS_SERVER ..: Stats.StarSpace.Net
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 1
+# -- Not in use but still here --
+Set net_quit ......: SS
diff --git a/networks/template.network b/networks/template.network
new file mode 100644 (file)
index 0000000..0a7901c
--- /dev/null
@@ -0,0 +1,71 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <day> <month> <year> <hh:dd> GMT
+#  Author:       <nick> (<real name>)
+#  E-Mail:       <email>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: IRC
+Set ircnetwork ....: IRC
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.ircnet.org
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: services.ircnet.org
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: ircop.ircnet.org
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: admin.ircnet.org
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: locop.ircnet.org
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: serviceop.ircnet.org
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: netadmin.ircnet.org
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: coadmin.ircnet.org
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.ircnet.org
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: mpx
+# This is the domain of the IRC network
+Set netdomain .....: ircnet.org
+# This is where people can go for help
+Set helpchan ......: #IRC
+# This is the name of the stats server
+Set STATS_SERVER ..: stats.ircnet.org
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: ic
diff --git a/networks/tspre.network b/networks/tspre.network
new file mode 100644 (file)
index 0000000..4aab6c3
--- /dev/null
@@ -0,0 +1,71 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <day> <month> <year> <hh:dd> GMT
+#  Author:       <nick> (<real name>)
+#  E-Mail:       <email>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: TSpre
+Set ircnetwork ....: TSpre
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.tspre.org
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: services.tspre.org
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: ircop.tspre.org
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: admin.tspre.org
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: locop.tspre.org
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: serviceop.tspre.org
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: netadmin.tspre.org
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: coadmin.tspre.org
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.tspre.org
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: ts
+# This is the domain of the IRC network
+Set netdomain .....: tspre.org
+# This is where people can go for help
+Set helpchan ......: #TSpre
+# This is the name of the stats server
+Set STATS_SERVER ..: stats.tspre.org
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: ic
diff --git a/networks/unrealircd.conf b/networks/unrealircd.conf
new file mode 100644 (file)
index 0000000..7434e45
--- /dev/null
@@ -0,0 +1,81 @@
+ver^1.1
+#
+#   UnrealIRCd Configuration file - unrealircd.conf
+#   (C) Carsten Munk 1999 - Under the GNU license
+#   $Id$   
+# Follow the instructions here.
+# 
+# change the filename to what network header file you use
+# relative to DPATH
+Include .................: networks/roxnet.network
+
+#
+# What K:Line address can K:lined users mail at?
+#
+Set KLINE_ADDRESS .......: the admin of this server
+
+# If you want users to get auto +x on connect
+# 1 = Yes 0 = No
+Set MODE_X ..............: 1
+
+# Auto +i users when they connect?
+# 1 = Yes 0 = No
+Set MODE_I ..............: 0
+
+# If compiled on a halfhub network this will upgrade it to be a real hub
+# *  else if tried on a leaf (not hub) it will cause an error
+# * NOTE: There are only TWO versions of UnrealIRCd - Leaf and [Half]Hub
+# *       (in wIRCd terms)
+# *       Leafs are normal leafs
+# *       Halfhubs are hubs that doesn't send out a GLOBOPS when connect estab
+# *         (unless if #define TRUEHUB)
+# 1 = Yes  0 = No
+
+Set TRUEHUB .............: 1
+
+#
+# The IRCd won't boot if not this setting set correctly 
+# RTFM and go thru the config file (this file)
+# 1 = Yes  0 = No
+Set CONFIG_FILE_STOP ....: 0
+
+# 
+# If to let non-opers do /stats O
+#
+#
+Set SHOWOPERS ...........: 0
+
+#
+# This will get the IRCd to exit links with different protocol ( < / > )
+#
+Set KILLDIFF ............: 1
+
+#
+# Show Oper MOTD at oper up?
+# 1 = Yes 0 = No
+Set SHOWOPERMOTD ........: 1
+
+#
+# Hide U:lines from non-opers in /links?
+# 1 = Yes 0 = No
+Set HIDE_ULINES .........: 0
+
+#
+# Allow use of ChatOps?
+# 1 = Yes 0 = No
+Set ALLOW_CHATOPS .......: 1
+
+#
+# What message do you want send to Z:lined SOCKS users?
+#
+Set SOCKS_BAN_MESSAGE ...: Insecure SOCKS server
+
+#
+# What quit message do we want to send not yet Z:lined SOCKS users?
+#
+Set SOCKS_QUIT_MESSAGE ..: Insecure SOCKS server
+
+#
+# How many seconds will a insecure SOCKS be banned?
+#
+Set SOCKSBANTIME ........: 86400
diff --git a/networks/uzaynet.network b/networks/uzaynet.network
new file mode 100644 (file)
index 0000000..deb33cb
--- /dev/null
@@ -0,0 +1,72 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     <day> <month> <year> <hh:dd> GMT
+#  Author:       <nick> (<real name>)
+#  E-Mail:       <email>
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: UzayNet
+Set ircnetwork ....: UzayNet
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: uzaynet.com
+
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: service.uzaynet.com
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: ircop.silverserver.nu
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: admin.uzaynet.nu
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: locop.uzaynet.nu
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: serviceop.uzaynet.nu
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: netadmin.uzaynet.nu
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: coadmin.uzaynet.nu
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.uzaynet.nu
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: UzayNet
+# This is the domain of the IRC network
+Set netdomain .....: uzaynet.nu
+# This is where people can go for help
+Set helpchan ......: #Help
+# This is the name of the stats server
+Set STATS_SERVER ..: statserv.uzaynet.com
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 1
+# -- Not in use but still here --
+Set net_quit ......: ic
diff --git a/networks/v64net.network b/networks/v64net.network
new file mode 100644 (file)
index 0000000..7b0a801
--- /dev/null
@@ -0,0 +1,71 @@
+ver^2.2
+#
+# Network Configuration File Template
+# -----------------------------------------
+#  Added-at:     27 February 2000 05:46 CST
+#  Author:       Venusaur64 (Jahn Veach)
+#  E-Mail:       venusaur@flash.net
+#  $Id$
+# -----------------------------------------
+# This is a template so you can create your own network configuration files
+# Just follow the instructions and it will prolly work ;)
+# 0 = No   1 = Yes
+# -------------------------------------------------------
+#
+# These two specify the name of the IRC network, set the same in both fields
+Network >..........: V64net
+Set ircnetwork ....: V64net
+
+# This is where your DNS pool is (like irc.dal.net)
+Set defserv .......: irc.v64.net
+
+# This is the name of your Services Server
+Set SERVICES_NAME .: services.v64.net
+
+# This is the virtual hostname IRCops will get if iNAH option is enabled
+# on oper up
+Set oper_host .....: ircop.v64.net
+
+# This is the virtual hostname Server Admins will get if iNAH option is enabled
+# on oper up
+Set admin_host ....: admin.v64.net
+
+# This is the virtual hostname Local IRCops will get if iNAH option is enabled
+# on oper up
+
+Set locop_host ....: locop.v64.net
+
+# This is the virtual hostname Services Operators/Admins will get
+# if iNAH option is enabled on oper up
+
+Set sadmin_host ...: serviceop.v64.net
+
+# This is the virtual hostname NetAdmins will get
+# if iNAH option is enabled on oper up
+
+Set netadmin_host .: netadmin.v64.net
+
+# This is the virtual hostname CoAdmins will get
+# if iNAH option is enabled on oper up
+Set coadmin_host ..: coadmin.v64.net
+
+
+# This is the virtual hostname TechAdmins will get
+# if iNAH option is enabled on oper up
+Set techadmin_host : techadmin.v64.net
+
+# This is the prefix of the hidden host (cloaking) hostname
+Set hidden_host ...: V64net
+# This is the domain of the IRC network
+Set netdomain .....: v64.net
+# This is where people can go for help
+Set helpchan ......: #HELP
+# This is the name of the stats server
+Set STATS_SERVER ..: stats.v64.net
+# -- Not in use--
+Set HUB ...........: 1
+# This enables the auto-setting of f.x @netadmin.network.net 
+# on oper up
+Set iNAH ..........: 0
+# -- Not in use but still here --
+Set net_quit ......: ic
diff --git a/newnet b/newnet
new file mode 100755 (executable)
index 0000000..b0fb149
--- /dev/null
+++ b/newnet
@@ -0,0 +1,12 @@
+#!/bin/sh
+# $Id$
+       echo "|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= "
+       echo "|      UnrealIRCd Network Submission             "
+       echo "|                                                "
+       echo "| If you want your networks network file in the  "
+       echo "| next release please attach your network file   "
+       echo "| to an email and mail it to                     "
+       echo" |  unreal-networks@lists.sourceforge.net         "
+       echo "|                                                "
+       echo "|=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= "
+       exit 1
diff --git a/rehash b/rehash
new file mode 100755 (executable)
index 0000000..5da1c93
--- /dev/null
+++ b/rehash
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Rehash Script v2.0
+# $Id$
+
+IRCDPID="ircd.pid"
+
+if [ ! -r $IRCDPID ]; then
+clear
+echo "|--------------------------------------------|"
+echo "|              **** ERROR ****               |"
+echo "|             Possible problems:             |"
+echo "| (1) $IRCDPID not found                     |"
+echo "| (2) The IRCd is not running                |"
+echo "|--------------------------------------------|"
+else
+PID=`cat $IRCDPID`
+kill -HUP $PID
+echo "|----------------------------------------"
+echo "| UnrealIRCD successfully rehashed."
+echo "| Process ID: $PID"
+echo "|----------------------------------------"
+fi
+
diff --git a/src/Config.c b/src/Config.c
new file mode 100644 (file)
index 0000000..16bd1d9
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * $Id$
+ */
+#include <stdio.h>
+#ifdef _WIN32
+#include <io.h>
+#endif
+#include <fcntl.h>
+#ifdef _WIN32 
+#include <sys\stat.h>
+#endif
+#include <time.h>
+
+int _FD_SETSIZE = 1024;
+char _NS_ADDRESS[256], _KLINE_ADDRESS[256];
+
+
+char Makefile[] =
+"CC=cl\n"
+"FD_SETSIZE=/D FD_SETSIZE=$FD_SETSIZE\n"
+"CFLAGS=/MT /O2 /I ./INCLUDE /Fosrc/ /nologo $(FD_SETSIZE) $(NS_ADDRESS) /D NOSPOOF=1 /c\n"
+"INCLUDES=./include/struct.h ./include/config.h ./include/sys.h \\\n"
+" ./include/common.h ./include/settings.h ./include/h.h ./include/numeric.h \\\n"
+" ./include/msg.h ./include/setup.h\n"
+"LINK=link.exe\n"
+"LFLAGS=kernel32.lib user32.lib gdi32.lib shell32.lib wsock32.lib \\\n"
+" oldnames.lib libcmt.lib /nodefaultlib /nologo /out:SRC/WIRCD.EXE\n"
+"OBJ_FILES=SRC/CHANNEL.OBJ SRC/USERLOAD.OBJ SRC/SEND.OBJ SRC/BSD.OBJ \\\n"
+" SRC/CIO_MAIN.OBJ SRC/S_CONF.OBJ SRC/DBUF.OBJ SRC/RES.OBJ \\\n"
+" SRC/HASH.OBJ SRC/CIO_INIT.OBJ SRC/PARSE.OBJ SRC/IRCD.OBJ \\\n"
+" SRC/S_NUMERIC.OBJ SRC/WHOWAS.OBJ SRC/RES_COMP.OBJ SRC/S_AUTH.OBJ \\\n"
+" SRC/HELP.OBJ SRC/S_MISC.OBJ SRC/MATCH.OBJ SRC/CRULE.OBJ \\\n"
+" SRC/S_DEBUG.OBJ SRC/RES_INIT.OBJ SRC/SUPPORT.OBJ SRC/LIST.OBJ \\\n"
+" SRC/S_ERR.OBJ SRC/PACKET.OBJ SRC/CLASS.OBJ SRC/S_BSD.OBJ \\\n"
+" SRC/MD5.OBJ SRC/S_SERV.OBJ SRC/S_USER.OBJ SRC/WIN32.OBJ \\\n"
+" SRC/DYNCONF.OBJ\\\n"
+" SRC/VERSION.OBJ SRC/WIN32.RES SRC/CLOAK.OBJ SRC/S_UNREAL.OBJ\n"
+"RC=rc.exe\n"
+"\n"
+"ALL: SRC/WIRCD.EXE SRC/CHKCONF.EXE\n"
+"        @echo Complete.\n"
+"\n"
+"CLEAN:\n"
+"        -@erase src\\*.exe 2>NUL\n"
+"        -@erase src\\*.obj 2>NUL\n"
+"        -@erase src\\win32.res 2>NUL\n"
+"        -@erase src\\version.c 2>NUL\n"
+"\n"
+"include/setup.h:\n"
+"        @echo Hmm...doesn't look like you've run Config...\n"
+"        @echo Doing so now.\n"
+"        @config.exe\n"
+"\n"
+"src/version.c: dummy\n"
+"        @config.exe -v\n"
+"\n"
+"src/version.obj: src/version.c\n"
+"        $(CC) $(CFLAGS) src/version.c\n"
+"\n"
+"SRC/WIRCD.EXE: $(OBJ_FILES) src/version.obj\n"
+"        $(LINK) $(LFLAGS) $(OBJ_FILES)\n"
+"\n"
+"SRC/CHKCONF.EXE: ./include/struct.h ./include/config.h ./include/sys.h \\\n"
+"                 ./include/common.h ./src/crule.c ./src/match.c ./src/chkconf.c\n"
+"        $(CC) /nologo /I ./include /D CR_CHKCONF /Fosrc/chkcrule.obj /c src/crule.c\n"
+"        $(CC) /nologo /I ./include /D CR_CHKCONF /Fosrc/chkmatch.obj /c src/match.c\n"
+"        $(CC) /nologo /I ./include /D CR_CHKCONF /Fosrc/chkconf.obj /c src/chkconf.c\n"
+"        $(LINK) /nologo /out:src/chkconf.exe src/chkconf.obj src/chkmatch.obj \\\n"
+"                src/chkcrule.obj\n"
+"\n"
+"src/parse.obj: src/parse.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/parse.c\n"
+"\n"
+"src/bsd.obj: src/bsd.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/bsd.c\n"
+"\n"
+"src/dbuf.obj: src/dbuf.c $(INCLUDES) ./include/dbuf.h\n"
+"        $(CC) $(CFLAGS) src/dbuf.c\n"
+"\n"
+"src/packet.obj: src/packet.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/packet.c\n"
+"\n"
+"src/send.obj: src/send.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/send.c\n"
+"\n"
+"src/match.obj: src/match.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/match.c\n"
+"\n"
+"src/support.obj: src/support.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/support.c\n"
+"\n"
+"src/channel.obj: src/channel.c $(INCLUDES) ./include/channel.h\n"
+"        $(CC) $(CFLAGS) src/channel.c\n"
+"\n"
+"src/class.obj: src/class.c $(INCLUDES) ./include/class.h\n"
+"        $(CC) $(CFLAGS) src/class.c\n"
+"\n"
+"src/ircd.obj: src/ircd.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/ircd.c\n"
+"\n"
+"src/list.obj: src/list.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/list.c\n"
+"\n"
+"src/res.obj: src/res.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/res.c\n"
+"\n"
+"src/s_bsd.obj: src/s_bsd.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/s_bsd.c\n"
+"\n"
+"src/s_auth.obj: src/s_auth.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/s_auth.c\n"
+"\n"
+"src/s_conf.obj: src/s_conf.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/s_conf.c\n"
+"\n"
+"src/s_debug.obj: src/s_debug.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/s_debug.c\n"
+"\n"
+"src/s_err.obj: src/s_err.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/s_err.c\n"
+"\n"
+"src/s_misc.obj: src/s_misc.c $(INCLUDES) ./include/dbuf.h\n"
+"        $(CC) $(CFLAGS) src/s_misc.c\n"
+"\n"
+"src/s_user.obj: src/s_user.c $(INCLUDES) ./include/dbuf.h \\\n"
+"                ./include/channel.h ./include/whowas.h\n"
+"        $(CC) $(CFLAGS) src/s_user.c\n"
+"\n"
+"src/dynconf.obj: src/dynconf.c $(INCLUDES) ./include/dbuf.h \\\n"
+"                ./include/channel.h ./include/whowas.h ./include/dynconf.h\n"
+"        $(CC) $(CFLAGS) src/dynconf.c\n"
+"\n"
+"src/s_unreal.obj: src/s_unreal.c $(INCLUDES) ./include/dbuf.h \\\n"
+"                ./include/channel.h ./include/whowas.h\n"
+"        $(CC) $(CFLAGS) src/s_unreal.c\n"
+"\n"
+"src/cloak.obj: src/cloak.c $(INCLUDES) ./include/dbuf.h \\\n"
+"                ./include/channel.h ./include/whowas.h\n"
+"        $(CC) $(CFLAGS) src/s_unreal.c\n"
+"\n"
+"src/s_serv.obj: src/s_serv.c $(INCLUDES) ./include/dbuf.h ./include/whowas.h\n"
+"        $(CC) $(CFLAGS) src/s_serv.c\n"
+"\n"
+"src/s_numeric.obj: src/s_numeric.c $(INCLUDES) ./include/dbuf.h\n"
+"        $(CC) $(CFLAGS) src/s_numeric.c\n"
+"\n"
+"src/whowas.obj: src/whowas.c $(INCLUDES) ./include/dbuf.h ./include/whowas.h\n"
+"        $(CC) $(CFLAGS) src/whowas.c\n"
+"\n"
+"src/hash.obj: src/hash.c $(INCLUDES) ./include/hash.h\n"
+"        $(CC) $(CFLAGS) src/hash.c\n"
+"\n"
+"src/crule.obj: src/crule.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/crule.c\n"
+"\n"
+"src/win32.obj: src/win32.c $(INCLUDES) ./include/resource.h\n"
+"        $(CC) $(CFLAGS) src/win32.c\n"
+"\n"
+"src/cio_main.obj: src/cio_main.c $(INCLUDES) ./include/cio.h ./include/ciofunc.h\n"
+"        $(CC) $(CFLAGS) src/cio_main.c\n"
+"\n"
+"src/cio_init.obj: src/cio_init.c $(INCLUDES) ./include/cio.h ./include/ciofunc.h\n"
+"        $(CC) $(CFLAGS) src/cio_init.c\n"
+"\n"
+"src/res_comp.obj: src/res_comp.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/res_comp.c\n"
+"\n"
+"src/res_init.obj: src/res_init.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/res_init.c\n"
+"\n"
+"src/help.obj: src/help.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/help.c\n"
+"\n"
+"src/md5.obj: src/md5.c $(INCLUDES)\n"
+"        $(CC) $(CFLAGS) src/md5.c\n"
+"\n"
+"src/win32.res: src/win32.rc\n"
+"        $(RC) /l 0x409 /fosrc/win32.res /i ./include /i ./src \\\n"
+"              /d NDEBUG src/win32.rc\n"
+"\n"
+"dummy:\n"
+"\n";
+
+
+char SetupH[] =
+"/* This is only a wrapper.. --Stskeeps */\n"
+"#include \"win32/setup.h\"\n";
+
+
+int     main(int argc, char *argv[])
+{
+       if (argc>1)
+           {
+               if (!strcmp(argv[1], "-v"))
+                       return do_version();
+
+               if (!strcmp(argv[1], "-n"))
+                       return do_config(1);
+           }
+       printf("To do win32 compiling copy include/win32/setup.h to include/\n");
+       printf("Copy include/win32/settings.h to include/ and modify it\n");
+       printf("and copy makefile.win32 to Makefile\n");
+//     return do_config(0);
+}
+
+
+int     do_config(int autoconf)
+{
+       int     fd;
+       char    str[128];
+
+
+       if ((fd = open("include\\setup.h", O_CREAT|O_TRUNC|O_WRONLY|O_TEXT,
+                      S_IREAD|S_IWRITE)) == -1)
+               printf("Error opening include\\setup.h\n\r");
+       else
+           {
+               write(fd, SetupH, strlen(SetupH));
+               close(fd);
+           }
+
+       while (1)
+           {
+               /*
+                * FD_SETSIZE
+                */
+               printf("\n");
+               printf("How many file descriptors (or sockets) can the irc server use?");
+               printf("\n");
+               printf("[%d] -> ", _FD_SETSIZE);
+               gets(str);
+               if (*str != '\n' && *str != '\r')
+                       sscanf(str, "%d", &_FD_SETSIZE);
+
+               if (_FD_SETSIZE >= 100)
+                   {
+                       printf("\n");
+                       printf("FD_SETSIZE will be overridden using -D "
+                              "FD_SETSIZE=%d when compiling ircd.", _FD_SETSIZE);
+                       printf("\n");
+                       break;
+                   }
+               printf("\n");
+               printf("You need to enter a number here, greater or equal to 100.\n");
+           }
+               while (1) {
+               }
+       /*
+        * Now write the makefile out.
+        */
+       write_makefile();
+
+       return 0;
+}
+
+
+int     write_makefile(void)
+{
+       int     fd, makfd, len;
+       char    *buffer, *s;
+
+       buffer = (char *)malloc(strlen(Makefile)+4096);
+       memcpy(buffer, Makefile, strlen(Makefile)+1);
+
+       s = (char *)strstr(buffer, "$FD_SETSIZE");
+       if (s)
+           {
+               itoa(_FD_SETSIZE, s, 10);
+               memmove(s+strlen(s), s+11, strlen(s+11)+1);
+           }
+
+
+       if ((makfd = open("Makefile", O_CREAT|O_TRUNC|O_WRONLY|O_TEXT,
+                      S_IREAD|S_IWRITE)) == -1)
+           {
+               printf("Error creating Makefile\n\r");
+               return 1;
+           }
+       write(makfd, buffer, strlen(buffer));
+       close(makfd);
+
+       free(buffer);
+       return 0;
+}
+
+
+int     do_version(void)
+{
+       int     fd, verfd, generation=0, len, doingvernow=0;
+       char    buffer[16384], *s;
+
+       if ((verfd = open("src\\version.c", O_RDONLY | O_TEXT)) != -1)
+           {
+               while (!eof(verfd))
+                   {
+                       len = read(verfd, buffer, sizeof(buffer)-1);
+                       if (len == -1)
+                               break;
+                       buffer[len] = 0;
+                       s = (char *)strstr(buffer, "char *generation = \"");
+                       if (s)
+                           {
+                               s += 20;
+                               generation = atoi(s);
+                               break;
+                           }
+                   }
+
+                   close(verfd);
+           }
+
+       if ((fd = open("src\\version.c.SH", O_RDONLY | O_TEXT)) == -1)
+           {
+               printf("Error opening src\\version.c.SH\n\r");
+               return 1;
+           }
+
+       if ((verfd = open("src\\version.c", O_CREAT|O_TRUNC|O_WRONLY|O_TEXT,
+                      S_IREAD|S_IWRITE)) == -1)
+           {
+               printf("Error opening src\\version.c\n\r");
+               return 1;
+           }
+
+       generation++;
+
+       printf("Extracting IRC/ircd/version.c...\n\r");
+
+       while (!eof(fd))
+           {
+               len = read(fd, buffer, sizeof(buffer)-1);
+               if (len == -1)
+                       break;
+               buffer[len] = 0;
+               if (!doingvernow)
+                   {
+                       s = (char *)strstr(buffer, "/*");
+                       if (!s)
+                               continue;
+                       memmove(buffer, s, strlen(s)+1);
+                       doingvernow=1;
+                   }
+               s = (char *)strstr(buffer, "$generation");
+               if (s)
+                   {
+                       itoa(generation, s, 10);
+                       memmove(s+strlen(s), s+11, strlen(s+11)+1);
+                   }
+               s = (char *)strstr(buffer, "$creation");
+               if (s)
+                   {
+                       time_t  t = time(0);
+                       char    *ct = ctime(&t);
+
+                       memmove(s+strlen(ct)-1, s+9, strlen(s+9)+1);
+                       memmove(s, ct, strlen(ct)-1);
+                   }
+               s = (char *)strstr(buffer, "$package");
+               if (s)
+                   {
+                       memmove(s, "IRC", 3);
+                       memmove(s+3, s+8, strlen(s+8)+1);
+                   }
+
+               s = (char *)strstr(buffer, "!SUB!THIS!");
+               if (s)
+                       *s = 0;
+
+               write(verfd, buffer, strlen(buffer));
+           }
+
+       close(fd);
+       close(verfd);
+       return 0;
+}
+
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..c6f58c3
--- /dev/null
@@ -0,0 +1,177 @@
+#************************************************************************
+#*   IRC - Internet Relay Chat, src/Makefile
+#*   Copyright (C) 1990 Jarkko Oikarinen
+#*
+#*   This program is free software; you can redistribute it and/or modify
+#*   it under the terms of the GNU General Public License as published by
+#*   the Free Software Foundation; either version 1, or (at your option)
+#*   any later version.
+#*
+#*   This program is distributed in the hope that it will be useful,
+#*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#*   GNU General Public License for more details.
+#*
+#*   You should have received a copy of the GNU General Public License
+#*   along with this program; if not, write to the Free Software
+#*   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#*   
+#*   $Id$
+#*/
+
+CC=danger will robinson
+
+LINTFLAGS=-hba
+
+OBJS=bsd.o dbuf.o packet.o send.o match.o parse.o support.o channel.o \
+       class.o hash.o ircd.o list.o res.o cloak.o s_auth.o s_bsd.o s_conf.o \
+       s_debug.o s_err.o s_extra.o s_misc.o s_numeric.o s_serv.o s_user.o s_unreal.o \
+       whowas.o userload.o crule.o help.o md5.o version.o dynconf.o \
+        s_socks.o s_kline.o fdlist.o \
+       $(RES) $(STRTOUL)
+
+SRC=$(OBJS:%.o=%.c)
+
+MAKE = make 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'IRCDLIBS=${IRCDLIBS}' \
+           'LDFLAGS=${LDFLAGS}' 'IRCDMODE=${IRCDMODE}'
+
+INCLUDES = ../include/struct.h ../include/config.h ../include/settings.h \
+       ../include/sys.h ../include/common.h ../include/version.h \
+       ../include/h.h ../include/numeric.h ../include/msg.h \
+       ../include/dynconf.h
+
+all: build
+
+build: ircd chkconf
+
+version.c:
+       $(SHELL) version.c.SH
+
+version.o: version.c ../include/version.h
+       $(CC) $(CFLAGS) -c version.c
+
+ircd: $(OBJS) 
+       $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(IRCDLIBS) -o ircd
+       chmod $(IRCDMODE) ircd
+
+chkconf: ../include/struct.h ../include/config.h ../include/settings.h ../include/sys.h \
+        ../include/common.h crule.c chkconf.c
+       $(CC) $(CFLAGS) -DCR_CHKCONF -o chkcrule.o -c crule.c
+       $(CC) $(CFLAGS) -DCR_CHKCONF -o chkmatch.o -c match.c
+       $(CC) $(CFLAGS) chkconf.c chkmatch.o chkcrule.o \
+       $(LDFLAGS) $(IRCDLIBS) -o chkconf
+
+saber: $(SRC)
+       #load -I../include $(SRC) version.c $(IRCDLIBS)
+
+lint:
+       lint $(LINTFLAGS) -I../include $(SRC) | egrep -v 'sendto_|debug'
+
+parse.o: parse.c $(INCLUDES)
+bsd.o: bsd.c $(INCLUDES)
+dbuf.o: dbuf.c $(INCLUDES) ../include/dbuf.h
+packet.o: packet.c $(INCLUDES)
+send.o: send.c $(INCLUDES)
+match.o: match.c $(INCLUDES)
+support.o: support.c $(INCLUDES)
+
+#install: all
+#      -if [ ! -d ${IRCDDIR} -a ! -f ${IRCDDIR} ] ; then \
+#              mkdir ${IRCDDIR}; \
+#      fi
+#      ../bsdinstall -m ${IRCDMODE} ircd ${BINDIR}
+#      ../bsdinstall -m 700 chkconf ${BINDIR}
+#      $(CP) ../doc/example.conf ${IRCDDIR}
+#      $(TOUCH) ${IRCDDIR}/ircd.motd
+#      $(RM) -f ${IRCDDIR}/ircd.m4
+#      $(TOUCH) ${IRCDDIR}/ircd.m4
+#      chmod +x buildm4
+#      ./buildm4 ${IRCDDIR}
+
+clean:
+       $(RM) -f *.o *~ core ircd version.c chkconf
+
+cleandir: clean
+
+depend:
+       makedepend -I${INCLUDEDIR} ${SRC}
+
+channel.o: channel.c $(INCLUDES) ../include/channel.h
+       $(CC) $(CFLAGS) -c channel.c
+
+class.o: class.c $(INCLUDES) ../include/class.h
+       $(CC) $(CFLAGS) -c class.c
+
+ircd.o: ircd.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c ircd.c
+
+list.o: list.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c list.c
+
+res.o: res.c ../include/res.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c res.c
+
+cloak.o: cloak.c ../include/res.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c cloak.c
+
+fdlist.o: fdlist.c ../include/fdlist.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c fdlist.c
+
+s_bsd.o: s_bsd.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_bsd.c
+
+s_auth.o: s_auth.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_auth.c
+
+s_socks.o: s_socks.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_socks.c
+
+s_conf.o: s_conf.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_conf.c
+
+s_debug.o: ../include/sys.h s_debug.c $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_debug.c
+
+s_err.o: ../include/msg.h s_err.c $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_err.c
+
+s_misc.o: s_misc.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_misc.c
+
+s_user.o: s_user.c $(INCLUDES) \
+         ../include/dbuf.h ../include/channel.h ../include/whowas.h
+       $(CC) $(CFLAGS) -c s_user.c
+
+s_extra.o: s_extra.c $(INCLUDES) \
+         s_numeric.c ../include/dbuf.h ../include/channel.h ../include/whowas.h
+       $(CC) $(CFLAGS) -c s_extra.c
+
+s_kline.o: s_kline.c $(INCLUDES) \
+         s_numeric.c ../include/dbuf.h ../include/channel.h ../include/whowas.h
+       $(CC) $(CFLAGS) -c s_kline.c
+
+s_unreal.o: s_unreal.c $(INCLUDES) \
+         s_numeric.c ../include/dbuf.h ../include/channel.h ../include/whowas.h
+       $(CC) $(CFLAGS) -c s_unreal.c
+
+s_serv.o: s_serv.c $(INCLUDES) \
+         ../include/dbuf.h ../include/whowas.h
+       $(CC) $(CFLAGS) -c s_serv.c
+
+s_numeric.o: s_numeric.c ../include/dbuf.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c s_numeric.c
+
+whowas.o: whowas.c ../include/dbuf.h ../include/whowas.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c whowas.c
+
+hash.o: hash.c ../include/hash.h $(INCLUDES)
+       $(CC) $(CFLAGS) -c hash.c
+
+crule.o: crule.c $(INCLUDES)
+       $(CC) $(CFLAGS) -c crule.c
+
+dynconf.o: dynconf.c $(INCLUDES) \
+         s_numeric.c ../include/dbuf.h ../include/channel.h ../include/whowas.h ../include/dynconf.h
+       $(CC) $(CFLAGS) -c dynconf.c
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/src/bsd.c b/src/bsd.c
new file mode 100644 (file)
index 0000000..a2ba8ef
--- /dev/null
+++ b/src/bsd.c
@@ -0,0 +1,202 @@
+/************************************************************************
+ *   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 "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include <signal.h>
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen");
+
+
+#ifndef _WIN32
+extern int errno; /* ...seems that errno.h doesn't define this everywhere */
+#endif
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__linux__)
+extern char    *sys_errlist[];
+#endif
+
+#ifdef DEBUGMODE
+int    writecalls = 0, writeb[10] = {0,0,0,0,0,0,0,0,0,0};
+#endif
+#ifndef _WIN32
+VOIDSIG dummy()
+{
+#ifndef HAVE_RELIABLE_SIGNALS
+       (void)signal(SIGALRM, dummy);
+       (void)signal(SIGPIPE, dummy);
+#ifndef HPUX   /* Only 9k/800 series require this, but don't know how to.. */
+# ifdef SIGWINCH
+       (void)signal(SIGWINCH, dummy);
+# endif
+#endif
+#else
+# ifdef POSIX_SIGNALS
+       struct  sigaction       act;
+
+       act.sa_handler = dummy;
+       act.sa_flags = 0;
+       (void)sigemptyset(&act.sa_mask);
+       (void)sigaddset(&act.sa_mask, SIGALRM);
+       (void)sigaddset(&act.sa_mask, SIGPIPE);
+#  ifdef SIGWINCH
+       (void)sigaddset(&act.sa_mask, SIGWINCH);
+#  endif
+       (void)sigaction(SIGALRM, &act, (struct sigaction *)NULL);
+       (void)sigaction(SIGPIPE, &act, (struct sigaction *)NULL);
+#  ifdef SIGWINCH
+       (void)sigaction(SIGWINCH, &act, (struct sigaction *)NULL);
+#  endif
+# endif
+#endif
+}
+#endif /* _WIN32 */
+
+
+/*
+** 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...
+**
+**     *NOTE*  I nuked 'em.  At the load of current ircd servers
+**             you can't run with stuff that blocks. And we don't.
+*/
+int    deliver_it(cptr, str, len)
+aClient *cptr;
+int    len;
+char   *str;
+    {
+       int     retval;
+       aClient *acpt = cptr->acpt;
+
+#ifdef DEBUGMODE
+       writecalls++;
+#endif
+#ifdef VMS
+       retval = netwrite(cptr->fd, str, len);
+#else
+       if (IsDead(cptr) || (!IsServer(cptr) && !IsPerson(cptr) && !IsHandshake(cptr) && !IsUnknown(cptr)))
+       {
+         str[len]='\0';
+         sendto_ops("* * * DEBUG ERROR * * * !!! Calling deliver_it() for %s, status %d %s, with message: %s",
+             cptr->name, cptr->status, IsDead(cptr)?"DEAD":"", str);
+         return -1;
+       }
+       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
+       */
+# ifndef _WIN32
+       if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN ||
+                          errno == ENOBUFS))
+# else
+       if (retval < 0 && (WSAGetLastError() == WSAEWOULDBLOCK ||
+           WSAGetLastError() == WSAENOBUFS))
+# endif
+           {
+               retval = 0;
+               SetBlocked(cptr);
+           }
+       else if (retval > 0)
+           {
+#ifdef pyr
+               (void)gettimeofday(&cptr->lw, NULL);
+#endif
+               ClearBlocked(cptr);
+           }
+
+#endif
+#ifdef DEBUGMODE
+       if (retval < 0) {
+               writeb[0]++;
+# ifndef _WIN32
+               Debug((DEBUG_ERROR,"write error (%s) to %s",
+                       sys_errlist[errno], cptr->name));
+# else
+               Debug((DEBUG_ERROR,"write error (%s) to %s",
+                       sys_errlist[WSAGetLastError()], cptr->name));
+# endif
+
+       } 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);
+}
diff --git a/src/buildm4 b/src/buildm4
new file mode 100644 (file)
index 0000000..894c9ec
--- /dev/null
@@ -0,0 +1,85 @@
+#!/bin/sh
+# IRC - Internet Relay Chat, ircd/buildm4
+# Copyright (C) 1993 Darren Reed
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# - $Id$
+#
+# If only this was a perl script...*sigh*
+#
+IRCDDIR=$1
+M4=$IRCDDIR/ircd.m4
+/bin/rm -f $M4
+egrep "^#def[^P]*VERSION" ../include/version.h | \
+sed -e 's/[^\"]*\"\([^\"]*\)\"/define(VERSION,\1)/' >>$M4
+DEBUG=`egrep "^#define[                ]*DEBUGMODE" ../include/config.h`
+if [ -n "$DEBUG" ] ; then
+       echo "define(DEBUGMODE,1)" >>$M4
+else
+       echo "undefine(DEBUGMODE)" >>$M4
+fi
+echo -n "define(HOSTNAME," >> $M4
+echo "`hostname`" | sed -e 's/\([a-zA-Z0-9\-]*\).*/\1)/' >> $M4
+echo "define(USER,$USER)" >>$M4
+echo -n 'define(PORT,' >>$M4
+PORT=`egrep '^#define[         ]*PORT[         ]*[0-9]*' ../include/config.h`
+echo "$PORT" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
+echo -n 'define(PFREQ,' >>$M4
+PING=`egrep '^#define[         ]*PINGFREQUENCY[        ]*[0-9]*' ../include/config.h`
+echo "$PING" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
+echo -n 'define(CFREQ,' >>$M4
+CONT=`egrep '^#define[         ]*CONNECTFREQUENCY[     ]*[0-9]*' ../include/config.h`
+echo "$CONT" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
+echo -n "define(MAXSENDQ," >>$M4
+MAXQ=`egrep '^#define[         ]*MAXSENDQLENGTH[       ]*[0-9]*' ../include/config.h`
+echo "$MAXQ" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
+echo -n "define(MAXLINKS," >>$M4
+MAXL=`egrep '^#define[         ]*MAXIMUM_LINKS[        ]*[0-9]* | head -1' \
+../include/config.h`
+echo "$MAXL" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
+DOM=`egrep '^domain' /etc/resolv.conf | \
+sed -e 's/^domain[     ]*\([a-zA-Z\-\.0-9]*\).*/\1/'`
+echo "define(DOMAIN,$DOM)" >> $M4
+
+cat >>$M4 <<_EOF_
+define(CL,\`ifelse(len(\$1),0,0,\$1)')
+define(HOST,\$1)
+define(HOSTM,\$1)
+define(ID,*@\$1)
+define(PASS,\$1)
+define(PING,\`ifelse(len(\$1),0,PFREQ,\$1)')
+define(APORT,\`ifelse(len(\$1),0,PORT,\$1)')
+define(FREQ,\`ifelse(len(\$1),0,CFREQ,\$1)')
+define(SENDQ,\`ifelse(len(\$1),0,MAXSENDQ,\$1)')
+define(MAX,\`ifelse(len(\$1),0,MAXLINKS,\$1)')
+define(CPORT,\$1)
+define(SERV,\$1)
+define(ADMIN,A:\$1:\$2:\$3:\$4:\$5)
+define(ALLOW,N:\`HOST(\$1)':\`PASS(\$2)':\`SERV(\$3)':\`HOSTM(\$4)':\`CL(\$5)')
+define(BAN,K:\$1:\$2:\$3)
+define(CLASS,Y:\$1:\`PING(\$2)':\$3:\`MAX(\$4)':\`SENDQ(\$5)')
+define(CLIENT,I:\`HOST(\$1)':\`PASS(\$2)':\`ifelse(len(HOST(\$3)),0,\$1,\$3)':\
+\`APORT(\$4)':\`CL(\$5)')
+define(CONNECT,C:\`HOST(\$1)':\`PASS(\$2)':\`SERV(\$3)':\
+\`CPORT(\$4)':\`CL(\$5)')
+define(ME,M:\$1:\$2:\$3:\$4:\$5)
+define(HUB,H:\`ifelse(len(\$2),0,*,\$2)':*:\$1)
+define(LEAF,L:\`ifelse(len(\$2),0,*,\$2)':*:\$1:1)
+define(SERVER,\`
+CONNECT(\$1,\$2,\$3,\$5,\$6)
+ALLOW(\$1,\$2,\$3,\$4,\$6)
+')
+_EOF_
diff --git a/src/channel.c b/src/channel.c
new file mode 100644 (file)
index 0000000..f42719d
--- /dev/null
@@ -0,0 +1,4529 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/channel.c
+ *   Copyright (C) 1990 Jarkko Oikarinen and
+ *                      University of Oulu, Co 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.
+ */
+/*
+ * 23 Jun 1999
+ * Changing unsigned int modes to long
+ * --- Sts - 28 May 1999
+    Incorporated twilight mode system
+*/
+/* -- Jto -- 09 Jul 1990
+ * Bug fix
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Moved m_channel() and related functions from s_msg.c to here
+ * Many changes to start changing into string channels...
+ */
+
+/* -- Jto -- 24 May 1990
+ * Moved is_full() from list.c
+ */
+
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "channel.h"
+#include "msg.h"       /* For TOK_*** and MSG_*** strings  */
+#include "hash.h"      /* For CHANNELHASHSIZE */
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1990 University of Oulu, Computing Center and Jarkko Oikarinen");
+
+#define MAXBOUNCE      5 /** Most sensible */
+
+typedef struct ChLink CHLINK;
+struct CHLink {
+       aChannel *chan;
+};
+
+static int     bouncedtimes = 0;
+
+struct CHLink  chlbounce[MAXBOUNCE];
+int    chbounce = 0;
+static long    opermode = 0;
+aChannel *channel = NullChn;
+extern aCRline *crlines;
+extern char    *cannotjoin_msg;
+// #define is_zombie(x,y) 0
+
+static void    add_invite PROTO((aClient *, aChannel *));
+static int     add_banid PROTO((aClient *, aChannel *, char *));
+static int     can_join PROTO((aClient *, aClient *, aChannel *, char *, char *, char **));
+static int     channel_link PROTO((aClient *, aClient *, int, char **));
+static void    channel_modes PROTO((aClient *, char *, char *, aChannel *));
+static int     check_channelmask PROTO((aClient *, aClient *, char *));
+static int     del_banid PROTO((aChannel *, char *));
+static int     find_banid PROTO((aChannel *, char *));
+static  int     have_ops PROTO((aChannel *));
+// static      int     number_of_zombies PROTO((aChannel *));
+static  int     is_deopped PROTO((aClient *, aChannel *));
+static void    set_mode PROTO((aChannel *, aClient *, int, char **, u_int *, \
+                       char [MAXMODEPARAMS][MODEBUFLEN+3], int));
+static void    make_mode_str PROTO((aChannel *, long, long, int,         \
+                       char [MAXMODEPARAMS][MODEBUFLEN+3], char *, char *, char));
+static int     do_mode_char PROTO((aChannel *, long, char, char *, u_int, \
+                       aClient *, u_int *, char [MAXMODEPARAMS][MODEBUFLEN+3], char));
+static void    do_mode PROTO((aChannel *, aClient *, aClient *, int, char **,
+                       int, int));
+static void    bounce_mode PROTO((aChannel *, aClient *, int, char **));
+
+static void    sub1_from_channel PROTO((aChannel *));
+
+void   clean_channelname PROTO((char *));
+void   del_invite PROTO((aClient *, aChannel *));
+
+static char    *PartFmt = ":%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 long    linkedjoined = 0;
+#include "sjoin.h"
+
+#ifdef USE_LONGMODE
+typedef struct {
+       long    mode;
+       char    flag;
+       int             halfop; /* 1 = yes 0 = no */
+} aCtab;
+// typedef struct CFlagTab aCtab;
+#define MODESYS_LINKOK /* We do this for a TEST  */
+aCtab cFlagTab[] = {
+               {MODE_LIMIT,            'l', 0},
+               {MODE_VOICE,            'v', 1},
+               {MODE_HALFOP,           'h', 0},
+               {MODE_CHANOP,           'o', 0},
+               {MODE_PRIVATE,          'p', 0},
+               {MODE_SECRET,           's', 0},
+               {MODE_MODERATED,        'm', 1},
+               {MODE_NOPRIVMSGS,       'n', 1},
+               {MODE_TOPICLIMIT,       't', 1},
+               {MODE_INVITEONLY,       'i', 1},
+               {MODE_KEY,              'k', 1},
+               {MODE_RGSTR,            'r', 0},
+               {MODE_RGSTRONLY,        'R', 0},
+               {MODE_NOCOLOR,          'c', 0},
+               {MODE_CHANPROT,         'a', 0},
+               {MODE_CHANOWNER,        'q', 0},
+               {MODE_OPERONLY,         'O', 0},
+               {MODE_ADMONLY,          'A', 0},
+               {MODE_LINK,             'L', 0},
+               {MODE_NOKICKS,          'Q', 0},
+               {MODE_BAN,              'b', 1},
+               {MODE_STRIP,            'S', 0}, /* works? */
+               {MODE_EXCEPT,           'e', 1}, /* exception ban */
+               {MODE_NOKNOCK,          'K', 0}, /* knock knock (no way!) */
+               {MODE_NOINVITE,         'V', 0}, /* no invites */       
+               {MODE_FLOODLIMIT,       'f', 0}, /* flood limiter */
+               {MODE_NOHIDING,         'H', 0}, /* no +I joiners */
+               {0x0, 0x0, 0x0}
+};
+#endif
+
+
+#define        BADOP_BOUNCE    1
+#define        BADOP_USER      2
+#define        BADOP_SERVER    3
+#define        BADOP_OVERRIDE  4
+
+/* is some kind of admin */
+#define IsSkoAdmin(sptr) (IsAdmin(sptr) || IsNetAdmin(sptr) || IsTechAdmin(sptr) || IsSAdmin(sptr))
+
+char   cmodestring[512];
+
+void   make_cmodestr(void)
+{
+       char    *p = &cmodestring[0];
+       aCtab   *tab = &cFlagTab[0];
+       
+       while (tab->mode != 0x0) {
+               *p = tab->flag;
+               p++;
+               tab++;
+       }
+       *p = '\0';
+}
+
+int    Halfop_mode(long mode) {
+       aCtab   *tab = &cFlagTab[0];
+       
+       while (tab->mode != 0x0) {
+               if (tab->mode == mode)
+                       return (tab->halfop == 1 ? TRUE : FALSE);
+               tab++;
+       }
+}
+
+/*
+ * return the length (>=0) of a chain of links.
+ */
+static int     list_length(lp)
+Reg1   Link    *lp;
+{
+       Reg2    int     count = 0;
+
+       for (; lp; lp = lp->next)
+               count++;
+       return count;
+}
+
+/*
+** 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(sptr, user, chasing)
+aClient *sptr;
+char   *user;
+Reg1   int     *chasing;
+{
+       Reg2    aClient *who = find_client(user, (aClient *)NULL);
+
+       if (chasing)
+               *chasing = 0;
+       if (who)
+               return who;
+       if (!(who = get_history(user, (long)KILLCHASETIMELIMIT)))
+           {
+               sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+                          me.name, sptr->name, user);
+               return NULL;
+           }
+       if (chasing)
+               *chasing = 1;
+       return who;
+}
+/*
+  Exception functions to work with mode +e
+   -sts
+
+
+/* add_exbanid - add an id to be excepted to the channel bans  (belongs to cptr) */
+
+static int     add_exbanid(cptr, chptr, banid)
+aClient        *cptr;
+aChannel *chptr;
+char   *banid;
+{
+       Reg1    Ban     *ban;
+       Reg2    int     cnt = 0, len = 0;
+
+       if (MyClient(cptr))
+               (void)collapse(banid);
+       for (ban = chptr->exlist; ban; ban = ban->next)
+           {
+               len += strlen(ban->banstr);
+               if (MyClient(cptr))
+                       if ((len > MAXBANLENGTH) || (++cnt >= MAXBANS))
+                           {
+                               sendto_one(cptr, err_str(ERR_BANLISTFULL),
+                                          me.name, cptr->name,
+                                          chptr->chname, banid);
+                               return -1;
+                           }
+                       else
+                           {
+                               if (!match(ban->banstr, banid) ||
+                                   !match(banid, ban->banstr))
+                                       return -1;
+                           }
+               else if (!mycmp(ban->banstr, banid))
+                       return -1;
+               
+           }
+       ban = make_ban();
+       bzero((char *)ban, sizeof(Ban));
+   /*  ban->flags = CHFL_BAN;                  They're all bans!! */
+       ban->next = chptr->exlist;
+       ban->banstr = (char *)MyMalloc(strlen(banid)+1);
+       (void)strcpy(ban->banstr, banid);
+       ban->who = (char *)MyMalloc(strlen(cptr->name)+1);
+       (void)strcpy(ban->who, cptr->name);
+       ban->when = TStime();
+       chptr->exlist = ban;
+       return 0;
+}
+/*
+ * del_exbanid - delete an id belonging to cptr
+ */
+static int     del_exbanid(chptr, banid)
+aChannel *chptr;
+char   *banid;
+{
+       Reg1 Ban **ban;
+       Reg2 Ban *tmp;
+
+       if (!banid)
+               return -1;
+       for (ban = &(chptr->exlist); *ban; ban = &((*ban)->next))
+               if (mycmp(banid, (*ban)->banstr)==0)
+                   {
+                       tmp = *ban;
+                       *ban = tmp->next;
+                       MyFree(tmp->banstr);
+                       MyFree(tmp->who);
+                       free_ban(tmp);
+                       return 0;
+                   }
+       return -1;
+}
+
+/*
+ * find_banid - Find an exact match for a exban
+ */
+static int     find_exbanid(chptr, banid)
+aChannel *chptr;
+char   *banid;
+{
+       Reg1 Ban **ban;
+       Reg2 Ban *tmp;
+
+       if (!banid)
+               return -1;
+       for (ban = &(chptr->exlist); *ban; ban = &((*ban)->next))
+               if (!mycmp(banid, (*ban)->banstr)) return 1;
+       return 0;
+}
+
+
+/*
+ * Ban functions to work with mode +b
+ */
+/* add_banid - add an id to be banned to the channel  (belongs to cptr) */
+
+static int     add_banid(cptr, chptr, banid)
+aClient        *cptr;
+aChannel *chptr;
+char   *banid;
+{
+       Reg1    Ban     *ban;
+       Reg2    int     cnt = 0, len = 0;
+
+       if (MyClient(cptr))
+               (void)collapse(banid);
+       for (ban = chptr->banlist; ban; ban = ban->next)
+           {
+               len += strlen(ban->banstr);
+               if (MyClient(cptr))
+                       if ((len > MAXBANLENGTH) || (++cnt >= MAXBANS))
+                           {
+                               sendto_one(cptr, err_str(ERR_BANLISTFULL),
+                                          me.name, cptr->name,
+                                          chptr->chname, banid);
+                               return -1;
+                           }
+                       else
+                           {
+                               if (!match(ban->banstr, banid) ||
+                                   !match(banid, ban->banstr))
+                                       return -1;
+                           }
+               else if (!mycmp(ban->banstr, banid))
+                       return -1;
+               
+           }
+       ban = make_ban();
+       bzero((char *)ban, sizeof(Ban));
+   /*  ban->flags = CHFL_BAN;                  They're all bans!! */
+       ban->next = chptr->banlist;
+       ban->banstr = (char *)MyMalloc(strlen(banid)+1);
+       (void)strcpy(ban->banstr, banid);
+       ban->who = (char *)MyMalloc(strlen(cptr->name)+1);
+       (void)strcpy(ban->who, cptr->name);
+       ban->when = TStime();
+       chptr->banlist = ban;
+       return 0;
+}
+/*
+ * del_banid - delete an id belonging to cptr
+ */
+static int     del_banid(chptr, banid)
+aChannel *chptr;
+char   *banid;
+{
+       Reg1 Ban **ban;
+       Reg2 Ban *tmp;
+
+       if (!banid)
+               return -1;
+       for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
+               if (mycmp(banid, (*ban)->banstr)==0)
+                   {
+                       tmp = *ban;
+                       *ban = tmp->next;
+                       MyFree(tmp->banstr);
+                       MyFree(tmp->who);
+                       free_ban(tmp);
+                       return 0;
+                   }
+       return -1;
+}
+
+/*
+ * find_banid - Find an exact match for a ban
+ */
+static int     find_banid(chptr, banid)
+aChannel *chptr;
+char   *banid;
+{
+       Reg1 Ban **ban;
+       Reg2 Ban *tmp;
+
+       if (!banid)
+               return -1;
+       for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
+               if (!mycmp(banid, (*ban)->banstr)) return 1;
+       return 0;
+}
+
+/*
+ * IsMember - returns 1 if a person is joined and not a zombie
+ * Moved to struct.h
+ */
+
+/*
+ * is_banned - returns a pointer to the ban structure if banned else NULL
+ */
+extern Ban     *is_banned(cptr, sptr, chptr)
+aClient *cptr, *sptr;
+aChannel *chptr;
+{
+       Reg1    Ban     *tmp;
+       char    *s, realhost[NICKLEN+USERLEN+HOSTLEN+6],
+                    virthost[NICKLEN+USERLEN+HOSTLEN+6];
+
+        int     dovirt = 0;
+
+        if (!IsPerson(cptr))
+                return NULL;
+
+        if (strcmp(cptr->user->realhost, cptr->user->virthost))
+             dovirt = 1;
+
+        s = make_nick_user_host(cptr->name, cptr->user->username,
+                                  cptr->user->realhost);
+        strcpy(realhost, s);
+
+        s = make_nick_user_host(cptr->name, cptr->user->username,
+                                  cptr->user->virthost);
+        strcpy(virthost, s);
+          /* -- exceptions are BEFORE testing bans */
+       for (tmp = chptr->exlist; tmp; tmp = tmp->next)
+                       if ((match(tmp->banstr, realhost) == 0) ||
+                                       (dovirt && (match(tmp->banstr, virthost) == 0))
+                               )
+                                               return (NULL); /* exception ! */
+
+        for (tmp = chptr->banlist; tmp; tmp = tmp->next)
+                if ((match(tmp->banstr, realhost) == 0) ||
+                    (dovirt && (match(tmp->banstr, virthost) == 0))
+                   )
+                        break;
+        return (tmp);
+}
+
+/*
+ * adds a user to a channel by adding another link to the channels member
+ * chain.
+ */
+static void    add_user_to_channel(chptr, who, flags)
+aChannel *chptr;
+aClient *who;
+int    flags;
+{
+       Reg1    Link *ptr;
+
+       if (who->user)
+           {
+               ptr = make_link();
+               ptr->value.cptr = who;
+               ptr->flags = flags;
+               ptr->flood = (aFloodOpt *) MyMalloc(sizeof(aFloodOpt));
+               ptr->flood->nmsg = 0;
+               ptr->flood->lastmsg = 0;
+               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++;
+           }
+}
+
+void   remove_user_from_channel(sptr, chptr)
+aClient *sptr;
+aChannel *chptr;
+{
+       Reg1    Link    **curr;
+       Reg2    Link    *tmp;
+       Reg3    Link    *lp = chptr->members;
+
+       for (; lp && (lp->value.cptr==sptr);
+           lp=lp->next);
+       for (;;)
+       {
+         for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
+                 if (tmp->value.cptr == sptr)
+                     {
+                         if (tmp->flood)
+                               MyFree((aFloodOpt *) tmp->flood);
+                         *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;
+                     }
+         sptr->user->joined--;
+         if (lp) break;
+         if (chptr->members) sptr = chptr->members->value.cptr;
+         else break;
+         sub1_from_channel(chptr);
+       }
+       sub1_from_channel(chptr);
+}
+
+
+static int     have_ops(chptr)
+aChannel *chptr;
+{
+       Reg1    Link    *lp;
+
+       if (chptr)
+        {
+         lp=chptr->members;
+         while (lp)
+         {
+           if (lp->flags & CHFL_CHANOP) return(1);
+           lp = lp->next;
+         }
+        }
+       return 0;
+}
+
+int    is_chan_op(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+       Reg1    Link    *lp;
+/* chanop/halfop ? */
+       if (chptr)
+               if (lp = find_user_link(chptr->members, cptr))
+                       return ((lp->flags & CHFL_CHANOP));
+
+       return 0;
+}
+
+
+/* This was the original function that allowed mode hacking - not
+   anymore. -- Barubary */
+static int     is_deopped(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+       if (!IsPerson(cptr)) return 0;
+       return !is_chan_op(cptr, chptr);
+}
+
+
+int    has_voice(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+       Reg1    Link    *lp;
+
+       if (chptr)
+               if ((lp = find_user_link(chptr->members, cptr)))
+                       return (lp->flags & CHFL_VOICE);
+
+       return 0;
+}
+int            is_halfop(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+        Reg1    Link    *lp;
+
+        if (chptr)
+                if (lp = find_user_link(chptr->members, cptr))
+                       if (!is_chan_op(cptr, chptr)) /* excessive but needed */
+                        return (lp->flags & CHFL_HALFOP);
+
+        return 0;
+}
+
+int     is_chanowner(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+        Reg1    Link    *lp;
+
+        if (chptr)
+                if (lp = find_user_link(chptr->members, cptr))
+                        return (lp->flags & CHFL_CHANOWNER);
+
+        return 0;
+}
+
+int     is_chanprot(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+        Reg1    Link    *lp;
+
+        if (chptr)
+                if (lp = find_user_link(chptr->members, cptr))
+                        return (lp->flags & CHFL_CHANPROT);
+
+        return 0;
+}
+
+#define CANNOT_SEND_MODERATED 1
+#define CANNOT_SEND_NOPRIVMSGS 2
+#define CANNOT_SEND_NOCOLOR 3
+#define CANNOT_SEND_BAN 4
+// #define CAN_SEND_STRIP 5
+
+int    can_send(cptr, chptr, msgtext)
+aClient *cptr;
+aChannel *chptr;
+char   *msgtext;
+{
+       Reg1    Link    *lp;
+       Reg2    int     member;
+
+       /* Moved check here, kinda faster.
+        * Note IsULine only uses the other parameter. -Donwulff */
+       if (IsULine(cptr,cptr)||IsServer(cptr)) return 0;
+
+       member = IsMember(cptr, chptr);
+       lp = find_user_link(chptr->members, cptr);
+
+       if (chptr->mode.mode & MODE_MODERATED &&
+           (!lp || !(lp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANPROT))))
+                       return (CANNOT_SEND_MODERATED);
+
+       if (chptr->mode.mode & MODE_NOPRIVMSGS && !member)
+               /* Yet another bug by Potvin
+               return (CANNOT_SEND_MODERATED);
+               */
+               return (CANNOT_SEND_NOPRIVMSGS);
+
+        if (chptr->mode.mode & MODE_NOCOLOR)
+          if(strchr((char *) msgtext, 3) || strchr((char *) msgtext, 27))
+            return (CANNOT_SEND_NOCOLOR);
+/* Fixed strip bug --sts */
+/*     if (chptr->mode.mode & MODE_STRIP) {
+               if ((strchr(msgtext, 3) != NULL) ||
+                 (strchr(msgtext, 27) != NULL)) {
+                       return (CAN_SEND_STRIP);                        
+               }
+       }       
+*/
+if ((!lp || !(lp->flags & (CHFL_CHANOP|CHFL_VOICE|CHFL_CHANOWNER|CHFL_HALFOP|CHFL_CHANPROT))) && MyClient(cptr) &&
+    is_banned(cptr, cptr, chptr))
+       return (CANNOT_SEND_BAN);
+
+       return 0;
+}
+
+aChannel *find_channel(chname, chptr)
+Reg1   char    *chname;
+Reg2   aChannel *chptr;
+{
+       return hash_find_channel(chname, chptr);
+}
+
+/*
+ * write the "simple" list of channel modes for channel chptr onto buffer mbuf
+ * with the parameters in pbuf.
+ */
+static void    channel_modes(cptr, mbuf, pbuf, chptr)
+aClient        *cptr;
+Reg1   char    *mbuf, *pbuf;
+aChannel *chptr;
+{
+       int                             *ip, *ipx;
+       long                            zode;
+       aCtab                   *tab = &cFlagTab[0];
+       char                            bcbuf[1024];
+
+       *mbuf++ = '+';
+       while (tab->mode != 0x0) {
+         if ((chptr->mode.mode & tab->mode)) {
+               zode = chptr->mode.mode;
+               if (!(zode & (MODE_LIMIT|MODE_KEY|MODE_LINK)))
+                       if (!(zode & (MODE_CHANOP|MODE_VOICE|MODE_CHANOWNER)))
+                               if (!(zode & (MODE_BAN|MODE_EXCEPT|MODE_CHANPROT)))
+                                       if (!(zode & (MODE_HALFOP)))
+                                               *mbuf++ = tab->flag;
+          }
+          tab++;
+       }
+       if (chptr->mode.limit)
+           {
+               *mbuf++ = 'l';
+               if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr,cptr))
+                       (void)sprintf(pbuf, "%d ", chptr->mode.limit);
+           }
+       if (*chptr->mode.key)
+           {
+               *mbuf++ = 'k';
+               if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr,cptr))
+                       (void)strcat(pbuf, chptr->mode.key);
+           }
+        if (*chptr->mode.link)
+            {
+                *mbuf++ = 'L';
+                if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr,cptr))
+                        (void)strcat(pbuf, chptr->mode.link);
+            }
+       if (chptr->mode.per)
+       {
+               *mbuf++ = 'f';
+                if (IsMember(cptr, chptr) || IsServer(cptr) || IsULine(cptr,cptr))
+                {
+                       if (chptr->mode.kmode == 1)
+                               sprintf(bcbuf, "*%i:%i", chptr->mode.msgs, chptr->mode.per);
+                       else
+                               sprintf(bcbuf, "%i:%i", chptr->mode.msgs, chptr->mode.per);
+                       (void)strcat(pbuf, bcbuf);
+                }
+
+       }
+       *mbuf++ = '\0';
+       return;
+}
+
+static int send_mode_list(cptr, chname, creationtime, top, mask, flag)
+aClient        *cptr;
+Link   *top;
+int    mask;
+char   flag, *chname;
+time_t creationtime;
+{
+       Reg1    Link    *lp;
+       Reg2    char    *cp, *name;
+       int     count = 0, send = 0, sent = 0;
+
+       cp = modebuf + strlen(modebuf);
+       if (*parabuf)   /* mode +l or +k xx */
+               count = 1;
+       for (lp = top; lp; lp = lp->next)
+           {
+               /* 
+                * Okay, since ban's are stored in their own linked
+                * list, we won't even bother to check if CHFL_BAN
+                * is set in the flags. This should work as long
+                * as only ban-lists are feed in with CHFL_BAN mask.
+                * However, we still need to typecast... -Donwulff 
+                */
+               if ((mask == CHFL_BAN) || (mask == CHFL_EXCEPT)) {
+/*                     if (!(((Ban *)lp)->flags & mask)) continue; */
+                       name = ((Ban *)lp)->banstr;
+               } else {
+                       if (!(lp->flags & mask)) continue;
+                       name = lp->value.cptr->name;
+               }
+               if (strlen(parabuf) + strlen(name) + 11 < (size_t) MODEBUFLEN)
+                   {
+                       if(*parabuf) (void)strcat(parabuf, " ");
+                       (void)strcat(parabuf, name);
+                       count++;
+                       *cp++ = flag;
+                       *cp = '\0';
+                   }
+               else if (*parabuf)
+                       send = 1;
+               if (count == RESYNCMODES)
+                       send = 1;
+               if (send)
+                   {
+                      /* cptr is always a server! So we send creationtimes */
+                       sendmodeto_one(cptr, me.name, chname, modebuf,
+                                  parabuf, creationtime);
+                        sent = 1;
+                       send = 0;
+                       *parabuf = '\0';
+                       cp = modebuf;
+                       *cp++ = '+';
+                       if (count != RESYNCMODES)
+                           {
+                               (void)strcpy(parabuf, name);
+                               *cp++ = flag;
+                           }
+                       count = 0;
+                       *cp = '\0';
+                   }
+           }
+     return sent;
+}
+
+/*
+ * send "cptr" a full list of the modes for channel chptr.
+ */
+void   send_channel_modes(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{       int sent;
+/* fixed a bit .. to fit halfops --sts */
+       if (*chptr->chname != '#')
+               return;
+
+       *parabuf = '\0';
+       *modebuf = '\0';
+       channel_modes(cptr, modebuf, parabuf, chptr);
+       sent=send_mode_list(cptr, chptr->chname, chptr->creationtime,
+           chptr->members, CHFL_CHANOP, 'o');
+       if (!sent && chptr->creationtime)
+         sendto_one(cptr, ":%s %s %s %s %s %lu", me.name,
+             (IsToken(cptr)?TOK_MODE:MSG_MODE), 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';
+
+       sent=send_mode_list(cptr, chptr->chname, chptr->creationtime,
+           chptr->members, CHFL_HALFOP, 'h');
+       if (!sent && chptr->creationtime)
+         sendto_one(cptr, ":%s %s %s %s %s %lu", me.name,
+             (IsToken(cptr)?TOK_MODE:MSG_MODE), 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';
+       (void)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';
+       (void)send_mode_list(cptr, chptr->chname,chptr->creationtime,
+           chptr->exlist, CHFL_EXCEPT, 'e');
+       if (modebuf[1] || *parabuf)
+         sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
+             parabuf, chptr->creationtime);
+
+       *parabuf = '\0';
+       *modebuf = '+';
+       modebuf[1] = '\0';
+       (void)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);
+
+        *parabuf = '\0';
+        *modebuf = '+';
+        modebuf[1] = '\0';
+        (void)send_mode_list(cptr, chptr->chname,chptr->creationtime,
+            chptr->members, CHFL_CHANOWNER, 'q');
+        if (modebuf[1] || *parabuf)
+          sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
+              parabuf, chptr->creationtime);
+
+        *parabuf = '\0';
+        *modebuf = '+';
+        modebuf[1] = '\0';
+        (void)send_mode_list(cptr, chptr->chname,chptr->creationtime,
+            chptr->members, CHFL_CHANPROT, 'a');
+        if (modebuf[1] || *parabuf)
+          sendmodeto_one(cptr, me.name, chptr->chname, modebuf,
+              parabuf, chptr->creationtime);
+
+
+
+
+}
+/*********/
+
+/*
+ * m_samode
+ * parv[0] = sender
+ * parv[1] = channel
+ * parv[2] = modes
+ * -taz
+ */
+int    m_samode(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       static char tmp[MODEBUFLEN];
+       int badop, sendts;
+       aChannel *chptr;
+
+       if (check_registered(cptr))
+               return 0;
+
+       if (!IsPrivileged(cptr) || !IsSAdmin(sptr))
+       {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+       }
+
+       if (parc > 2)
+       {
+               chptr = find_channel(parv[1], NullChn);
+               if (chptr == NullChn)
+                       return 0;
+       }
+       else
+       {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "MODE");
+               return 0;
+       }
+       opermode = 0; 
+       (void)do_mode(chptr, cptr, sptr, parc - 2, parv + 2, 0, 1);
+
+       return 0;
+
+}
+
+/*
+ * m_mode -- written by binary (garryb@binary.islesfan.net)
+ *     Completely rewrote it.  The old mode command was 820 lines of ICKY
+ * coding, which is a complete waste, because I wrote it in 570 lines of
+ * *decent* coding.  This is also easier to read, change, and fine-tune.  Plus,
+ * everything isn't scattered; everything's grouped where it should be.
+ *
+ * parv[0] - sender
+ * parv[1] - channel
+ */
+int    m_mode(cptr, sptr, parc, parv)
+aClient *cptr;
+aClient *sptr;
+int    parc;
+char   *parv[];
+{
+       static char tmp[MODEBUFLEN];
+       static char mode_buf[MODEBUFLEN], parabuf[MODEBUFLEN];
+       char    tmp1[1024];
+//     int     opermode = 0;
+       
+       long unsigned timestamp, sendts;
+       Ban *ban; Link *l;
+       aChannel *chptr;
+
+       if (check_registered(sptr))
+               return 0;
+
+       /* Now, try to find the channel in question */
+       if (parc > 1)
+       {
+               chptr = find_channel(parv[1], NullChn);
+               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 (MyConnect(sptr))
+               clean_channelname(parv[1]);
+       if (check_channelmask(sptr, cptr, parv[1]))
+               return 0;
+
+       if (parc < 3)
+       {
+               *mode_buf = *parabuf = '\0';
+               mode_buf[1] = '\0';
+               channel_modes(sptr, mode_buf, parabuf, chptr);
+               sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0],
+                          chptr->chname, mode_buf, parabuf);
+               sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0],
+                                chptr->chname, chptr->creationtime);
+               return 0;
+       }
+
+       if (IsPerson(sptr) && parc<4 && ((*parv[2]=='b' && parv[2][1]=='\0')
+               || (parv[2][1]=='b' && parv[2][2] == '\0' && (*parv[2] == '+'
+               || *parv[2] == '-'))))
+       {
+               if (!IsMember(sptr, chptr))
+                       return 0;
+               /* send ban list */
+               for (ban=chptr->banlist; ban; ban=ban->next)
+                       sendto_one(sptr, rpl_str(RPL_BANLIST), me.name,
+                               sptr->name, chptr->chname, ban->banstr,
+                               ban->who, ban->when);
+               sendto_one(cptr,
+                       rpl_str(RPL_ENDOFBANLIST), me.name, sptr->name,
+                       chptr->chname);
+               return 0;
+       }
+
+       if (IsPerson(sptr) && parc<4 && ((*parv[2]=='e' && parv[2][1]=='\0')
+               || (parv[2][1]=='e' && parv[2][2] == '\0' && (*parv[2] == '+'
+               || *parv[2] == '-'))))
+       {
+               if (!IsMember(sptr, chptr))
+                       return 0;
+               /* send exban list */
+               for (ban=chptr->exlist; ban; ban=ban->next)
+                       sendto_one(sptr, rpl_str(RPL_EXLIST), me.name,
+                               sptr->name, chptr->chname, ban->banstr,
+                               ban->who, ban->when);
+               sendto_one(cptr,
+                       rpl_str(RPL_ENDOFEXLIST), me.name, sptr->name,
+                       chptr->chname);
+               return 0;
+       }
+       if (IsPerson(sptr) && parc<4 && ((*parv[2]=='I' && parv[2][1]=='\0')
+               || (parv[2][1]=='I' && parv[2][2] == '\0' && (*parv[2] == '+'
+               || *parv[2] == '-'))))
+       {
+               if (!IsMember(sptr, chptr))
+                       return 0;
+               sendto_one(sptr, rpl_str(RPL_ENDOFINVITELIST), me.name, sptr->name, chptr->chname);
+               return 0;
+       }
+       opermode = 0;
+       /* opermode stuff --sts */
+       if (IsPerson(sptr) && !IsULine(cptr, sptr) && !is_chan_op(sptr, chptr))
+               if (IsOper(sptr)) {
+                       sendts = 0;
+                       opermode = 1;
+                       goto aftercheck;
+               }
+/*-------*/
+
+
+       if (is_half_op(sptr, chptr)) {
+               opermode = 2;
+               goto aftercheck;
+       }
+       if (IsPerson(sptr) && !IsULine(cptr, sptr) && !is_chan_op(sptr, chptr)
+               && !is_half_op(sptr, chptr)
+               && (cptr == sptr || !IsSAdmin(sptr) || !IsOper(sptr)))
+       {       
+               if (cptr == sptr)
+               {
+                       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+                               me.name, parv[0], chptr->chname);
+                       return 0;
+               }
+               sendto_one(cptr, ":%s MODE %s -oh %s %s 0",
+                       me.name, chptr->chname, parv[0], parv[0]);
+                       /* Tell the other server that the user is
+                        * de-opped.  Fix op desyncs. */
+               bounce_mode(chptr, cptr, parc - 2, parv + 2);
+               return 0;
+       }
+       
+       if (IsServer(sptr) && (sendts = atoi(parv[parc-1]))
+               && !IsULine(cptr,sptr) && chptr->creationtime
+               && sendts > chptr->creationtime)
+       {
+               if (!(*parv[2] == '&')) /* & denotes a bounce */
+               {
+            /* !!! */
+                       sendto_umode(UMODE_EYES, "*** TS bounce for %s - %lu(ours) %lu(theirs)",
+                                chptr->chname, chptr->creationtime, sendts);
+                       bounce_mode(chptr, cptr, parc - 2, parv + 2);
+                       return 0;
+               }
+               /* other server will resync soon enough... */
+       }
+       if (IsServer(sptr) && !sendts && *parv[parc - 1] != '0')
+               sendts = -1;
+       if (IsServer(sptr) && sendts != -1)
+               parc--; /* server supplied a time stamp, remove it now */
+
+aftercheck:
+/*     if (IsPerson(sptr) && IsOper(sptr)) {
+               if (!is_chan_op(sptr, chptr)) {
+                       if (MyClient(sptr) && !IsULine(cptr, cptr))
+                               sendto_umode(UMODE_EYES, "*** OperMode [IRCop: %s] - [Channel: %s] - [Mode: %s %s]",
+                                  sptr->name, chptr->chname, mode_buf, parabuf);
+                       sendts = 0;
+               }
+       }       
+*/
+       /* Filter out the unprivileged FIRST. *
+        * Now, we can actually do the mode.  */
+
+       (void)do_mode(chptr, cptr, sptr, parc - 2, parv + 2, sendts, 0);
+        
+       return 0;
+}
+
+/* bounce_mode -- written by binary
+ *     User or server is NOT authorized to change the mode.  This takes care
+ * of making the bounce string and bounce it.  Because of the 1 for the bounce
+ * param (last param) of the calls to set_mode and make_mode_str, it will not
+ * set the mode, but create the bounce string.
+ */
+void   bounce_mode(chptr, cptr, parc, parv)
+aChannel       *chptr;
+aClient                *cptr;
+int            parc;
+char           *parv[];
+{
+       char    pvar[MAXMODEPARAMS][MODEBUFLEN+3];
+       int     pcount;
+       long    oldm, oldl;
+       char    mode_buf[MODEBUFLEN], parabuf[MODEBUFLEN];
+       
+       oldm = chptr->mode.mode;
+       oldl = chptr->mode.limit;
+       set_mode(chptr, cptr, parc, parv, &pcount, pvar, 1);
+       make_mode_str(chptr, oldm, oldl, pcount, pvar, mode_buf,
+               parabuf, 1);
+       
+       sendto_one(cptr, ":%s MODE %s &%s %s %lu", me.name, chptr->chname,
+               mode_buf, parabuf, chptr->creationtime);
+       /* the '&' denotes a bounce so servers won't bounce a bounce */
+}
+
+/* do_mode -- written by binary
+ *     User or server is authorized to do the mode.  This takes care of
+ * setting the mode and relaying it to other users and servers.
+ */
+void   do_mode(chptr, cptr, sptr, parc, parv, sendts, samode)
+aChannel       *chptr;
+aClient                *cptr, *sptr;
+int            parc, sendts, samode;
+char           *parv[];
+{
+       char    pvar[MAXMODEPARAMS][MODEBUFLEN+3];
+       int     pcount;
+       long    oldm, oldl;
+       char    tschange = 0, isbounce = 0; /* fwd'ing bounce */
+       char    mode_buf[MODEBUFLEN], parabuf[MODEBUFLEN];
+
+       if (**parv == '&')
+               isbounce = 1;
+       oldm = chptr->mode.mode;
+       oldl = chptr->mode.limit;
+
+       set_mode(chptr, sptr, parc, parv, &pcount, pvar, 0);
+       make_mode_str(chptr, oldm, oldl, pcount, pvar, mode_buf,
+               parabuf, 0);
+
+       if (IsServer(sptr))
+       {
+               if (sendts > 0)
+               {
+                       if (!chptr->creationtime || sendts < chptr->creationtime)
+                       {
+                               tschange = 1;
+                               if (chptr->creationtime != 0)
+                                       sendto_umode(UMODE_EYES, "*** TS fix for %s - %lu(ours) %lu(theirs)",
+                                       chptr->chname, chptr->creationtime, sendts);                            
+                               chptr->creationtime = sendts;
+                               /* new chan or our timestamp is wrong */
+                               /* now works for double-bounce prevention */
+
+                       }
+                       if (sendts > chptr->creationtime && chptr->creationtime)
+                       {
+                               /* theirs is wrong but we let it pass anyway */
+                               sendts = chptr->creationtime;
+                               sendto_one(cptr, ":%s MODE %s + %lu", me.name,
+                                       chptr->chname, chptr->creationtime);
+                       }
+               }
+               if (sendts == -1 && chptr->creationtime)
+                       sendts = chptr->creationtime;
+       }
+       if (*mode_buf == '\0' || (*(mode_buf+1) == '\0' && (*mode_buf == '+' ||
+                       *mode_buf == '-')))
+       {
+               if (tschange || isbounce) /* relay bounce time changes */
+                       sendto_serv_butone(cptr, ":%s MODE %s %s+ %lu", me.name,
+                               chptr->chname, isbounce ? "&" : "",
+                               chptr->creationtime);
+               return; /* nothing to send */
+       }
+       /* opermode for twimodesystem --sts*/
+       if (opermode == 1) {
+               if (MyClient(sptr))
+                       sendto_umode(UMODE_EYES, "*** OperMode [IRCop: %s] - [Channel: %s] - [Mode: %s %s]",
+                                  sptr->name, chptr->chname, mode_buf, parabuf);
+               sendts = 0;
+       }
+       
+    if (IsPerson(sptr) && samode && MyClient(sptr))
+    {
+               sendto_serv_butone(NULL,
+                       ":%s GLOBOPS :%s used SAMODE %s (%s %s)",
+                       me.name, sptr->name, chptr->chname, mode_buf, parabuf);
+               sendto_failops_whoare_opers(
+                       "from %s: %s used SAMODE %s (%s %s)", 
+                       me.name, sptr->name, chptr->chname, mode_buf, parabuf);
+               sptr = &me;
+               sendts = 0;
+       }
+       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s",
+                       sptr->name, chptr->chname, mode_buf, parabuf);
+               if (IsServer(sptr) && sendts != -1)
+               sendto_serv_butone(cptr, ":%s MODE %s %s%s %s %lu",
+                       sptr->name, chptr->chname, isbounce ? "&" : "",
+                       mode_buf, parabuf, sendts);
+        else
+               sendto_serv_butone(cptr, ":%s MODE %s %s%s %s NoTS",
+                       sptr->name, chptr->chname, isbounce ? "&" : "",
+                       mode_buf, parabuf);
+               /* tell them it's not a timestamp, in case the last param
+               ** is a number. */
+}
+/* make_mode_str -- written by binary
+ *     Reconstructs the mode string, to make it look clean.  mode_buf will
+ *  contain the +x-y stuff, and the parabuf will contain the parameters.
+ *  If bounce is set to 1, it will make the string it needs for a bounce.
+ */
+void   make_mode_str(chptr, oldm, oldl, pcount, pvar, mode_buf, parabuf, bounce)
+aChannel       *chptr;
+int    pcount;
+long   oldm, oldl;
+char pvar[MAXMODEPARAMS][MODEBUFLEN+3], *mode_buf, *parabuf, bounce;
+{
+
+       char    *x = mode_buf, tmpbuf[MODEBUFLEN], *tmpstr, foo;
+       // int  *ip;
+       aCtab *tab = &cFlagTab[0];
+       int     what, cnt, z;
+       
+       what = 0;
+       
+       *tmpbuf = '\0';
+       *mode_buf = '\0';
+       *parabuf = '\0';
+       what = 0;
+       /* + param-less modes */
+       tab = &cFlagTab[0];
+       while (tab->mode != 0x0) {
+               if (chptr->mode.mode & tab->mode) {
+                       if (!(oldm & tab->mode)) {
+                               if (what != MODE_ADD)
+                               {
+                                       *x++ = bounce ? '-' : '+';
+                                       what = MODE_ADD;
+                               }       
+                               *x++ = tab->flag;
+                       }
+               }
+               tab++;
+       }
+       
+       *x = '\0';
+/* + param-less modes */
+       tab = &cFlagTab[0];
+       while (tab->mode != 0x0) {
+               if (!(chptr->mode.mode & tab->mode)) {
+                       if (oldm & tab->mode) {
+                               if (what != MODE_DEL)
+                               {
+                                       *x++ = bounce ? '+' : '-';
+                                       what = MODE_DEL;
+                               }       
+                               *x++ = tab->flag;
+                       }
+               }
+               tab++;
+       }
+       
+       *x = '\0';
+       /* reconstruct bkov chain */
+       for (cnt = 0; cnt < pcount; cnt++)
+       {
+               if ((*(pvar[cnt]) == '+') && what != MODE_ADD)
+               {
+                       *x++ = bounce ? '-' : '+';
+                       what = MODE_ADD;
+               }
+               if ((*(pvar[cnt]) == '-') && what != MODE_DEL)
+               {
+                       *x++ = bounce ? '+' : '-';
+                       what = MODE_DEL;
+               }
+               *x++ = *(pvar[cnt] + 1);
+               tmpstr = &pvar[cnt][2];
+               strncat(parabuf, tmpstr, MODEBUFLEN - 1);
+               parabuf[MODEBUFLEN-1] = '\0';
+               z = strlen(parabuf);
+               parabuf[z] = ' ';       /* add a space */
+               parabuf[z+1] = '\0';
+       }
+       /* user limit */
+       if (chptr->mode.limit != oldl)
+       {
+               if ((!bounce && chptr->mode.limit == 0) ||
+                       (bounce && chptr->mode.limit != 0))
+               {
+                       if (what != MODE_DEL)
+                       {
+                               *x++ = '-';
+                               what = MODE_DEL;
+                       }
+                       if (bounce)
+                               chptr->mode.limit = 0; /* set it back */
+                       *x++ = 'l';
+               }
+               else
+               {
+                       if (what != MODE_ADD)
+                       {
+                               *x++ = '+';
+                               what = MODE_ADD;
+                       }
+                       *x++ = 'l';
+                       if (bounce)
+                               chptr->mode.limit = oldl; /* set it back */
+                       sprintf(parabuf, "%s%d", parabuf, chptr->mode.limit);
+               }
+       }
+       if (bounce)
+               chptr->mode.mode = oldm;
+       z = strlen(parabuf);
+       if (parabuf[z-1] == ' ')
+               parabuf[z-1] = '\0';
+       *x = '\0';
+       if (*mode_buf == '\0')
+       {
+               *mode_buf = '+';
+               mode_buf++;
+               *mode_buf = '\0';
+               /* Don't send empty lines. */
+       }
+       return;
+}
+
+
+/* do_mode_char
+ *  processes one mode character
+ *  returns 1 if it ate up a param, otherwise 0
+ *     written by binary
+ *  modified for Unreal by stskeeps..
+ */
+
+int do_mode_char(chptr, modetype, modechar, param, what, cptr, pcount, pvar,
+       bounce)
+char *param, modechar, pvar[MAXMODEPARAMS][MODEBUFLEN+3], bounce;
+u_int what;
+long modetype;
+u_int *pcount;
+aClient *cptr;
+aChannel       *chptr;
+
+{
+       aCtab   *tab = &cFlagTab[0];
+       
+
+       int retval = 0;
+       Link    *member;
+       aClient *who;
+       unsigned int tmp = 0;
+       char tmpbuf[512], *tmpstr;
+       char tc; /* */
+       int chasing, x;
+       int xxi, xyi, xzi;
+       char *xxx;
+       char *xp;
+       
+       chasing = 0;
+       if (opermode == 2 && !is_chan_op(cptr, chptr)) {
+        /* Ugly halfop hack --sts 
+           - this allows halfops to do +b +e +v and so on */
+         if (Halfop_mode(modetype) == FALSE) {
+                       while (tab->mode != 0x0) {
+                               if (tab->mode == modetype) {
+                                       sendto_one(cptr, err_str(ERR_NOTFORHALFOPS),
+                                               me.name,
+                                               cptr->name,                                             
+                                               tab->flag);
+                               }
+                               tab++;
+                       }
+                       return(0);
+         }
+       }
+       switch(modetype)
+       {
+               case MODE_OPERONLY:
+                       if (!IsAnOper(cptr) && !IsServer(cptr) && !IsULine(cptr,cptr)) {
+                               sendto_one(cptr, ":%s NOTICE %s :*** Only IRCops can set that mode", me.name, cptr->name);
+                               break;
+                       }
+                       goto setthephuckingmode;
+               case MODE_ADMONLY:
+                       if (!IsSkoAdmin(cptr) && !IsServer(cptr) && !IsULine(cptr,cptr)) {
+                               sendto_one(cptr, ":%s NOTICE %s :*** Only admins can set that mode", me.name, cptr->name);
+                               break;
+                       }
+                       goto setthephuckingmode;
+               case MODE_RGSTR:
+                       if (!IsServer(cptr) && !IsULine(cptr,cptr))
+                               break;
+                       goto setthephuckingmode;
+               case MODE_NOHIDING:
+                       if (!IsSkoAdmin(cptr) && !IsServer(cptr) && !IsULine(cptr,cptr))
+                       {
+                               sendto_one(cptr, ":%s NOTICE %s :*** Only admins can set that mode", me.name, cptr->name);
+                               break;
+                       }
+                       goto setthephuckingmode;
+               case MODE_SECRET:
+               case MODE_PRIVATE:
+               case MODE_MODERATED:
+               case MODE_TOPICLIMIT:
+               case MODE_NOPRIVMSGS:
+               case MODE_INVITEONLY:
+               case MODE_RGSTRONLY:
+               case MODE_NOCOLOR:
+               case MODE_NOKICKS:
+               case MODE_STRIP:
+               case MODE_NOKNOCK:
+               case MODE_NOINVITE:
+setthephuckingmode:
+                       /* +sp bugfix.. */
+                       if (modetype == MODE_SECRET && (chptr->mode.mode & MODE_PRIVATE))
+                               chptr->mode.mode &= ~MODE_PRIVATE;
+                       if (modetype == MODE_PRIVATE && (chptr->mode.mode & MODE_SECRET))
+                               chptr->mode.mode &= ~MODE_SECRET;
+                       if (modetype == MODE_NOCOLOR && (chptr->mode.mode & MODE_STRIP))
+                               chptr->mode.mode &= ~MODE_STRIP;
+                       if (modetype == MODE_STRIP && (chptr->mode.mode & MODE_NOCOLOR))
+                               chptr->mode.mode &= ~MODE_NOCOLOR;
+                       retval = 0;
+                       if (what == MODE_ADD)
+                               chptr->mode.mode |= modetype;
+                       else
+                               chptr->mode.mode &= ~modetype;
+                       break;
+
+/* do pro-opping here (popping) */
+               case MODE_CHANOWNER:
+            if (!IsULine(cptr,cptr) && !IsServer(cptr) && !IsNetAdmin(cptr) &&
+                   !IsCoAdmin(cptr) && !IsTechAdmin(cptr) && !is_chanowner(cptr, chptr)) {
+                    sendto_one(cptr, err_str(ERR_ONLYSERVERSCANCHANGE),
+                              me.name, cptr->name, chptr->chname);
+                                       break;          
+                       }
+               case MODE_CHANPROT:
+                  if (!IsULine(cptr,cptr) && !IsServer(cptr) && !IsNetAdmin(cptr) &&
+                       !IsCoAdmin(cptr) && !IsTechAdmin(cptr) && !is_chanowner(cptr, chptr)) {
+                        sendto_one(cptr, ":%s NOTICE %s :*** Protected users can only be set by the channel owner.",
+                        me.name, cptr->name);
+                       break;
+                       }                                                                                                                                                
+       
+               case MODE_HALFOP:
+               case MODE_CHANOP:
+               case MODE_VOICE:
+                       switch (modetype)
+                       {
+                               case MODE_CHANOWNER: xxx = "deown"; break;
+                               case MODE_CHANPROT: xxx = "deprot"; break;
+                               case MODE_HALFOP: xxx = "dehalfop"; break;
+                               case MODE_CHANOP: xxx = "deop"; break;
+                               case MODE_VOICE: xxx ="devoice"; break;
+                               default: xxx = "whatthefuckisthatmode?";
+                       }
+                       if (!param || *pcount >= MAXMODEPARAMS)
+                       {
+                               retval = 0;
+                               break;
+                       }
+                       retval = 1;
+                       if (!(who = find_chasing(cptr, param, &chasing)))
+                               break;
+                       if (!(member = find_user_link(chptr->members, who)))
+                       {
+                               sendto_one(cptr, err_str(ERR_USERNOTINCHANNEL),
+                                          me.name, cptr->name,
+                                          who->name, chptr->chname);
+                               break;
+                       }
+                       /* we make the rules, we bend the rules */
+                       if (IsServer(cptr) || IsULine(cptr, cptr))
+                               goto breaktherules;
+                                       
+                       if (is_chanowner(member->value.cptr, chptr) && member->value.cptr != cptr && !is_chanowner(cptr, chptr) && !IsServer(cptr) && !IsULine(cptr,cptr) && (what == MODE_DEL)) {
+                               if (MyClient(cptr)) {
+                                       sendto_one(cptr, ":%s NOTICE %s :*** You cannot %s because %s is %s channel owner (+q)",
+                                               me.name, cptr->name, xxx, member->value.cptr->name, chptr->chname);
+                               }
+                               break;
+                       }
+                       if (is_chanprot(member->value.cptr, chptr) && member->value.cptr != cptr && !is_chanowner(cptr, chptr) && !IsServer(cptr) && modetype != MODE_CHANOWNER && (what==MODE_DEL)) {
+                               if (MyClient(cptr)) {
+                                       sendto_one(cptr, ":%s NOTICE %s :*** You cannot %s because %s is %s protected user (+a)",
+                                                         me.name, cptr->name,         xxx,         member->value.cptr->name, chptr->chname);
+                               }
+                               break;
+                       }
+breaktherules:
+                       tmp = member->flags;
+                       if (what == MODE_ADD)
+                               member->flags |= modetype;
+                       else
+                               member->flags &= ~modetype;
+                       if (tmp == member->flags &&
+                                       (bounce || !IsULine(cptr,cptr)))
+                               break;
+                       /* It's easier to undo the mode here instead of later
+                        * when you call make_mode_str for a bounce string.
+                        * Why set it if it will be instantly removed?
+                        * Besides, pvar keeps a log of it. */
+                       if (bounce)
+                               member->flags = tmp;
+                       if (modetype == MODE_CHANOWNER)
+                               tc = 'q';
+                       if (modetype == MODE_CHANPROT)
+                               tc = 'a';
+                       if (modetype == MODE_CHANOP)
+                               tc = 'o';
+                       if (modetype == MODE_HALFOP)
+                               tc = 'h';
+                       if (modetype == MODE_VOICE)
+                               tc = 'v';
+                                       
+                       (void)sprintf(pvar[*pcount], "%c%c%s",
+                               what == MODE_ADD ? '+' : '-',
+                               tc,
+                               who->name);
+
+                       (*pcount)++;
+                       break;
+               case MODE_LIMIT:
+                       if (what == MODE_ADD)
+                       {
+                               if (!param)
+                               {
+                                       retval = 0;
+                                       break;
+                               }
+                               retval = 1;
+                               tmp = atoi(param);
+                               if (chptr->mode.limit == tmp)
+                                       break;
+                               chptr->mode.limit = tmp;
+                       }
+                       else
+                       {
+                               retval = 0;
+                               if (!chptr->mode.limit)
+                                       break;
+                               chptr->mode.limit = 0;
+                       }
+                       break;
+               case MODE_KEY:
+                       if (!param || *pcount >= MAXMODEPARAMS)
+                       {
+                               retval = 0;
+                               break;
+                       }
+                       retval = 1;
+                       for (x = 0; x < *pcount; x++)
+                       {
+                               if (pvar[x][1] == 'k')
+                               {       /* don't allow user to change key
+                                        * more than once per command. */
+                                       retval = 0;
+                                       break;
+                               }
+                       }
+                       if (retval == 0) /* you can't break a case from loop */
+                               break;
+                       if (what == MODE_ADD)
+                       {
+                               if (!bounce) /* don't do the mode at all. */
+                                       strncpyzt(chptr->mode.key, param,
+                                               sizeof(chptr->mode.key));
+                               tmpstr = param;
+                       }
+                       else
+                       {
+                               if (!*chptr->mode.key)
+                                       break; /* no change */
+                               strncpyzt(tmpbuf, chptr->mode.key,
+                                       sizeof(tmpbuf));
+                               tmpstr = tmpbuf;
+                               if (!bounce)
+                                       strcpy(chptr->mode.key, "");
+                       }
+                       retval = 1;
+                       
+                       (void)sprintf(pvar[*pcount], "%ck%s",
+                               what == MODE_ADD ? '+' : '-', tmpstr);
+                       (*pcount)++;                            
+                       break;
+               
+               case MODE_BAN:
+                       if (!param || *pcount >= MAXMODEPARAMS)
+                       {
+                               retval = 0;
+                               break;
+                       }
+                       retval = 1;
+                       tmpstr = pretty_mask(param);
+                       /* For bounce, we don't really need to worry whether
+                        * or not it exists on our server.  We'll just always
+                        * bounce it. */
+                       if (!bounce &&
+                          ((what==MODE_ADD && add_banid(cptr, chptr, tmpstr))
+                          || (what == MODE_DEL && del_banid(chptr, tmpstr))))
+                               break; /* already exists */
+                       (void)sprintf(pvar[*pcount], "%cb%s",
+                               what == MODE_ADD ? '+' : '-', tmpstr);
+                       (*pcount)++;                            
+                       break;
+               case MODE_EXCEPT:
+                       if (!param || *pcount >= MAXMODEPARAMS)
+                       {
+                               retval = 0;
+                               break;
+                       }
+                       retval = 1;
+                       tmpstr = pretty_mask(param);
+                       /* For bounce, we don't really need to worry whether
+                        * or not it exists on our server.  We'll just always
+                        * bounce it. */
+                       if (!bounce &&
+                          ((what==MODE_ADD && add_exbanid(cptr, chptr, tmpstr))
+                          || (what == MODE_DEL && del_exbanid(chptr, tmpstr))))
+                               break; /* already exists */
+                       (void)sprintf(pvar[*pcount], "%ce%s",
+                               what == MODE_ADD ? '+' : '-', tmpstr);
+                       (*pcount)++;                            
+                       break;
+               case MODE_LINK:
+                       if (IsULine(cptr, cptr) || IsServer(cptr)) {
+                               goto linkok;
+                       }
+#ifndef OPSLINK
+                       if (!IsNetAdmin(cptr) && !IsCoAdmin(cptr) && !IsTechAdmin(cptr) && !is_chanowner(cptr,chptr))
+                       {
+                               sendto_one(cptr, ":%s NOTICE %s :*** Channel mode +L can only be set by the channel owner", me.name, cptr->name);                               
+                               break;
+                       }
+#endif
+                       linkok:
+                       if (!chptr->mode.limit && what == MODE_ADD) {
+                               sendto_one(cptr, ":%s NOTICE %s :*** Channel mode +l <max> is requried for +L to be set", me.name, cptr->name);
+                               break;
+                       }
+                       retval = 1;
+                       for (x = 0; x < *pcount; x++)
+                       {
+                               if (pvar[x][1] == 'L')
+                               {       /* don't allow user to change link
+                                        * more than once per command. */
+                                       retval = 0;
+                                       break;
+                               }
+                       }
+                       if (retval == 0) /* you can't break a case from loop */
+                               break;
+                       if (what == MODE_ADD)
+                       {
+                               if (!param || *pcount >= MAXMODEPARAMS)
+                               {
+                                       retval = 0;
+                                       break;
+                               }
+
+                               if (!bounce) /* don't do the mode at all. */
+                                       strncpyzt(chptr->mode.link, param,
+                                               sizeof(chptr->mode.link));
+                               tmpstr = param;
+                       }
+                       else
+                       {
+                               if (!*chptr->mode.link)
+                                       break; /* no change */
+                               strncpyzt(tmpbuf, chptr->mode.link,
+                                       sizeof(tmpbuf));
+                               tmpstr = tmpbuf;
+                               if (!bounce)
+                                       strcpy(chptr->mode.link, "");
+                       }
+                       retval = 1;
+                       
+                       (void)sprintf(pvar[*pcount], "%cL%s",
+                               what == MODE_ADD ? '+' : '-', tmpstr);
+                       (*pcount)++;                            
+                       break;
+               case MODE_FLOODLIMIT:
+                       retval = 1;
+                       for (x = 0; x < *pcount; x++)
+                       {
+                               if (pvar[x][1] == 'f')
+                               {       /* don't allow user to change flood
+                                        * more than once per command. */
+                                       retval = 0;
+                                       break;
+                               }
+                       }
+                       if (retval == 0) /* you can't break a case from loop */
+                               break;
+                       if (what == MODE_ADD)
+                       {
+                               if (!bounce) /* don't do the mode at all. */
+                               {
+                                       if (!param || *pcount >= MAXMODEPARAMS)
+                                       {
+                                               retval = 0;
+                                               break;
+                                       }
+
+                                       /* like 1:1 and if its less than 3 chars then ahem.. */
+                                       if (strlen(param) < 3)
+                                       {
+                                               break;
+                                       }
+                                       /* may not contain other chars 
+                                          than 0123456789: & NULL */
+                                       for (xp = param; *xp; xp++)
+                                       {
+                                               /* fast alpha check */
+                                               if ( (*xp < '0') 
+                                                 && (*xp > '9')
+                                                 && (*xp != '\0')
+                                                 && (*xp != ':')
+                                                 && (*xp == '*' && xp != param))
+                                      
+                                                       break;
+                                       }
+                                       /* haven't got a : .. oh well */
+                                       if (!strchr(param, ':'))
+                                       {
+                                               break;
+                                       }
+                                       /* got multiple :'s .. omg */
+                                       if (strchr(param, ':') != strrchr(param, ':'))
+                                       {
+                                               break;
+                                       }
+                                       if (*param == '*' )
+                                       {
+                                               xzi = 1;
+                                               chptr->mode.kmode = 1;
+                                       }
+                                        else
+                                       {
+                                               xzi = 0;
+                                               
+                                            chptr->mode.kmode = 0;
+                                       }
+                                       xp = index(param, ':');
+                                       *xp = '\0';
+                                       xxi = atoi((*param == '*' ? (param + 1) : param));
+                                       xp++;
+                                       xyi = atoi(xp);
+                                       xp--;
+                                       *xp = ':';
+                                       if ((xxi == 0) || (xyi == 0))
+                                               break;
+                                       if ((chptr->mode.msgs == xxi) && (chptr->mode.per == xyi) && (chptr->mode.kmode == xzi))
+                                               break;                                  chptr->mode.msgs = xxi;
+                                       chptr->mode.per = xyi;
+                               }
+                               tmpstr = param;
+                               retval = 1;
+                       }
+                       else
+                       {
+                               if (!chptr->mode.msgs || !chptr->mode.per)
+                                       break; /* no change */
+                               sprintf(tmpbuf, (chptr->mode.kmode > 0 ? "*%i:%i" : "%i:%i"), chptr->mode.msgs, chptr->mode.per);
+                               tmpstr = tmpbuf;
+                               if (!bounce)
+                               {
+                                       chptr->mode.msgs = chptr->mode.per = chptr->mode.kmode =  0;
+                               }
+                               retval = 0;
+                       }
+                       
+                       (void)sprintf(pvar[*pcount], "%cf%s",
+                               what == MODE_ADD ? '+' : '-', tmpstr);
+                       (*pcount)++;                            
+                       break;
+#ifdef _WIN32
+               default: ; 
+#else
+               default:
+#endif
+       }
+       return(retval); 
+}
+
+/*
+ * ListBits(bitvalue, bitlength);
+ * written by Stskeeps
+*/
+char   *ListBits(long bits, long length) {
+       char    *bitstr, *p;
+       long    l,x,y;
+        y = 1;
+       bitstr = (char *) MyMalloc(length + 1);
+        p = bitstr;
+       for (l = 1; l <= length; l++) {
+               if (bits & y)
+                       *p = '1';
+               else
+                       *p = '0';
+                p++;
+               y = y + y;
+       }
+       *p = '\0';
+        return (bitstr);
+}
+
+
+/* set_mode
+ *     written by binary
+ */
+void set_mode(chptr, cptr, parc, parv, pcount, pvar, bounce)
+aChannel       *chptr;
+aClient        *cptr;
+int    parc;
+u_int  *pcount;
+char   bounce;
+char   *parv[], pvar[MAXMODEPARAMS][MODEBUFLEN+3];
+// long    opermode;
+{
+       Reg1 char *curchr;
+       u_int   what = MODE_ADD;
+       long    modetype;
+       int paracount;
+       char *tmpo;
+       int *ip, xid;
+       aCtab *tab = &cFlagTab[0];
+       aCtab foundat;
+       int     found = 0;
+       paracount = 1;
+       *pcount = 0;
+       for (curchr = parv[0]; *curchr; curchr++)
+       {
+               switch(*curchr)
+               {
+                       case '+':
+                               what = MODE_ADD;
+                               break;
+                       case '-':
+                               what = MODE_DEL;
+                               break;
+                       case '^':
+                               tmpo = (char *) ListBits(chptr->mode.mode, 64);
+                               sendto_one(cptr, ":%s NOTICE %s :*** %s mode is %li (0x%lx) [%s]",
+                                   me.name,
+                                   cptr->name,
+                                   chptr->chname,
+                                   chptr->mode.mode,
+                                   chptr->mode.mode,
+                                   tmpo);
+                               MyFree(tmpo);
+                               break;
+
+                       case 'x':
+                               if (MyClient(cptr))
+                               {
+                                       sendto_one(cptr, ":%s NOTICE %s :*** Mode not set - Please do not use mode +x as this is now named +c instead (Colorblock)",
+                                           me.name,
+                                           cptr->name);
+                                       break;
+                               }
+                                else
+                               {
+                                       /* compatiblity */
+                                       *curchr = 'c';
+                               }
+                               goto jumpdammit;
+                       case 'I':
+                               if (MyClient(cptr))
+                               {
+                                       break;
+                               }
+                                else
+                               {
+                                       /* compatiblity */
+                                       *curchr = 'V';
+                               }
+jumpdammit:                            
+                       default:
+                               found = 0;
+                               tab = &cFlagTab[0];                             while ((tab->mode != 0x0) && found == 0) {
+                                       if (tab->flag == *curchr) {
+                                               found = 1;
+                                               foundat = *tab;
+                                       }
+                                       tab++;
+                               }
+                               if (found == 1)
+                                       modetype = foundat.mode;
+                               if (found == 0)
+                                       modetype = 0;                           
+       
+                               if (modetype == 0)
+                               {
+                                       if (!MyClient(cptr))
+                                               break;
+                                           /* don't flood other servers */
+                                       sendto_one(cptr,
+                                               err_str(ERR_UNKNOWNMODE),
+                                               me.name, cptr->name, *curchr);
+                                       break;
+                               }
+                               if (parv[paracount] &&
+                                               strlen(parv[paracount]) >=
+                                               MODEBUFLEN)
+                                       parv[paracount][MODEBUFLEN-1] = '\0';
+                               paracount += do_mode_char(chptr, modetype,
+                                       *curchr, parv[paracount], what, cptr,
+                                       pcount, pvar, bounce);
+                               break;
+               }
+       }
+}
+
+int DoesOp(modebuf)
+char *modebuf;
+{
+  modebuf--; /* Is it possible that a mode starts with o and not +o ? */
+  while (*++modebuf) if (*modebuf == 'h' || *modebuf=='o' || *modebuf=='v' || *modebuf=='q') return(1);
+  return 0;
+}
+
+int sendmodeto_one(cptr, from, name, mode, param, creationtime)
+Reg2 aClient *cptr;
+char *from,*name,*mode,*param;
+time_t creationtime;
+{
+       if ((IsServer(cptr) && DoesOp(mode) && creationtime) ||
+               IsULine(cptr,cptr))
+         sendto_one(cptr,":%s %s %s %s %s %lu", from,
+             (IsToken(cptr)?TOK_MODE:MSG_MODE), name, mode, param,
+             creationtime);
+       else
+         sendto_one(cptr,":%s %s %s %s %s", from,
+             (IsToken(cptr)?TOK_MODE:MSG_MODE), name, mode, param);
+}
+
+char *pretty_mask(mask)
+char *mask;
+{ Reg1 char *cp;
+  Reg2 char *user;
+  Reg3 char *host;
+
+  if ((user = index((cp = mask), '!'))) *user++ = '\0';
+  if ((host = rindex(user ? user : cp, '@')))
+  { *host++ = '\0';
+    if (!user) return make_nick_user_host(NULL, cp, host); }
+  else if (!user && index(cp, '.')) return make_nick_user_host(NULL, NULL, cp);
+  return make_nick_user_host(cp, user, host);
+}
+/* Now let _invited_ people join thru bans, +i and +l.
+ * Checking if an invite exist could be done only if a block exists,
+ * but I'm not too fancy of the complicated structure that'd cause,
+ * when optimization will hopefully take care of it. Most of the time
+ * a user won't have invites on him anyway. -Donwulff
+ */
+
+static int     can_join(cptr, sptr, chptr, key, link, parv)
+aClient        *cptr, *sptr;
+Reg2   aChannel *chptr;
+char   *key, *link;
+char   *parv[];
+{
+       Reg1    Link    *lp;
+       int             ib = 1;
+
+       /* 0 = noone 1 = IRCops 2 = Net Admins 3 =Net/Tech admins  (override) */
+
+       if ((chptr->mode.limit && chptr->users >= chptr->mode.limit)) {
+               if (chptr->mode.link) {
+                       if (*chptr->mode.link != '\0') {
+                               /* We are linked. */
+                               sendto_one(sptr, err_str(ERR_LINKCHANNEL), me.name, sptr->name,
+                               chptr->chname, chptr->mode.link);
+                               parv[0] = sptr->name;
+                               parv[1] = (chptr->mode.link);
+                               channel_link(cptr, sptr, 2, parv);                                              
+                               return -1;
+                       }
+               }
+               return (ERR_CHANNELISFULL);
+       }
+
+/*    if ((chptr->mode.mode & MODE_OPERONLY) && IsOper(sptr)) {
+       goto admok;
+    } */
+    if ((chptr->mode.mode & MODE_OPERONLY) && !IsOper(sptr)) {
+        return (ERR_OPERONLY);
+    }
+    if ((chptr->mode.mode & MODE_ADMONLY)) {
+                       if (!IsSkoAdmin(sptr))
+                       return (ERR_ADMONLY);
+       }
+               
+       if ((chptr->mode.mode & MODE_NOHIDING) && IsHiding(sptr))
+                    return (ERR_NOHIDING);
+
+       if ((IsOper(sptr) && !(chptr->mode.mode & MODE_ADMONLY))) {
+               return 0; /* may override */
+       }
+       if ((IsOper(sptr) && is_banned(cptr, sptr, chptr) && (chptr->mode.mode & MODE_OPERONLY)))
+               return (ERR_BANNEDFROMCHAN); /* banned as an ircop at a +O cannot join */
+
+/*     if (ib == 1)
+               if (IsOper(sptr))
+                       return 0;
+       else
+               if (ib == 2)
+                       if (IsNetAdmin(sptr))
+                               return 0;
+*/
+       switch(ib) {
+               case 1: if (IsOper(sptr))
+                       {
+                               return 0;
+                       }
+                               break;
+               case 2: if (IsNetAdmin(sptr))
+               {
+                       return 0;
+               }
+                               break;
+               case 3: if (IsNetAdmin(sptr) || IsTechAdmin(sptr)) return 0;
+                               break;
+               default: break;
+       }       
+    if ((chptr->mode.mode & MODE_RGSTRONLY) && !IsARegNick(sptr))
+               return (ERR_NEEDREGGEDNICK);
+               
+       if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key)))
+               return (ERR_BADCHANNELKEY);
+
+       for (lp = sptr->user->invited; lp; lp = lp->next)
+               if (lp->value.chptr == chptr)
+                       break;
+
+       if ((chptr->mode.mode & MODE_INVITEONLY) && !lp)
+               return (ERR_INVITEONLYCHAN);
+    
+       if ((chptr->mode.limit && chptr->users >= chptr->mode.limit))
+               return (ERR_CHANNELISFULL);
+
+       if (is_banned(sptr, sptr, chptr) && !lp)
+               return (ERR_BANNEDFROMCHAN);
+     
+
+       
+       return 0;
+}
+
+
+/*
+** Remove bells and commas from channel name
+*/
+
+void   clean_channelname(cn)
+char   *cn;
+{
+       Reg1    u_char  *ch = (u_char *)cn;
+
+
+       for (; *ch; ch++)
+               /* Don't allow any control chars, the space, the comma,
+                * or the "non-breaking space" in channel names.
+                * Might later be changed to a system where the list of
+                * allowed/non-allowed chars for channels was a define
+                * or some such.
+                *   --Wizzu
+                */
+               if (*ch < 33 || *ch == ',' || *ch == 160)
+                   {
+                       *ch = '\0';
+                       return;
+                   }
+}
+
+/*
+** Return -1 if mask is present and doesnt match our server name.
+*/
+static int     check_channelmask(sptr, cptr, chname)
+aClient        *sptr, *cptr;
+char   *chname;
+{
+       Reg1    char    *s;
+
+       if (*chname == '&' && IsServer(cptr))
+               return -1;
+       s = rindex(chname, ':');
+       if (!s)
+               return 0;
+
+       s++;
+       if (match(s, me.name) || (IsServer(cptr) && match(s, cptr->name)))
+           {
+               if (MyClient(sptr))
+                       sendto_one(sptr, err_str(ERR_BADCHANMASK),
+                                  me.name, sptr->name, chname);
+               return -1;
+           }
+       return 0;
+}
+
+/*
+**  Get Channel block for i (and allocate a new channel
+**  block, if it didn't exists before).
+*/
+static aChannel *get_channel(cptr, chname, flag)
+aClient *cptr;
+char   *chname;
+int    flag;
+    {
+       Reg1    aChannel *chptr;
+       int     len;
+
+       if (BadPtr(chname))
+               return NULL;
+
+       len = strlen(chname);
+       if (MyClient(cptr) && len > CHANNELLEN)
+           {
+               len = CHANNELLEN;
+               *(chname+CHANNELLEN) = '\0';
+           }
+       if ((chptr = find_channel(chname, (aChannel *)NULL)))
+               return (chptr);
+       if (flag == CREATE)
+           {
+               chptr = (aChannel *)MyMalloc(sizeof(aChannel) + len);
+               bzero((char *)chptr, sizeof(aChannel));
+               strncpyzt(chptr->chname, chname, len+1);
+               if (channel)
+                       channel->prevch = chptr;
+               chptr->prevch = NULL;
+               chptr->nextch = channel;
+               chptr->creationtime = MyClient(cptr)?TStime():(time_t)0;
+               channel = chptr;
+               (void)add_to_channel_hash_table(chname, chptr);
+           }
+       return chptr;
+    }
+
+/*
+ * Slight changes in routine, now working somewhat symmetrical:
+ *   First try to remove the client & channel pair to avoid duplicates
+ *   Second check client & channel invite-list lengths and remove tail
+ *   Finally add new invite-links to both client and channel
+ * Should U-lined clients have higher limits?   -Donwulff
+ */
+
+static void    add_invite(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+       Reg1    Link    *inv, *tmp;
+
+       del_invite(cptr, chptr);
+       /*
+        * delete last link in chain if the list is max length
+        */
+       if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER)
+           {
+/*             This forgets the channel side of invitation     -Vesa
+               inv = cptr->user->invited;
+               cptr->user->invited = inv->next;
+               free_link(inv);
+*/
+               for (tmp = cptr->user->invited; tmp->next; tmp = tmp->next)
+                       ;
+               del_invite(cptr, tmp->value.chptr);
+           }
+       /* We get pissy over too many invites per channel as well now,
+        * since otherwise mass-inviters could take up some major
+        * resources -Donwulff
+        */
+       if (list_length(chptr->invites) >= MAXCHANNELSPERUSER) {
+               for (tmp = chptr->invites; tmp->next; tmp = tmp->next)
+                       ;
+               del_invite(tmp->value.cptr, chptr);
+       }
+       /*
+        * add client to the beginning of the channel invite list
+        */
+       inv = make_link();
+       inv->value.cptr = cptr;
+       inv->next = chptr->invites;
+       chptr->invites = inv;
+       /*
+        * add channel to the beginning of the client invite list
+        */
+       inv = make_link();
+       inv->value.chptr = chptr;
+       inv->next = cptr->user->invited;
+       cptr->user->invited = inv;
+}
+
+/*
+ * Delete Invite block from channel invite list and client invite list
+ */
+void   del_invite(cptr, chptr)
+aClient *cptr;
+aChannel *chptr;
+{
+       Reg1    Link    **inv, *tmp;
+
+       for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next)
+               if (tmp->value.cptr == cptr)
+                   {
+                       *inv = tmp->next;
+                       free_link(tmp);
+                       break;
+                   }
+
+       for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next)
+               if (tmp->value.chptr == chptr)
+                   {
+                       *inv = tmp->next;
+                       free_link(tmp);
+                       break;
+                   }
+}
+
+/*
+**  Subtract one user from channel i (and free channel
+**  block, if channel became empty).
+*/
+static void    sub1_from_channel(chptr)
+Reg1   aChannel *chptr;
+{
+       Ban     *ban;
+       Link    *lp;
+
+       if (--chptr->users <= 0)
+           {
+               /*
+                * Now, find all invite links from channel structure
+                */
+               while ((lp = chptr->invites))
+                       del_invite(lp->value.cptr, chptr);
+
+               while (chptr->banlist)
+               {
+                       ban = chptr->banlist;
+                       chptr->banlist = ban->next;
+                       MyFree(ban->banstr);
+                       MyFree(ban->who);
+                       free_ban(ban);
+               }
+               while (chptr->exlist)
+               {
+                       ban = chptr->exlist;
+                       chptr->exlist = ban->next;
+                       MyFree(ban->banstr);
+                       MyFree(ban->who);
+                       free_ban(ban);
+               }
+               if (chptr->prevch)
+                       chptr->prevch->nextch = chptr->nextch;
+               else
+                       channel = chptr->nextch;
+               if (chptr->nextch)
+                       chptr->nextch->prevch = chptr->prevch;
+               (void)del_from_channel_hash_table(chptr->chname, chptr);
+               MyFree((char *)chptr);
+           }
+}
+
+
+/*
+ * Channel Link
+ */
+int     channel_link(cptr, sptr, parc, parv)
+Reg2    aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        static  char    jbuf[BUFSIZE], *tmp;
+        Reg1    Link    *lp;
+        Reg3    aChannel *chptr;
+        Reg4    char    *name, *key = NULL, *link = NULL;
+        int     i,i1, flags = 0, zombie = 0;
+        char    *p = NULL, *p2 = NULL;
+
+        if (check_registered_user(sptr))
+                return 0;
+
+
+        if (parc < 2 || *parv[1] == '\0')
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "JOIN");
+                return 0;
+            }
+
+        *jbuf = '\0';
+        /*
+        ** Rebuild list of channels joined to be the actual result of the
+        ** JOIN.  Note that "JOIN 0" is the destructive problem.
+        */
+               bouncedtimes++;
+        if (bouncedtimes > MAXBOUNCE) {
+               /* bounced too many times */
+               sendto_one(sptr, ":%s NOTICE %s :*** Couldn't join %s ! - Link setting was too bouncy",
+                       me.name,
+                       sptr->name,
+                       parv[1]);
+               return;
+        }
+        for (i = 0, name = strtoken(&p, parv[1], ","); name;
+             name = strtoken(&p, NULL, ","))
+            {
+                /* pathological case only on longest channel name.
+                ** If not dealt with here, causes desynced channel ops
+                ** since ChannelExists() doesn't see the same channel
+                ** as one being joined. cute bug. Oct 11 1997, Dianora/comstud
+                ** Copied from Dianora's "hybrid 5" ircd.
+                */
+
+                if(strlen(name) >  CHANNELLEN)  /* same thing is done in get_channel() */
+                        name[CHANNELLEN] = '\0';
+
+                if (MyConnect(sptr))
+                        clean_channelname(name);
+                if (check_channelmask(sptr, cptr, name)==-1)
+                        continue;
+                if (*name == '&' && !MyConnect(sptr))
+                        continue;
+                if (*name == '0' && !atoi(name))
+                    {
+                        (void)strcpy(jbuf, "0");
+                        i = 1;
+                        continue;
+                    }
+                else if (!IsChannelName(name))
+                    {
+                        if (MyClient(sptr))
+                                sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+                                           me.name, parv[0], name);
+                        continue;
+                    }
+                if (*jbuf)
+                        (void)strcat(jbuf, ",");
+                (void)strncat(jbuf, name, sizeof(jbuf) - i - 1);
+                i += strlen(name)+1;
+            }
+        (void)strcpy(parv[1], jbuf);
+
+        p = NULL;
+        if (parv[2])
+        if (parv[2])
+                key = strtoken(&p2, parv[2], ",");
+        parv[2] = NULL; /* for m_names call later, parv[parc] must == NULL */
+        for (name = strtoken(&p, jbuf, ","); name;
+             key = (key) ? strtoken(&p2, NULL, ",") : NULL,
+             name = strtoken(&p, NULL, ","))
+            {
+                /*
+                ** JOIN 0 sends out a part for all channels a user
+                ** has joined.
+                */
+                if (*name == '0' && !atoi(name))
+                    {
+                        while ((lp = sptr->user->channel))
+                            {
+                                chptr = lp->value.chptr;
+                                  sendto_channel_butserv(chptr, sptr, PartFmt,
+                                      parv[0], chptr->chname);
+                                remove_user_from_channel(sptr, chptr);
+                            }
+                        sendto_serv_butone(cptr, ":%s JOIN 0", parv[0]);
+                        continue;
+                    }
+
+                if (MyConnect(sptr))
+                    {
+                        /*
+                        ** local client is first to enter previously nonexistant
+                        ** channel so make them (rightfully) the Channel
+                        ** Operator.
+                        */
+                        if (!IsModelessChannel(name))
+                            flags = (ChannelExists(name)) ? CHFL_DEOPPED :
+                                                            CHFL_CHANOP;
+                        else
+                            flags = CHFL_DEOPPED;
+
+                        if (sptr->user->joined >= MAXCHANNELSPERUSER)
+                            {
+                                sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
+                                           me.name, parv[0], name);
+                                return 0;
+                            }
+                    }
+
+                chptr = get_channel(sptr, name, CREATE);
+                
+                if (chptr && (lp=find_user_link(chptr->members, sptr)))
+                  continue;
+
+                       if (!MyConnect(sptr)) flags = CHFL_DEOPPED;
+                        if (sptr->flags & FLAGS_TS8) flags|=CHFL_SERVOPOK;
+
+               i1 = 0;
+               if (chptr == NULL)
+                       return;
+
+                if (!chptr ||
+                    (MyConnect(sptr) && (i = can_join(cptr, sptr, chptr, key, link, parv))))
+                    {
+                        if ( i != -1 ) 
+                       {        sendto_one(sptr, err_str(i),
+                                          me.name, parv[0], name);
+                        }
+                        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
+                */
+                               if (!IsHiding(sptr))
+                       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s",
+                                        parv[0], name);
+                       else {
+                               if (MyClient(sptr)) 
+                                       sendto_one(sptr, ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username,
+                                                       (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost),
+                                                        name);
+                               sendto_umode(UMODE_NETADMIN|UMODE_TECHADMIN, "*** Invisible(+I) user %s joined %s", sptr->name, chptr->chname);
+                       }
+                sendto_match_servs(chptr, cptr, ":%s JOIN :%s", parv[0], name);
+
+                if (MyClient(sptr))
+                    {
+                        /*
+                        ** Make a (temporal) creationtime, if someone joins
+                        ** during a net.reconnect : between remote join and
+                        ** the mode with TS. --Run
+                        */
+                        if (chptr->creationtime == 0)
+                        { chptr->creationtime = TStime();
+                          sendto_match_servs(chptr, cptr, ":%s MODE %s + %lu",
+                              me.name, name, chptr->creationtime);
+                        }
+                        del_invite(sptr, chptr);
+                        if (flags & CHFL_CHANOP)
+                                sendto_match_servs(chptr, cptr,
+                                  ":%s MODE %s +o %s %lu",
+                                  me.name, name, parv[0], chptr->creationtime);
+                        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;
+                        (void)m_names(cptr, sptr, 2, parv);
+                       bouncedtimes = 0;
+                    }
+
+            }
+        return 0;
+}
+
+/*
+** m_join
+**     parv[0] = sender prefix
+**     parv[1] = channel
+**     parv[2] = channel password (key)
+*/
+int    m_join(cptr, sptr, parc, parv)
+Reg2   aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       static  char    jbuf[BUFSIZE], *tmp;
+       Reg1    Link    *lp;
+       Reg3    aChannel *chptr;
+       Reg4    char    *name, *key = NULL, *link = NULL;
+       int     i, flags = 0, zombie = 0;
+       char    *p = NULL, *p2 = NULL;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       bouncedtimes = 0;       
+
+       if (parc < 2 || *parv[1] == '\0')
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "JOIN");
+               return 0;
+           }
+
+       *jbuf = '\0';
+       /*
+       ** Rebuild list of channels joined to be the actual result of the
+       ** JOIN.  Note that "JOIN 0" is the destructive problem.
+       */
+       for (i = 0, name = strtoken(&p, parv[1], ","); name;
+            name = strtoken(&p, NULL, ","))
+           {
+               /* pathological case only on longest channel name.
+               ** If not dealt with here, causes desynced channel ops
+               ** since ChannelExists() doesn't see the same channel
+               ** as one being joined. cute bug. Oct 11 1997, Dianora/comstud
+               ** Copied from Dianora's "hybrid 5" ircd.
+               */
+
+               if(strlen(name) >  CHANNELLEN)  /* same thing is done in get_channel() */
+                       name[CHANNELLEN] = '\0';
+
+               if (MyConnect(sptr))
+                       clean_channelname(name);
+               if (check_channelmask(sptr, cptr, name)==-1)
+                       continue;
+               if (*name == '&' && !MyConnect(sptr))
+                       continue;
+               if (*name == '0' && !atoi(name))
+                   {
+                       (void)strcpy(jbuf, "0");
+                       i = 1;
+                       continue;
+                   }
+               else if (!IsChannelName(name))
+                   {
+                       if (MyClient(sptr))
+                               sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+                                          me.name, parv[0], name);
+                       continue;
+                   }
+               if (*jbuf)
+                       (void)strcat(jbuf, ",");
+               (void)strncat(jbuf, name, sizeof(jbuf) - i - 1);
+               i += strlen(name)+1;
+           }
+       (void)strcpy(parv[1], jbuf);
+
+       p = NULL;
+       if (parv[2])
+               key = strtoken(&p2, parv[2], ",");
+       parv[2] = NULL; /* for m_names call later, parv[parc] must == NULL */
+       for (name = strtoken(&p, jbuf, ","); name;
+            key = (key) ? strtoken(&p2, NULL, ",") : NULL,
+            name = strtoken(&p, NULL, ","))
+           {
+               /*
+               ** JOIN 0 sends out a part for all channels a user
+               ** has joined.
+               */
+               if (*name == '0' && !atoi(name))
+                   {
+                       while ((lp = sptr->user->channel))
+                           {
+                               chptr = lp->value.chptr;
+                                 sendto_channel_butserv(chptr, sptr, PartFmt2,
+                                     parv[0], chptr->chname, "Left all channels");
+                               remove_user_from_channel(sptr, chptr);
+                           }
+                       sendto_serv_butone(cptr, ":%s JOIN 0", parv[0]);
+                       continue;
+                   }
+
+               if (MyConnect(sptr))
+                   {
+                       /*
+                       ** local client is first to enter previously nonexistant
+                       ** channel so make them (rightfully) the Channel
+                       ** Operator.
+                       */
+                        if (!IsModelessChannel(name))
+                            flags = (ChannelExists(name)) ? CHFL_DEOPPED :
+                                                            CHFL_CHANOWNER;
+                        else
+                            flags &= ~CHFL_CHANOWNER;
+
+                       if (!IsModelessChannel(name))
+                            flags = (ChannelExists(name)) ? CHFL_DEOPPED :
+                                                            CHFL_CHANOP;
+                       else
+                           flags = CHFL_DEOPPED;
+
+                       if (!(sptr->umodes & UMODE_AGENT)) /* Agents can join as many channels as needed */
+                               if (sptr->user->joined >= MAXCHANNELSPERUSER)
+                           {
+                                       sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS),
+                                          me.name, parv[0], name);
+                                       return 0;
+                           }
+/* RESTRICTCHAN */
+                       if (crlines)
+                       {
+                               if (channel_canjoin(sptr, name) != 1)
+                               {
+                                       if (cannotjoin_msg)
+                                               sendto_one(sptr, ":%s NOTICE %s :%s", me.name, sptr->name, cannotjoin_msg);
+                                       return 0;
+                               }
+                       }
+                   }
+
+               chptr = get_channel(sptr, name, CREATE);
+                if (chptr && (lp=find_user_link(chptr->members, sptr)))
+                 continue; 
+               
+               if (!MyConnect(sptr)) flags = CHFL_DEOPPED;
+               if (sptr->flags & FLAGS_TS8) flags|=CHFL_SERVOPOK;
+
+               if (!chptr ||
+                   (MyConnect(sptr) && (i = can_join(cptr, sptr, chptr, key, link, parv))))
+                   { 
+                               
+                               if (i != -1)
+                                       sendto_one(sptr, err_str(i),
+                                                  me.name, parv[0], name);
+                               
+                               /* uhm? was *chptr ??? *NULL = dangerous */
+                       continue;
+                               
+                       }
+               if (is_banned(cptr, sptr, chptr) && IsOper(sptr))
+               {
+                       sendto_umode(UMODE_EYES, "*** Banwalk [IRCop: %s] [Channel: %s]", sptr->name, chptr->chname);
+               }
+               /*
+               **  Complete user entry to the new channel (if any)
+               */
+               add_user_to_channel(chptr, sptr, flags);
+               /*
+               ** notify all other users on the new channel
+               */
+               if (!(IsHiding(sptr)))
+                       sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s",
+                                               parv[0], chptr->chname);
+               else {
+                               if (MyClient(sptr))
+                                       sendto_one(sptr, ":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username,
+                                       (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost),
+                                        chptr->chname);
+                               if (MyClient(sptr)) {
+                                       sendto_umode(UMODE_ADMIN, "*** [+I] %s invisible joined %s", sptr->name, chptr->chname); 
+                                       sendto_serv_butone(&me, ":%s SMO A :[+I] %s invisible joined %s", me.name, sptr->name, chptr->chname);
+                               }
+                       }
+               sendto_match_servs(chptr, cptr, ":%s JOIN :%s", parv[0], chptr->chname);
+
+               if (MyClient(sptr))
+                   {
+                       /*
+                       ** Make a (temporal) creationtime, if someone joins
+                       ** during a net.reconnect : between remote join and
+                       ** the mode with TS. --Run
+                       */
+                       if (chptr->creationtime == 0)
+                       { chptr->creationtime = TStime();
+                         sendto_match_servs(chptr, cptr, ":%s MODE %s + %lu",
+                             me.name, chptr->chname, chptr->creationtime);
+                       }
+                       del_invite(sptr, chptr);
+                       if (flags & CHFL_CHANOP)
+                               sendto_match_servs(chptr, cptr,
+                                 ":%s MODE %s +o %s %lu",
+                                 me.name, chptr->chname, parv[0], chptr->creationtime);
+                       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] = chptr->chname;
+                       (void)m_names(cptr, sptr, 2, parv);
+                   }
+
+           }
+
+       bouncedtimes = 0;
+       return 0;
+}
+
+/*
+** m_part
+**     parv[0] = sender prefix
+**     parv[1] = channel
+**     parv[2] = comment (added by Lefler)
+*/
+int    m_part(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+    int                xx = 0;
+       Reg1    aChannel *chptr;
+       Reg2  Link      *lp;
+       char    *p = NULL, *name;
+       register char *comment = (parc > 2 && parv[2]) ? parv[2] : NULL;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+        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;
+       }
+
+#ifdef V28PlusOnly
+       *buf = '\0';
+#endif
+
+       for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+       {
+               chptr = get_channel(sptr, name, 0);
+               if (!chptr)
+           {
+                       sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+                                  me.name, parv[0], name);
+                       continue;
+           }
+               if (check_channelmask(sptr, cptr, name))
+                       continue;
+               if (!(lp=find_user_link(chptr->members, sptr)))
+           {
+                       /* Normal to get 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 (MyClient(sptr))
+                               sendto_one(sptr, err_str(ERR_NOTONCHANNEL),
+                             me.name, parv[0], name);
+                       continue;
+           }
+               /*
+               **  Remove user from the old channel (if any)
+               */
+#ifdef V28PlusOnly
+               if (*buf)
+                       (void)strcat(buf, ",");
+               (void)strcat(buf, name);
+#else
+        if (parc < 3)
+                 sendto_match_servs(chptr, cptr, PartFmt, parv[0], name);
+               else
+                 sendto_match_servs(chptr, cptr, PartFmt2, parv[0], name, comment);
+#endif
+               if (1)
+               {
+                       if (!IsHiding(sptr))
+                       {
+                               if (parc < 3)
+                               {
+                                       sendto_channel_butserv(chptr, sptr, PartFmt, parv[0], name);
+                               } 
+                                       else
+                               {
+                                               sendto_channel_butserv(chptr, sptr, PartFmt2, parv[0], name, comment);
+                               }
+                       }
+                               else
+                       {
+                               if (MyClient(sptr))
+                               {
+                                       sendto_umode(UMODE_ADMIN, "*** [+I] %s invisible parted %s", sptr->name, chptr->chname);
+                                       sendto_serv_butone(&me, ":%s SMO A :[+I] %s invisible parted %s", me.name, sptr->name, chptr->chname);
+                               }
+                               if (MyClient(sptr))
+                                       /* awful hack .. */
+                                        if (parc < 3)
+                                               sendto_one(sptr, ":%s!%s@%s PART %s", sptr->name, sptr->user->username,
+                                               (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost),
+                                                        name);
+                                               else
+                                               sendto_one(sptr, ":%s!%s@%s PART %s :%s", sptr->name, sptr->user->username,
+                                                       (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost),
+                                                        name, comment);
+                       }
+                       remove_user_from_channel(sptr, chptr);
+                }
+       }
+#ifdef V28PlusOnly
+               sendto_serv_butone(cptr, PartFmt, parv[0], buf);
+#endif
+       return 0;
+    }
+
+/*
+** m_kick
+**     parv[0] = sender prefix
+**     parv[1] = channel
+**     parv[2] = client to kick
+**     parv[3] = kick comment
+*/
+int    m_kick(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *who;
+       aChannel *chptr;
+       int     chasing = 0;
+       char    *comment, *name, *p = NULL, *user, *p2 = NULL;
+       Link *lp,*lp2;
+
+       if (check_registered(sptr))
+               return 0;
+
+       sptr->flags&=~FLAGS_TS8;
+
+       if (parc < 3 || *parv[1] == '\0')
+       {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "KICK");
+               return 0;
+       }
+
+       comment = (BadPtr(parv[3])) ? parv[0] : parv[3];
+       if (strlen(comment) > (size_t) TOPICLEN)
+               comment[TOPICLEN] = '\0';
+
+       *nickbuf = *buf = '\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 (check_channelmask(sptr, cptr, name))
+                       continue;
+               if (!IsServer(cptr) && !IsOper(sptr) && !IsULine(cptr,sptr) && !is_chan_op(sptr, chptr) && !is_halfop(sptr,chptr))
+               {
+                       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, parv[0], chptr->chname);
+                       continue;
+               }
+
+               lp2=find_user_link(chptr->members, sptr);
+               for (; (user = strtoken(&p2, parv[2], ",")); parv[2] = NULL)
+               {
+                       if (!(who = find_chasing(sptr, user, &chasing)))
+                               continue; /* No such user left! */
+                        if ((lp=find_user_link(chptr->members, who)))
+                       {
+                               if (IsULine(cptr,sptr))
+                                       goto attack;
+                               /* Hiding patch by }{ */
+                               if (IsHiding(who)) {
+                                       sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], user, name);
+                                       sendto_one(who, ":%s NOTICE %s :*** Hidden: %s tried to kick you from channel %s (%s)", me.name, who->name, parv[0], chptr->chname, comment);
+                                       break;
+                               }
+
+                               if ((chptr->mode.mode & MODE_NOKICKS)
+                                       && !IsULine(cptr, sptr))
+                               {
+                                       sendto_one(sptr, ":%s NOTICE %s :*** You cannot kick people on %s",
+                                               me.name, sptr->name,
+                                               chptr->chname);
+                                               goto deny;
+                                               continue; 
+                               }
+                               
+                               if (IsOper(sptr))
+                                       if (!is_chan_op(sptr, chptr)) {
+                                               sendto_umode(UMODE_EYES, "*** OperKick [%s @ %s -> %s (%s)]", sptr->name, chptr->chname, who->name, comment);
+                                                       goto attack;
+                                       } /* is_chan_op */                      
+                                       if (is_chanprot(who, chptr) || is_chanowner(who, chptr) || IsServices(who))
+                                               if (!IsULine(cptr, sptr) && who != sptr)
+                                       {
+                                               sendto_one(sptr, ":%s NOTICE %s :*** You cannot kick %s from %s because %s is channel protected", 
+                                                                 me.name,   sptr->name,             who->name, chptr->chname, who->name);                              
+                                               goto deny;
+                                               continue;
+                                        } /* chanprot/chanowner */
+                                if (is_chan_op(who,chptr) && is_halfop(sptr, chptr) && !is_chan_op(sptr, chptr) && !IsULine(cptr, sptr)) {
+                                       sendto_one(sptr, ":%s NOTICE %s :*** You cannot kick channel operators on %s if you only are halfop", me.name, sptr->name, chptr->chname);
+                                       goto deny;
+                                 } /* halfop */
+
+                                 if (IsKix(who) && !IsULine(cptr, sptr))
+                                 {
+                                       if (!(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+                                       {
+                                                       sendto_one(sptr, ":%s NOTICE %s :*** Cannot kick %s from channel %s (usermode +q)", me.name, sptr->name, who->name, chptr->chname);
+                                                       sendto_one(who, ":%s NOTICE %s :*** Q: %s tried to kick you from channel %s (%s)", me.name, who->name, parv[0], chptr->chname, comment);
+                                                       goto deny;
+                                       }
+                                 }
+
+                               goto attack;
+
+                               deny:
+                               sendto_one(sptr, err_str(ERR_ATTACKDENY), me.name, parv[0], chptr->chname, user);
+                               continue;
+
+                               attack:
+                               if (lp)
+                                       sendto_channel_butserv(chptr, sptr,
+                                               ":%s KICK %s %s :%s", parv[0],
+                                               name, who->name, comment);
+                               sendto_match_servs(chptr, cptr,
+                                               ":%s KICK %s %s :%s",
+                                               parv[0], name,
+                                            who->name, comment);
+                               if (lp)
+                               {
+                                       remove_user_from_channel(who, chptr);
+                                }
+                        }
+                        else if (MyClient(sptr))
+                                 sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
+                                           me.name, parv[0], user, name);
+                        if (!IsServer(cptr) || !IsULine(cptr,sptr))
+                          break;
+                } /* loop on parv[2] */
+                if (!IsServer(cptr) || !IsULine(cptr,sptr))
+                  break;
+            } /* loop on parv[1] */
+
+        return 0;
+}
+
+
+int    count_channels(sptr)
+aClient        *sptr;
+{
+Reg1   aChannel        *chptr;
+       Reg2    int     count = 0;
+
+       for (chptr = channel; chptr; chptr = chptr->nextch)
+#ifdef SHOW_INVISIBLE_LUSERS
+               if (SecretChannel(chptr))
+                   {
+                       if (IsAnOper(sptr))
+                               count++;
+                   }
+               else
+#endif
+                       count++;
+       return (count);
+}
+
+/*
+** m_topic
+**     parv[0] = sender prefix
+**     parv[1] = topic text
+**
+**     For servers using TS: (Lefler)
+**     parv[0] = sender prefix
+**     parv[1] = channel list
+**     parv[2] = topic nickname
+**     parv[3] = topic time
+**     parv[4] = topic text
+*/
+int    m_topic(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       aChannel *chptr = NullChn;
+       char    *topic = NULL, *name, *p = NULL, *tnick = NULL;
+       time_t  ttime = 0;
+       
+       if (check_registered(sptr))
+               return 0;
+
+       if (parc < 2)
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "TOPIC");
+               return 0;
+           }
+
+       for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+           {
+               if (parc > 1 && IsChannelName(name))
+                   {
+                       chptr = find_channel(name, NullChn);
+                       if (!chptr || (!IsMember(sptr, chptr) &&
+                           !IsServer(sptr) && !IsULine(cptr,sptr)))
+                           {
+                               sendto_one(sptr, err_str(ERR_NOTONCHANNEL),
+                                          me.name, parv[0], name);
+                               continue;
+                           }                           
+                       if (parc > 2)
+                               topic = parv[2];
+                       if (parc > 4) {
+                               tnick = parv[2];
+                               ttime = atol(parv[3]);
+                               topic = parv[4];
+                       }
+                   }
+
+               if (!chptr)
+                   {
+                       sendto_one(sptr, rpl_str(RPL_NOTOPIC),
+                                  me.name, parv[0], name);
+                       return 0;
+                   }
+
+               if (check_channelmask(sptr, cptr, name))
+                       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 (ttime && topic && (IsServer(sptr) || IsULine(cptr,sptr)))
+                   {
+                       if (!chptr->topic_time || ttime < chptr->topic_time)
+                          {
+                               /* setting a topic */
+                               strncpyzt(chptr->topic, topic, sizeof(chptr->topic));
+                               strcpy(chptr->topic_nick, tnick);
+                               chptr->topic_time = ttime;
+                               sendto_match_servs(chptr, cptr,":%s TOPIC %s %s %lu :%s",
+                                          parv[0], chptr->chname,
+                                          chptr->topic_nick, chptr->topic_time,
+                                          chptr->topic);
+                               sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s (%s)",
+                                              parv[0], chptr->chname,
+                                              chptr->topic, chptr->topic_nick);
+                          }
+                   }
+               else if (((chptr->mode.mode & MODE_TOPICLIMIT) == 0 ||
+                         is_chan_op(sptr, chptr)) || IsOper(sptr) || IsULine(cptr,sptr)
+                         || is_halfop(sptr, chptr)  && topic)
+                    {
+                       /* setting a topic */
+                       if (IsOper(sptr) && !(is_halfop(sptr, chptr) || IsULine(cptr,sptr) || is_chan_op(sptr, chptr)) && (chptr->mode.mode & MODE_TOPICLIMIT))
+                       {
+                               sendto_umode(UMODE_EYES, "*** OperTopic [IRCop: %s] - [Channel: %s] - [Topic: %s]", sptr->name, chptr->chname, topic);
+                       }
+                       strncpyzt(chptr->topic, topic, sizeof(chptr->topic));
+                       strcpy(chptr->topic_nick, sptr->name);
+                        if (ttime && IsServer(cptr))
+                         chptr->topic_time = ttime;
+                       else
+                         chptr->topic_time = TStime();
+                       sendto_match_servs(chptr, cptr,":%s TOPIC %s %s %lu :%s",
+                                          parv[0], chptr->chname, parv[0],
+                                          chptr->topic_time, 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 number
+*/
+int    m_invite(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       aClient *acptr;
+       aChannel *chptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 3 || *parv[1] == '\0')
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "INVITE");
+               return -1;
+           }
+
+       if (!(acptr = find_person(parv[1], (aClient *)NULL)))
+           {
+               sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+                          me.name, parv[0], parv[1]);
+               return 0;
+           }
+         
+       if (MyConnect(sptr))
+               clean_channelname(parv[2]);
+       if (check_channelmask(sptr, cptr, parv[2]))
+               return 0;
+       if (!(chptr = find_channel(parv[2], NullChn)))
+           {
+
+               sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",
+                                 parv[0], parv[1], parv[2]);
+               return 0;
+           }
+       if (chptr->mode.mode & MODE_NOINVITE)
+               if (!IsULine(cptr,sptr)) {
+                       sendto_one(sptr, err_str(ERR_NOINVITE),
+                               me.name, parv[0], parv[2]);
+                       return -1;
+               } 
+       if (chptr && !IsMember(sptr, chptr) && !IsULine(cptr,sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOTONCHANNEL),
+                          me.name, parv[0], parv[2]);
+               return -1;
+           }
+
+       if (IsMember(acptr, chptr))
+           {
+               sendto_one(sptr, err_str(ERR_USERONCHANNEL),
+                          me.name, parv[0], parv[1], parv[2]);
+               return 0;
+           }
+       if (chptr && (chptr->mode.mode & MODE_INVITEONLY))
+           {
+               if (!is_chan_op(sptr, chptr) && !IsULine(cptr,sptr))
+                   {
+                       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, parv[0], chptr->chname);
+                       return -1;
+                   }
+               else if (!IsMember(sptr, chptr) && !IsULine(cptr,sptr))
+                   {
+                       sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
+                                  me.name, parv[0],
+                                  ((chptr) ? (chptr->chname) : parv[2]));
+                       return -1;
+                   }
+           }
+
+       if (MyConnect(sptr))
+           {
+               if(check_for_target_limit(sptr, acptr, acptr->name))
+                       return 0;
+
+               sendto_one(sptr, rpl_str(RPL_INVITING), me.name, parv[0],
+                          acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
+               if (acptr->user->away)
+                       sendto_one(sptr, rpl_str(RPL_AWAY), me.name, parv[0],
+                                  acptr->name, acptr->user->away);
+           }
+       /* Note: is_banned() here will cause some extra CPU load, 
+        *       and we're really only relying on the existence
+        *       of the limit because we could momentarily have
+        *       less people on channel.
+        */
+       if (MyConnect(acptr))
+               if (chptr && sptr->user && (is_banned(acptr, sptr, chptr) ||
+                    (chptr->mode.mode & MODE_INVITEONLY) ||
+                    chptr->mode.limit) &&
+                   (is_chan_op(sptr, chptr) || IsULine(cptr,sptr)))
+               {
+                       add_invite(acptr, chptr);
+                       sendto_channelops_butone(NULL, &me, chptr,
+                         ":%s NOTICE @%s :%s invited %s into the channel.",
+                         me.name, chptr->chname, sptr->name, acptr->name);
+               }
+       sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",parv[0],
+                         acptr->name, ((chptr) ? (chptr->chname) : parv[2]));
+       return 0;
+    }
+
+
+
+
+/*
+ * send_list
+ *
+ * The function which sends
+ * The function which sends the actual /list output back to the user.
+ * Operates by stepping through the hashtable, sending the entries back if
+ * they match the criteria.
+ * cptr = Local client to send the output back to.
+ * numsend = Number (roughly) of lines to send back. Once this number has
+ * been exceeded, send_list will finish with the current hash bucket,
+ * and record that number as the number to start next time send_list
+ * is called for this user. So, this function will almost always send
+ * back more lines than specified by numsend (though not by much,
+ * assuming CHANNELHASHSIZE is was well picked). So be conservative
+ * if altering numsend };> -Rak
+ */
+void   send_list(cptr, numsend)
+aClient        *cptr;
+int    numsend;
+{
+    int        hashptr, done = 0;
+    aChannel   *chptr;
+    Link       *tmpl;
+
+#define l cptr->lopt /* lazy shortcut */
+
+    for (hashptr = l->starthash; hashptr < CHANNELHASHSIZE; hashptr++) {
+       for (chptr = hash_get_chan_bucket(hashptr);
+            chptr; chptr = chptr->hnextch) {
+           if (IsAnOper(cptr))
+               goto showmethesecrets;
+           if (SecretChannel(chptr) && !IsMember(cptr, chptr))
+               continue;
+showmethesecrets:
+           if (!l->showall && ((chptr->users <= l->usermin) ||
+               ((l->usermax == -1)?0:(chptr->users >= l->usermax)) ||
+               ((chptr->creationtime||1) <= l->chantimemin) ||
+               (chptr->topic_time < l->topictimemin) ||
+               (chptr->creationtime >= l->chantimemax) ||
+               (chptr->topic_time > l->topictimemax)))
+               continue;
+           /* For now, just extend to topics as well. Use patterns starting
+            * with # to stick to searching channel names only. -Donwulff
+            */
+           if (l->nolist && 
+               (find_str_match_link(&(l->nolist), chptr->chname) ||
+                find_str_match_link(&(l->nolist), chptr->topic)))
+               continue;
+           if (l->yeslist &&
+               (!find_str_match_link(&(l->yeslist), chptr->chname) &&
+                !find_str_match_link(&(l->yeslist), chptr->topic)))
+               continue;
+           if (!IsAnOper(cptr))
+                   sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name,
+                              ShowChannel(cptr, chptr) ? chptr->chname : "*",
+                              chptr->users,
+                              ShowChannel(cptr, chptr) ? chptr->topic : "");
+           else
+               sendto_one(cptr, rpl_str(RPL_LIST), me.name, cptr->name, chptr->chname, chptr->users, chptr->topic);
+           if (--numsend == 0) /* Send to the end of the list and return */
+           done = 1;
+       }
+
+       if (done && (++hashptr < CHANNELHASHSIZE)) {
+           l->starthash = hashptr;
+           return;
+       }
+    }
+
+    sendto_one(cptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
+    free_str_list(l->yeslist);
+    free_str_list(l->nolist);
+    MyFree(l);
+    l = NULL;
+
+    /* List finished, penalize by 10 seconds -Donwulff */
+    if (!IsPrivileged(cptr))
+       cptr->since+=10;
+
+    return;
+}
+
+int    check_for_chan_flood(cptr, sptr, chptr)
+aClient *cptr, *sptr;
+aChannel *chptr;
+{
+       Reg1    Link    *lp;
+       
+       if (!MyClient(sptr))
+               return 0;
+       if (IsOper(sptr) || IsULine(cptr,sptr))
+               return 0;
+       if (is_chan_op(sptr, chptr))
+               return 0;
+               
+        if (!(lp = find_user_link(chptr->members, sptr)))
+           return 0;
+       
+       if ((chptr->mode.msgs < 1) || (chptr->mode.per < 1))
+               return 0;
+       
+       /* Theory here is 
+          If current - lastmsgtime <= mode.per
+           and nummsg is higher than mode.msgs
+           then kick 
+       */
+       
+       if ( (TStime() - (lp->flood->lastmsg))  >= /* current - lastmsgtime */
+            chptr->mode.per)            /* mode.per */
+       {
+               /* reset the message counter */
+               lp->flood->lastmsg      = TStime();
+               lp->flood->nmsg         = 1;
+               return 0; /* forget about it.. */
+       }
+       
+       /* increase msgs */
+       lp->flood->nmsg++;
+       lp->flood->lastmsg = TStime();  
+       
+       if ( (lp->flood->nmsg) > chptr->mode.msgs )
+       {
+               char    comment[1024], mask[1024];
+               
+               sprintf(comment, "Flooding (Limit is %i lines per %i seconds)",
+                       chptr->mode.msgs, chptr->mode.per);
+               if (chptr->mode.kmode == 1)
+               {  /* ban. */
+                       sprintf(mask, "*!*@%s", (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost));
+                       add_banid(&me, chptr, mask);
+                       sendto_serv_butone(&me, ":%s MODE %s +b %s NoTS", me.name, chptr->chname, mask);
+                       sendto_channel_butserv (chptr, &me, ":%s MODE %s +b %s", me.name, chptr->chname, mask);
+                }
+                sendto_channel_butserv (chptr, &me,
+                         ":%s KICK %s %s :%s", me.name,
+                         chptr->chname,
+                         sptr->name, 
+                         comment);
+               sendto_serv_butone(cptr, ":%s KICK %s %s :%s",
+                         me.name,
+                         chptr->chname,
+                         sptr->name, 
+                         comment);
+               remove_user_from_channel (sptr, chptr);
+               return 1;                 
+       }       
+}
+
+/*
+ * m_list
+ *     parv[0] = sender prefix
+ *     parv[1,2,3...] = Channels or list options.
+ */
+int    m_list(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+    aChannel *chptr;
+    char   *name, *p = NULL;
+    LOpts  *lopt;
+    short  int  showall = 0;
+    Link   *yeslist = NULL, *nolist = NULL, *listptr;
+    short  usermin = 0, usermax = -1;
+    time_t currenttime = TStime();
+    time_t chantimemin = 0, topictimemin = 0;
+    time_t chantimemax, topictimemax;
+
+    static char *usage[] = {
+       "   Usage: /raw LIST options (on mirc) or /quote LIST options (ircII)",
+       "",
+       "If you don't include any options, the default is to send you the",
+       "entire unfiltered list of channels. Below are the options you can",
+       "use, and what channels LIST will return when you use them.",
+       ">number  List channels with more than <number> people.",
+       "<number  List channels with less than <number> people.",
+       "C>number List channels created between now and <number> minutes ago.",
+       "C<number List channels created earlier than <number> minutes ago.",
+       "T>number List channels whose topics are older than <number> minutes",
+       "         (Ie, they have not changed in the last <number> minutes.",
+       "T<number List channels whose topics are not older than <number> minutes.",
+       "*mask*   List channels that match *mask*",
+       "!*mask*  List channels that do not match *mask*",
+       NULL
+    };
+
+
+    /* None of that unregistered LIST stuff.  -- Barubary */
+    if (check_registered(sptr)) return 0;
+
+    /*
+     * I'm making the assumption it won't take over a day to transmit
+     * the list... -Rak
+     */
+    chantimemax = topictimemax = currenttime + 86400;
+
+
+    if ((parc == 2) && (!strcasecmp(parv[1], "?"))) {
+       char **ptr = usage;
+
+       for (; *ptr; ptr++)
+           sendto_one(sptr, rpl_str(RPL_LISTSYNTAX), me.name,
+                      cptr->name, *ptr);
+       return 0;
+    }
+
+    /*
+     * A list is already in process, for now we just interrupt the
+     * current listing, perhaps later we can allow stacked ones...
+     *  -Donwulff (Not that it's hard or anything, but I don't see
+     *             much use for it, beyond flooding)
+     */
+
+    if(cptr->lopt) {
+       free_str_list(cptr->lopt->yeslist);
+       free_str_list(cptr->lopt->nolist);
+       MyFree(cptr->lopt);
+       cptr->lopt=NULL;
+       sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
+       /* Interrupted list, penalize 10 seconds */
+       if(!IsPrivileged(sptr))
+           sptr->since+=10;
+       
+       return 0;
+    }
+
+    sendto_one(sptr, rpl_str(RPL_LISTSTART), me.name, cptr->name);
+
+    /* LIST with no arguements */
+    if (parc < 2 || BadPtr(parv[1])) {
+       lopt = (LOpts *)MyMalloc(sizeof(LOpts));
+           if (!lopt)
+               return 0;
+
+       /*
+        * Changed to default to ignoring channels with only
+        * 1 person on, to decrease floods... -Donwulff
+        */
+       bzero(lopt, sizeof(LOpts)); /* To be sure! */
+       lopt->next = (LOpts *)lopt->yeslist=lopt->nolist=(Link *)NULL;
+       lopt->usermin = 0; /* Default */
+       lopt->usermax = -1;
+       lopt->chantimemax = lopt->topictimemax = currenttime + 86400;
+       cptr->lopt = lopt;
+       if (IsSendable(cptr))
+           send_list(cptr, 64);
+       return 0;
+    }
+
+
+    /*
+     * General idea: We don't need parv[0], since we can get that
+     * information from cptr.name. So, let's parse each element of
+     * parv[], setting pointer parv to the element being parsed.
+     */
+    while (--parc) {
+       parv += 1;
+       if (BadPtr(parv)) /* Sanity check! */
+           continue;
+
+       name = strtoken(&p, *parv, ",");
+
+       while (name) {
+         switch (*name) {
+           case '>':
+               showall = 1;
+               usermin = strtol(++name, (char **) 0, 10);
+               break;
+
+           case '<':
+               showall = 1;
+               usermax = strtol(++name, (char **) 0, 10);
+               break;
+
+           case 't':
+           case 'T':
+               showall = 1;
+               switch (*++name) {
+                   case '>':
+                       topictimemax = currenttime - 60 *
+                                      strtol(++name, (char **) 0, 10);
+                       break;
+
+                   case '<':
+                       topictimemin = currenttime - 60 *
+                                      strtol(++name, (char **) 0, 10);
+                       break;
+
+                   case '\0':
+                       topictimemin = 1;
+                       break;
+
+                   default:
+                       sendto_one(sptr, err_str(ERR_LISTSYNTAX),
+                                  me.name, cptr->name);
+                       free_str_list(yeslist);
+                       free_str_list(nolist);
+                       sendto_one(sptr, rpl_str(RPL_LISTEND),
+                                  me.name, cptr->name);
+
+                       return 0;
+               }
+               break;
+
+               case 'c':
+               case 'C':
+                   showall = 1;
+                   switch (*++name) {
+                       case '>':
+                           chantimemin = currenttime - 60 *
+                                         strtol(++name, (char **) 0, 10);
+                           break;
+
+                       case '<':
+                           chantimemax = currenttime - 60 *
+                                         strtol(++name, (char **) 0, 10);
+                           break;
+
+                       default:
+                           sendto_one(sptr, err_str(ERR_LISTSYNTAX),
+                                      me.name, cptr->name);
+                           free_str_list(yeslist);
+                           free_str_list(nolist);
+                           sendto_one(sptr, rpl_str(RPL_LISTEND),
+                                      me.name, cptr->name);
+                           return 0;
+                   }
+                   break;
+
+               default: /* A channel or channel mask */
+
+                   /*
+                    * new syntax: !channelmask will tell ircd to ignore
+                    * any channels matching that mask, and then
+                    * channelmask will tell ircd to send us a list of
+                    * channels only masking channelmask. Note: Specifying
+                    * a channel without wildcards will return that
+                    * channel even if any of the !channelmask masks
+                    * matches it.
+                    */
+
+                   if (*name == '!') {
+                       showall = 1;
+                       listptr = make_link();
+                       listptr->next = nolist;
+                       DupString(listptr->value.cp, name+1);
+                       nolist = listptr;
+                   }
+                   else if (strchr(name, '*') || strchr(name, '?')) {
+                       showall = 1;
+                       listptr = make_link();
+                       listptr->next = yeslist;
+                       DupString(listptr->value.cp, name);
+                       yeslist = listptr;
+                   }
+                   else {
+                       chptr = find_channel(name, NullChn);
+                       if (chptr && ShowChannel(sptr, chptr))
+                           sendto_one(sptr, rpl_str(RPL_LIST),
+                                      me.name, cptr->name,
+                                      ShowChannel(sptr,chptr) ? name : "*",
+                                      chptr->users,
+                                      chptr->topic);
+                   }
+         } /* switch (*name) */
+       name = strtoken(&p, NULL, ",");
+       } /* while(name) */
+    } /* while(--parc) */
+
+    if (!showall || (chantimemin > currenttime) ||
+        (topictimemin > currenttime)) {
+       free_str_list(yeslist);
+       free_str_list(nolist);
+       sendto_one(sptr, rpl_str(RPL_LISTEND), me.name, cptr->name);
+
+       return 0;
+    }
+
+    lopt = (LOpts *)MyMalloc(sizeof(LOpts));
+
+    lopt->showall = 0;
+    lopt->next = NULL;
+    lopt->yeslist = yeslist;
+    lopt->nolist = nolist;
+    lopt->starthash = 0;
+    lopt->usermin = usermin;
+    lopt->usermax = usermax;
+    lopt->currenttime = currenttime;
+    lopt->chantimemin = chantimemin;
+    lopt->chantimemax = chantimemax;
+    lopt->topictimemin = topictimemin;
+    lopt->topictimemax = topictimemax;
+
+    cptr->lopt = lopt;
+    send_list(cptr, 64);
+
+
+
+    return 0;
+}
+
+
+/************************************************************************
+ * m_names() - Added by Jto 27 Apr 1989
+ * 12 Feb 2000 - geesh, time for a rewrite -lucas
+ ************************************************************************/
+/*
+** m_names
+**     parv[0] = sender prefix
+**     parv[1] = channel
+*/
+#define TRUNCATED_NAMES 64
+int    m_names(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{ 
+   int mlen = strlen(me.name) + NICKLEN + 7;
+   aChannel *chptr;
+   aClient *acptr;
+   int member;
+   Link *cm;
+   int idx, flag = 1, spos;
+   char *s, *para = parv[1];
+
+   if (check_registered(sptr)) return 0;
+   
+   if (parc < 2 || !MyConnect(sptr)) 
+   {
+      sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], "*");
+      return 0;
+   }
+
+   if (parc > 1 &&
+            hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
+                return 0;
+
+   for(s = para; *s; s++) 
+   {
+      if(*s == ',') 
+      {
+         para[TRUNCATED_NAMES] = '\0';
+         sendto_realops("names abuser %s %s", get_client_name(sptr, FALSE), para);
+         sendto_one(sptr, err_str(ERR_TOOMANYTARGETS), me.name, sptr->name, "NAMES");
+         return 0;
+      }
+   }
+
+   chptr = find_channel(para, (aChannel *) NULL);
+
+   if (!chptr || !ShowChannel(sptr, chptr))
+   {
+      sendto_one(sptr, rpl_str(RPL_ENDOFNAMES), me.name, parv[0], para);
+      return 0;
+   }
+
+   /* cache whether this user is a member of this channel or not */
+   member = IsMember(sptr, chptr);
+
+   if(PubChannel(chptr))
+      buf[0] = '=';
+   else if(SecretChannel(chptr))
+      buf[0] = '@';
+   else
+      buf[0] = '*';
+
+   idx = 1;
+   buf[idx++] = ' ';
+   for(s = chptr->chname; *s; s++)
+      buf[idx++] = *s;
+   buf[idx++] = ' ';
+   buf[idx++] = ':';
+
+   spos = idx; /* starting point in buffer for names!*/
+
+   for (cm = chptr->members; cm; cm = cm->next) 
+   {
+      acptr = cm->value.cptr;
+      if(IsInvisible(acptr) && !member)
+         continue;
+      if(cm->flags & CHFL_CHANOP)
+         buf[idx++] = '@';
+         else if (cm->flags & CHFL_HALFOP)
+        buf[idx++] = '%';
+      else if(cm->flags & CHFL_VOICE)
+         buf[idx++] = '+';
+      for(s = acptr->name; *s; s++)
+         buf[idx++] = *s;
+      buf[idx++] = ' ';
+      buf[idx] = '\0';
+      flag = 1;
+      if(mlen + idx + NICKLEN > BUFSIZE - 3)
+      {
+         sendto_one(sptr, rpl_str(RPL_NAMREPLY), me.name, parv[0], buf);
+         idx = spos;
+         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], para);
+
+   return 0;
+
+}
+
+void   send_user_joins(cptr, user)
+aClient        *cptr, *user;
+{
+       Reg1    Link    *lp;
+       Reg2    aChannel *chptr;
+       Reg3    int     cnt = 0, len = 0, clen;
+       char     *mask;
+
+       sprintf(buf, ":%s %s ", user->name,
+               (IsToken(cptr)?TOK_JOIN:MSG_JOIN));
+       len = strlen(buf);
+
+       for (lp = user->user->channel; lp; lp = lp->next)
+           {
+               chptr = lp->value.chptr;
+               if ((mask = index(chptr->chname, ':')))
+                       if (match(++mask, cptr->name))
+                               continue;
+               if (*chptr->chname == '&')
+                       continue;
+               clen = strlen(chptr->chname);
+               if (clen + 1 + len > BUFSIZE - 3)
+                   {
+                       if (cnt)
+                       {
+                               buf[len-1]='\0';
+                               sendto_one(cptr, "%s", buf);
+                       }
+                       sprintf(buf, ":%s %s ", user->name,
+                               (IsToken(cptr)?TOK_JOIN:MSG_JOIN));
+                       len = strlen(buf);
+                       cnt = 0;
+                   }
+               (void)strcpy(buf + len, chptr->chname);
+               cnt++;
+               len += clen;
+               if (lp->next)
+                   {
+                       len++;
+                       (void)strcat(buf, ",");
+                   }
+           }
+       if (*buf && cnt)
+               sendto_one(cptr, "%s", buf);
+
+       return;
+}
+
+
+/*
+** m_knock
+**     parv[0] - sender prefix
+**     parv[1] - channel
+**     parv[2] - reason
+**
+** Coded by Stskeeps
+** Additional bugfixes/ideas by codemastr
+** (C) codemastr & Stskeeps
+** 
+*/
+int    m_knock(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       aClient *acptr;
+       aChannel *chptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 3 || *parv[1] == '\0')
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "KNOCK");
+               return -1;
+           }
+
+       if (MyConnect(sptr))
+               clean_channelname(parv[1]);
+
+       if (check_channelmask(sptr, cptr, parv[1]))
+               return 0;
+       /* bugfix for /knock PRv Please? */
+       if (*parv[1] != '#' && *parv[1] != '&')
+       {
+                       sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                               me.name,
+                                               sptr->name,
+                                               parv[1],
+                                               "Remember to use a # prefix in channel name");
+       
+                       return 0;
+       }
+       if (!(chptr = find_channel(parv[1], NullChn)))
+           {
+                       sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                               me.name,
+                                               sptr->name,
+                                               parv[1],
+                                               "Channel does not exist!");
+                       return 0;
+           }
+
+       /* IsMember bugfix by codemastr */
+       if (IsMember(sptr, chptr)==1) {
+                       sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                               me.name,
+                                               sptr->name,
+                                               chptr->chname,
+                                       "You're already there!");
+               return 0;
+       }
+       if (chptr->mode.mode & MODE_NOKNOCK) {
+                       sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                               me.name,
+                                               sptr->name,
+                                               chptr->chname,
+                                       "No knocks are allowed! (+K)");
+               return 0;
+       }       
+
+       if (chptr->mode.mode & MODE_INVITEONLY) {
+       }
+        else
+       {
+               sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                       me.name,
+                                       sptr->name,
+                                       chptr->chname,
+                               "Channel is not invite only!");
+               return 0;
+       }
+
+       if (is_banned(cptr, sptr, chptr)) {
+               sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                       me.name,
+                                       sptr->name,
+                                       chptr->chname,
+                       "You're banned!");
+               return 0;
+       }       
+
+   if (chptr->mode.mode & MODE_NOINVITE) {
+               sendto_one(sptr, err_str(ERR_CANNOTKNOCK),
+                                       me.name,
+                                       sptr->name,
+                                       chptr->chname,
+                       "You can not get invited anyways! (+I)");
+
+               return 0;
+   }   
+               
+       sendto_channelops_butone(NULL, &me, chptr,
+                         ":%s NOTICE @%s :[Knock] by %s!%s@%s (%s) ",
+                         me.name, chptr->chname, sptr->name, 
+                         sptr->user->username,
+                         (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost),                         
+                         parv[2]);
+
+       sendto_one(sptr, ":%s NOTICE %s :Knocked on to %s", me.name, sptr->name,
+               chptr->chname);
+       return 0;
+}
+
+typedef struct xParv aParv;
+struct xParv
+{
+       int     parc;
+       char    *parv[256];
+};
+
+aParv  pparv;
+
+aParv   *mp2parv(char *xmbuf, char *parmbuf)
+{
+        int     c;
+        char    *p;
+        pparv.parv[0] = xmbuf;
+        c = 1;
+        for (p = (char *)strtok((char *) parmbuf, " "); p; p = (char *)strtok((char *)NULL, " "))
+        {
+               c++;        
+               pparv.parv[c-1] = p;
+        } 
+        pparv.parc = c;
+        return (&pparv);
+}
+
+/*
+   **      m_sjoin
+   **
+   **   SJOIN will synch channels and channelmodes using the new STS1 protocol
+   **      that is based on the EFnet TS3 protocol.
+   **                           -GZ (gz@starchat.net)
+   **         
+   **  Modified for Unreal3.0 by Stskeeps
+   **      parv[0] = sender prefix
+   **      parv[1] = channel timestamp
+   **      parv[2] = channel name
+   **      parv[3] = channel modes
+   **      parv[4] = channel mode parameters (key/limit)
+   **      parv[5] = nick names + modes - all in one parameter 
+ */
+#define FL_VOICE  0x1
+#define FL_HALFOP 0x2
+#define FL_CHANOP 0x4
+#define FL_PROT   0x8
+#define FL_FOUNDER  0x10
+
+int m_sjoin(cptr, sptr, parc, parv)
+    Reg2 aClient *cptr, *sptr;
+    int parc;
+    char *parv[];
+{
+    aClient *acptr, *tempptr;
+    aChannel *chptr;
+    aSynchList *synchptr, *synchptr2, *synchptr3;
+    aParv *ap;
+    char *p; int i;
+    char    pvar[MAXMODEPARAMS][MODEBUFLEN+3];
+    Link *lp, *lp2, *members;
+    static char nick[NICKLEN];
+    char *t, *bp;
+    int c, f, fl, ts, copy, merge, wipem, nopara;
+    int nickstatus, ns, tc, xsend, susp_ts, pcount;
+    int oldts,xxsend = 0;
+
+    if (IsClient(sptr) || parc < 6 || !IsServer(sptr)) /* Double check redundant? yeah, I think so -GZ */
+       return 0;
+
+    if (!IsChannelName(parv[2]))
+       return 0;
+    nopara = 0;
+
+    if (!strncmp(parv[4], "<none>", 6) || !strncmp(parv[4], "<->", 3)) {
+       nopara = 1;
+    }
+    xsend = 1;
+
+    /* If length of modebuf is 1, we dont have to do anything */
+
+    if (parv[3][1] == 0)       /* ie if the 2nd character is NULL, its length is one (or zero, but thats not possible */
+       xsend = 0;
+
+    chptr = get_channel(cptr, parv[2], CREATE);
+
+    ts = atol(parv[1]);
+
+    copy = merge = tc = wipem = susp_ts = 0;
+
+    if (chptr->creationtime > ts) {
+       copy = wipem = 1;
+    } else if (chptr->creationtime == ts) {
+       merge = 1;
+    }
+    /* If our timestamp is 0 this is a new channel, copy it. */
+
+    if (chptr->creationtime == 0 && ts > 0) {
+       copy = 1;
+        oldts = -1;
+    }
+     else
+       oldts = chptr->creationtime;
+    /* Hmmmmmm.....timestamp is below 750000, something fishy is going on
+     * let's just not take this SJOIN too seriously... -GZ
+     */
+
+    if (ts < 750000) {
+       if (ts != 0)
+           sendto_ops("Warning! Possible desynch: SJOIN for channel %s has a fishy timestamp (%ld)", chptr->chname, ts);
+       susp_ts = 1;
+    }
+    t = parv[5];
+    bp = buf;
+
+    c = fl = nickstatus = 0;
+    f = 1;
+
+    /* Let's see what the channel-modes are first here */
+
+    parabuf[0] = '\0';
+    modebuf[0] = '+';
+    modebuf[1] = '\0';
+    channel_modes(cptr, modebuf, parabuf, chptr);
+
+    /* Let's clean our channel-modes if nescessary */
+
+    if (wipem && (modebuf[1] != '\0') && !susp_ts) {
+
+       modebuf[0] = '-';
+       ap = mp2parv(modebuf, parabuf);
+       set_mode(chptr, cptr, ap->parc, ap->parv, &pcount, pvar, 0);
+       sendto_serv_butone_sjoin(cptr, ":%s %s %s %s %s %lu", me.name, MSG_MODE, chptr->chname, modebuf,
+                                parabuf, chptr->creationtime);
+       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s", me.name,
+                             chptr->chname, modebuf, parabuf);
+    }
+    /* Now let's apply the modes as required */
+
+    if ((copy || merge) && xsend && !susp_ts) {
+       *parabuf = '\0';
+       *modebuf = '+';
+       modebuf[1] = '\0';
+
+       if (parv[3]) {
+           strcpy(modebuf, parv[3]);
+           xsend = 1;
+       }
+       if (!nopara)
+           strcpy(parabuf, parv[4]);
+       else
+           parabuf[0] = '\0';
+
+       if (xsend) {
+           sendto_serv_butone_sjoin(cptr, ":%s %s %s %s %s %lu", me.name,
+            MSG_MODE, chptr->chname, modebuf,
+                                    parabuf, chptr->creationtime);
+           sendto_channel_butserv(chptr,sptr, ":%s MODE %s %s %s", me.name,
+                                  chptr->chname, modebuf, parabuf);
+           ap = mp2parv(modebuf, parabuf);
+               set_mode(chptr, cptr, ap->parc, ap->parv, &pcount, pvar, 0);
+       }
+    }
+    xsend = 0;
+
+    /* First we better wipe our chanop list if our TS is older than SJOIN TS */
+
+    if (wipem && !susp_ts)
+    {
+       members = chptr->members;
+       for (lp2 = members; lp2; lp2 = lp2->next)
+       {
+
+           if ((lp2->flags & MODE_CHANOP)) {
+               lp2->flags &= ~MODE_CHANOP;
+               acptr = lp2->value.cptr;
+
+               sendto_channel_butserv(chptr, cptr, ":%s MODE %s -o %s", me.name, chptr->chname, lp2->value.cptr->name);
+               sendto_serv_butone_sjoin(cptr, ":%s MODE %s -o %s %lu", me.name, chptr->chname, acptr->name, chptr->creationtime);
+           }
+           if ((lp2->flags & MODE_VOICE))
+           {
+               lp2->flags &= ~MODE_VOICE;
+
+               acptr = lp2->value.cptr;
+
+               sendto_channel_butserv(chptr, cptr, ":%s MODE %s -v %s", me.name, chptr->chname, acptr->name);
+               sendto_serv_butone_sjoin(cptr, ":%s MODE %s -v %s %lu", me.name, chptr->chname, acptr->name, chptr->creationtime);
+           }
+           if ((lp2->flags & MODE_HALFOP))
+           {
+               lp2->flags &= ~MODE_HALFOP;
+
+               acptr = lp2->value.cptr;
+
+               sendto_channel_butserv(chptr, cptr, ":%s MODE %s -h %s", me.name, chptr->chname, acptr->name);
+               sendto_serv_butone_sjoin(cptr, ":%s MODE %s -h %s %lu", me.name, chptr->chname, acptr->name, chptr->creationtime);
+           }
+           if ((lp2->flags & MODE_CHANOWNER)) {
+               lp2->flags &= ~MODE_CHANOWNER;
+
+               acptr = lp2->value.cptr;
+
+               sendto_channel_butserv(chptr, cptr, ":%s MODE %s -q %s", me.name, chptr->chname, acptr->name);
+               sendto_serv_butone_sjoin(cptr, ":%s MODE %s -q %s %lu", me.name, chptr->chname, acptr->name, chptr->creationtime);
+           }
+           if ((lp2->flags & MODE_CHANPROT)) {
+               lp2->flags &= ~MODE_CHANPROT;
+
+               acptr = lp2->value.cptr;
+
+               sendto_channel_butserv(chptr, cptr, ":%s MODE %s -a %s", me.name, chptr->chname, acptr->name);
+               sendto_serv_butone_sjoin(cptr, ":%s MODE %s -a %s %lu", me.name, chptr->chname, acptr->name, chptr->creationtime);
+           }
+       }
+    }
+    /* Ok - it should now all be wiped so lets see what they have to offer us */
+    /* t points to parv[5], nick list 
+     * f is 1 to begin with.
+     * c is 0 to begin with.
+     * bp points to buf. 
+     */
+
+    while (*t != '\0')
+    {
+       if (*t == ' ')
+       {
+               if (f)
+                       strncpyzt(bp, (t - c), (c + 1));        /* Put the nick in bp */
+               else
+                       strncpyzt(bp, (t - (c - 1)), c);        /* Put the nick in bp */
+
+           
+               i = 0;
+               ns = 0;
+               for (p = bp; *p; p++)
+               {
+                       if (*p == '@')
+                       {
+                               ns |= FL_CHANOP;
+                               i++;
+                       }
+                       else if (*p == '+')
+                       {
+                               ns |= FL_VOICE; i++;
+                       }
+                       else if (*p == '%')
+                       {
+                               ns |= FL_HALFOP; i++;
+                       }
+                       else if (*p == '*')
+                       {
+                               ns |= FL_FOUNDER; i++;
+                       }
+                       else if (*p == '~')
+                       {
+                               ns |= FL_PROT; i++;
+                       } else
+                               break;
+               }
+               if (i != 0)
+                       strncpyzt(nick, bp + i, c);
+               else
+                       strncpyzt(nick, bp, (c+1));
+               if (!(acptr = find_client(nick, NULL)))
+               {
+                   /* The client doesn't exist, probably Killed off for some reason, this is
+                    * ok, we will just ignore it 
+                    */
+                   /* horrible, horrible thing to do, but this while loop needs rewriting anyhow */
+                   sendto_realops("Missing user %s in SJOIN at %s !", nick, chptr->chname);
+                   goto bad_nick_jump;
+
+               }
+               /* ok, now, is this an evil nick (ie, one on our side), or a good one,
+                * ie, one on the other side?
+                */
+               /* sptr = server who is sending the SJOIN */
+               tempptr = acptr;
+
+               while (tempptr != &me && tempptr != sptr)
+                   tempptr = tempptr->srvptr;
+
+               if (tempptr == &me)
+               {
+                   /* this nick is an evil nick, since its on my
+                    * side... ignore this nick.
+                    */
+                   /* horrible, horrible thing to do, but this while loop needs rewriting anyhow */
+                   goto bad_nick_jump;
+               }
+               fl = 0;
+                   if (ns & FL_CHANOP)
+                       fl |= CHFL_CHANOP;
+                   if (ns & FL_VOICE)
+                       fl |= CHFL_VOICE;
+                   if (ns & FL_HALFOP)
+                       fl |= CHFL_HALFOP;
+                   if (ns & FL_FOUNDER)
+                       fl |= CHFL_CHANOWNER;
+                   if (ns & FL_PROT)
+                    fl |= CHFL_CHANPROT;
+               if (!IsMember(acptr, chptr)) 
+               {
+                   /* Its not really possible for the user to be a member of this
+                    * channel already, unless something is broken, but its not
+                    * too bad checking for this, just in case 
+                    */
+                          add_user_to_channel(chptr, acptr, fl);
+                          if (!IsHiding(acptr))
+                                  sendto_channel_butserv(chptr, acptr, ":%s JOIN :%s", nick, parv[2]);     
+                   sendto_serv_butone_sjoin(cptr, ":%s JOIN :%s", nick, parv[2]);
+               }
+               
+               lp = find_user_link(chptr->members, acptr);
+
+               if (!lp)
+                   sendto_ops("WARNING! possible desynch from %s in %s", nick, chptr->chname);
+
+               synchptr = make_synchlist();
+
+               strncpyzt(synchptr->nick, nick, sizeof(synchptr->nick));
+               
+                       if (ns & FL_VOICE)
+                                       synchptr->voice = 1;
+                       if (ns & FL_HALFOP)
+                                       synchptr->half = 1;
+                       if (ns & FL_CHANOP)
+                                       synchptr->op = 1;
+                       if (ns & FL_PROT)
+                                       synchptr->prot = 1;
+                       if (ns & FL_FOUNDER)
+                                       synchptr->own = 1;
+
+               if (SJSynchList == NULL)
+                   SJSynchList = synchptr;
+               else
+               {
+                   SJSynchList->prev = synchptr;
+                   synchptr->next = SJSynchList;
+                   SJSynchList = synchptr;
+               }
+bad_nick_jump:
+           tc++;
+           c = f = fl = 0;
+       }
+       t++;
+       c++;
+    } 
+
+    /* Ok, we parsed the nicks, we made them join. Time to set their modes -GZ */
+
+    xsend = 0;
+
+    if (!susp_ts)
+    {
+       if (SJSynchList == NULL)
+           goto EndMode;
+
+       modebuf[1] = '\0';
+       parabuf[0] = '\0';
+       modebuf[0] = '+';
+
+       xsend = 0;
+
+       for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3)
+       {
+
+           synchptr3 = synchptr2->next;
+
+           if ((synchptr2->op)) {
+               strcat(modebuf, "o");
+               strcat(parabuf, synchptr2->nick);
+               strcat(parabuf, " ");
+               xsend++;
+
+               if (xsend == RESYNCMODES) {
+                   strcat(modebuf, "\0");
+                   strcat(parabuf, "\0");
+
+                   sendto_channel_butserv(chptr, cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf);
+                   sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf, chptr->creationtime);
+
+                   modebuf[1] = '\0';
+                   parabuf[0] = '\0';
+                   modebuf[0] = '+';
+                   xsend = 0;
+               }
+           }
+       }
+
+       if (SJSynchList == NULL)
+           goto EndMode;
+
+       for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+           synchptr3 = synchptr2->next;
+
+           if ((synchptr2->voice)) {
+               strcat(modebuf, "v");
+               strcat(parabuf, synchptr2->nick);
+               strcat(parabuf, " ");
+               xsend++;
+
+               if (xsend == RESYNCMODES) {
+                   strcat(modebuf, "\0");
+                   strcat(parabuf, "\0");
+
+                   sendto_channel_butserv(chptr, cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf);
+                   sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf, chptr->creationtime);
+
+                   modebuf[1] = '\0';
+                   parabuf[0] = '\0';
+                   modebuf[0] = '+';
+
+                   xsend = 0;
+               }
+           }
+       }
+
+       if (SJSynchList == NULL)
+           goto EndMode;
+
+       for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+           synchptr3 = synchptr2->next;
+
+           if ((synchptr2->half)) {
+               strcat(modebuf, "h");
+               strcat(parabuf, synchptr2->nick);
+               strcat(parabuf, " ");
+               xsend++;
+
+               if (xsend == RESYNCMODES) {
+                   strcat(modebuf, "\0");
+                   strcat(parabuf, "\0");
+
+                   sendto_channel_butserv(chptr, cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf);
+                   sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf, chptr->creationtime);
+
+                   modebuf[1] = '\0';
+                   parabuf[0] = '\0';
+                   modebuf[0] = '+';
+
+                   xsend = 0;
+               }
+           }
+       }
+
+       if (SJSynchList == NULL)
+           goto EndMode;
+
+
+       for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+           synchptr3 = synchptr2->next;
+
+           if ((synchptr2->own)) {
+               strcat(modebuf, "q");
+               strcat(parabuf, synchptr2->nick);
+               strcat(parabuf, " ");
+               xsend++;
+
+               if (xsend == RESYNCMODES) {
+                   strcat(modebuf, "\0");
+                   strcat(parabuf, "\0");
+
+                   sendto_channel_butserv(chptr, cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf);
+                   sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf, chptr->creationtime);
+
+                   modebuf[1] = '\0';
+                   parabuf[0] = '\0';
+                   modebuf[0] = '+';
+
+                   xsend = 0;
+               }
+           }
+       }
+
+       if (SJSynchList == NULL)
+           goto EndMode;
+
+       for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+           synchptr3 = synchptr2->next;
+
+           if ((synchptr2->prot)) {
+               strcat(modebuf, "a");
+               strcat(parabuf, synchptr2->nick);
+               strcat(parabuf, " ");
+               xsend++;
+
+               if (xsend == RESYNCMODES) {
+                   strcat(modebuf, "\0");
+                   strcat(parabuf, "\0");
+
+                   sendto_channel_butserv(chptr, cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf);
+                   sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf, chptr->creationtime);
+
+                   modebuf[1] = '\0';
+                   parabuf[0] = '\0';
+                   modebuf[0] = '+';
+
+                   xsend = 0;
+               }
+           }
+       }
+
+       if (SJSynchList == NULL)
+           goto EndMode;
+
+    }
+    /* Ok! all done, time to clean up the mess */
+
+    for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+       synchptr3 = synchptr2->next;
+
+       if (synchptr2->prev)
+           synchptr2->prev->next = synchptr2->next;
+       else
+           SJSynchList = synchptr2->next;
+       if (synchptr2->next)
+           synchptr2->next->prev = synchptr2->prev;
+       free_synchlist(synchptr2);
+
+    }
+
+  EndMode:
+       if (xsend) {
+           sendto_channel_butserv(chptr, cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf);
+           sendto_serv_butone_sjoin(cptr, ":%s MODE %s %s %s", cptr->name, chptr->chname, modebuf, parabuf, chptr->creationtime);
+       }
+
+    /* After all is done, synch timestamps as channels should now be identical */
+
+    if (!(ts > chptr->creationtime) && !susp_ts)
+       chptr->creationtime = ts;
+
+    else if (chptr->creationtime == 0 && ts > 0)
+       chptr->creationtime = ts;
+
+    /* And we are desynched! - kidding! - *whew!* */
+    if (oldts != -1)
+           if (oldts != ts)
+                    sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :*** Notice -- TS for %s changed from %ld to %ld",
+                                         me.name, chptr->chname, chptr->chname, oldts, ts);
+
+    sendto_serv_sjoin(cptr, ":%s SJOIN %s %s %s %s :%s", parv[0], parv[1], parv[2], parv[3], parv[4], parv[5]);
+
+    return 0;
+}
+
+/* 
+ * This will send "cptr" a full list of the modes for channel chptr,
+ */
+
+void send_channel_modes_sjoin(cptr, chptr)
+    aClient *cptr;
+    aChannel *chptr;
+{
+
+    Link *members;
+    Reg1 Link *lp;
+    Reg2 char *name;
+    char *bufptr;
+
+    int n = 0;
+
+    if (*chptr->chname != '#')
+       return;
+
+    members = chptr->members;
+
+    /* First we'll send channel, channel modes and members and status */
+
+    *modebuf = *parabuf = '\0';
+    channel_modes(cptr, modebuf, parabuf, chptr);
+
+    if (*parabuf)
+       strcat(parabuf, " ");
+    else
+    {
+       if (!SupportSJOIN2(cptr))
+               strcpy(parabuf, "<none>");
+       else
+               strcpy(parabuf, "<->");
+    }
+    sprintf(buf, "%s %ld %s %s %s :",
+               (IsToken(cptr) ? TOK_SJOIN : MSG_SJOIN),
+           chptr->creationtime,
+           chptr->chname, modebuf, parabuf);
+
+    bufptr = buf + strlen(buf);
+
+    for (lp = members; lp; lp = lp->next) {
+
+       if (lp->flags & MODE_CHANOP)
+           *bufptr++ = '@';
+
+       if (lp->flags & MODE_VOICE)
+           *bufptr++ = '+';
+
+       if (lp->flags & MODE_HALFOP)
+           *bufptr++ = '%';
+       if (lp->flags & MODE_CHANOWNER)
+           *bufptr++ = '*';
+       if (lp->flags & MODE_CHANPROT)
+           *bufptr++ = '~';
+
+
+
+       name = lp->value.cptr->name;
+
+       strcpy(bufptr, name);
+       bufptr += strlen(bufptr);
+       *bufptr++ = ' ';
+       n++;
+
+       if (bufptr - buf > BUFSIZE - 80) {
+           *bufptr++ = '\0';
+           if (bufptr[-1] == ' ')
+               bufptr[-1] = '\0';
+           sendto_one(cptr, "%s", buf);
+
+           sprintf(buf, "%s %ld %s %s %s :", (IsToken(cptr) ? TOK_SJOIN : MSG_SJOIN),
+                   chptr->creationtime,
+                   chptr->chname, modebuf, parabuf);
+           n = 0;
+
+           bufptr = buf + strlen(buf);
+       }
+    }
+
+    if (n) {
+       *bufptr++ = '\0';
+       if (bufptr[-1] == ' ')
+           bufptr[-1] = '\0';
+       sendto_one(cptr, "%s", buf);
+    }
+    /* Then we'll send the ban-list */
+
+    *parabuf = '\0';
+    *modebuf = '+';
+    modebuf[1] = '\0';
+ // fixme
+//    send_ban_list(cptr, chptr->chname, chptr->creationtime, chptr->banlist);
+
+    if (modebuf[1] || *parabuf)
+       sendto_one(cptr, ":%s MODE %s %s %s", me.name, chptr->chname, modebuf, parabuf);
+
+    return;
+}
diff --git a/src/chkconf.c b/src/chkconf.c
new file mode 100644 (file)
index 0000000..55f8504
--- /dev/null
@@ -0,0 +1,812 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/chkconf.c
+ *   Copyright (C) 1993 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef __hpux
+#include "inet.h"
+#endif
+#ifdef PCS
+#include <time.h>
+#endif
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1993 Darren Reed");
+ID_Notes("DF version was 1.9 1/30/94");
+
+#ifdef DYNIXPTX
+#include <sys/types.h>
+#include <time.h>
+#endif
+
+/* for the connect rule patch..  these really should be in a header,
+** but i see h.h isn't included for some reason..  so they're here */
+char *crule_parse PROTO((char *rule));
+void crule_free PROTO((char **elem));
+
+#undef free
+#define        MyMalloc(x)     malloc(x)
+
+static void    new_class();
+static char    *getfield(), confchar ();
+static int     openconf(), validate();
+static aClass  *get_class();
+static aConfItem       *initconf();
+
+static int     numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
+static char    *configfile = CONFIGFILE;
+static char    nullfield[] = "";
+static char    maxsendq[12];
+
+main(argc, argv)
+int    argc;
+char   *argv[];
+{
+       new_class(0);
+
+       if (chdir(DPATH))
+           {
+               perror("chdir");
+               exit(-1);
+           }
+       if (argc > 1 && !strncmp(argv[1], "-d", 2))
+           {
+               debugflag = 1;
+               if (argv[1][2])
+                       debugflag = atoi(argv[1]+2);
+               argc--, argv++;
+           }
+       if (argc > 1)
+               configfile = argv[1];
+       return validate(initconf());
+}
+
+/*
+ * openconf
+ *
+ * returns -1 on any error or else the fd opened from which to read the
+ * configuration file from.  This may either be th4 file direct or one end
+ * of a pipe from m4.
+ */
+static int     openconf()
+{
+#ifdef M4_PREPROC
+       int     pi[2];
+
+       if (pipe(pi) == -1)
+               return -1;
+       switch(fork())
+       {
+       case -1 :
+               return -1;
+       case 0 :
+               (void)close(pi[0]);
+               if (pi[1] != 1)
+                   {
+                       (void)dup2(pi[1], 1);
+                       (void)close(pi[1]);
+                   }
+               (void)dup2(1,2);
+               /*
+                * m4 maybe anywhere, use execvp to find it.  Any error
+                * goes out with report_error.  Could be dangerous,
+                * two servers running with the same fd's >:-) -avalon
+                */
+               (void)execlp("m4", "m4", "ircd.m4", configfile, 0);
+               perror("m4");
+               exit(-1);
+       default :
+       }
+               (void)close(pi[1]);
+               return pi[0];
+
+#else
+       return open(configfile, O_RDONLY);
+#endif
+}
+
+#define STAR1 OFLAG_SADMIN|OFLAG_ADMIN|OFLAG_NETADMIN|OFLAG_COADMIN
+#define STAR2 OFLAG_TECHADMIN|OFLAG_ZLINE|OFLAG_AGENT|OFLAG_HIDE|OFLAG_WHOIS
+static int oper_access[] = {
+    ~(STAR1|STAR2), '*',
+       OFLAG_LOCAL,    'o',
+       OFLAG_GLOBAL,   'O',
+       OFLAG_REHASH,   'r',
+       OFLAG_EYES,     'e',
+       OFLAG_DIE,      'D',
+       OFLAG_RESTART,  'R',
+       OFLAG_HELPOP,   'h',
+       OFLAG_GLOBOP,   'g',
+       OFLAG_WALLOP,   'w',
+       OFLAG_LOCOP,    'l',
+       OFLAG_LROUTE,   'c',
+       OFLAG_GROUTE,   'L',
+       OFLAG_LKILL,    'k',
+       OFLAG_GKILL,    'K',
+       OFLAG_KLINE,    'b',
+       OFLAG_UNKLINE,  'B',
+       OFLAG_LNOTICE,  'n',
+       OFLAG_GNOTICE,  'G',
+       OFLAG_ADMIN,    'A',
+       OFLAG_SADMIN,   'a',
+       OFLAG_NETADMIN, 'N',
+       OFLAG_COADMIN,  'C',
+       OFLAG_TECHADMIN, 'T',
+       OFLAG_UMODEC,   'u',
+       OFLAG_UMODEF,   'f',
+       OFLAG_ZLINE,    'z',
+       OFLAG_WHOIS,    'W',
+    OFLAG_HIDE,     'H',
+    OFLAG_AGENT,       'S',
+       0, 0 };
+
+
+/*
+** initconf() 
+**    Read configuration file.
+**
+**    returns -1, if file cannot be opened
+**             0, if file opened
+*/
+
+static aConfItem       *initconf(opt)
+int    opt;
+{
+       int     fd;
+       char    line[512], *tmp, c[80], *s, *crule;
+       int     ccount = 0, ncount = 0, dh, flags = 0;
+       int     lineno;
+       aConfItem *aconf = NULL, *ctop = NULL;
+
+       (void)fprintf(stderr, "initconf(): ircd.conf = %s\n", configfile);
+       if ((fd = openconf()) == -1)
+           {
+#ifdef M4_PREPROC
+               (void)wait(0);
+#endif
+               return NULL;
+           }
+
+        lineno = 1;
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       while ((dh = dgets(fd, line, sizeof(line) - 1)) > 0)
+           {
+                printf("%u:    End of file\r",lineno++);
+               if (aconf)
+                   {
+                       if (aconf->host)
+                               (void)free(aconf->host);
+                       if (aconf->passwd)
+                               (void)free(aconf->passwd);
+                       if (aconf->name)
+                               (void)free(aconf->name);
+                   }
+               else
+                       aconf = (aConfItem *)malloc(sizeof(*aconf));
+               aconf->host = (char *)NULL;
+               aconf->passwd = (char *)NULL;
+               aconf->name = (char *)NULL;
+               aconf->class = (aClass *)NULL;
+               if (tmp = (char *)index(line, '\n'))
+                       *tmp = 0;
+               else while(dgets(fd, c, sizeof(c) - 1))
+                       if (tmp = (char *)index(c, '\n'))
+                           {
+                               *tmp = 0;
+                               break;
+                           }
+               /*
+                * Do quoting of characters and # detection.
+                */
+               for (tmp = line; *tmp; tmp++)
+                   {
+                       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++;
+                           }
+                       else if (*tmp == '#')
+                               *tmp = '\0';
+                   }
+               if (!*line || *line == '#' || *line == '\n' ||
+                   *line == ' ' || *line == '\t')
+                       continue;
+               if (*line == 'X' || *line == 'T')
+                       continue;
+               if (*line == 'x' || *line == 't')
+                       continue;
+
+               if (line[1] != ':')
+                   {
+                        (void)fprintf(stderr, "ERROR: Bad config line (%s)\n",
+                               line);
+                        continue;
+                    }
+
+               if (debugflag)
+                       (void)printf("\n%s\n",line);
+               (void)fflush(stdout);
+
+               tmp = getfield(line);
+               if (!tmp)
+                   {
+                        (void)fprintf(stderr, "\tERROR: no fields found\n");
+                       continue;
+                   }
+
+               aconf->status = CONF_ILLEGAL;
+
+               switch (*tmp)
+               {
+                       case 'A': /* Name, e-mail address of administrator */
+                               aconf->status = CONF_ADMIN;
+                               break;
+                       case 'a': /* of this server. */
+                               aconf->status = CONF_SADMIN;
+                               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 ircd.conf */
+                       case 'k':
+                               aconf->status = CONF_KILL;
+                               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)
+                        * Not anymore, OperFlag access levels. -Cabal95 */
+                       case 'o':
+                               aconf->status = CONF_OPERATOR;
+                               break;
+                       case 'P': /* listen port line */
+                       case 'p':
+                               aconf->status = CONF_LISTEN_PORT;
+                               break;
+                       case 'Q': /* a server that you don't want in your */
+                       case 'q': /* network. USE WITH CAUTION! */
+                               aconf->status = CONF_QUARANTINED_SERVER;
+                               break;
+                       case 'S': /* Service. Same semantics as   */
+                       case 's': /* CONF_OPERATOR                */
+                               aconf->status = CONF_SERVICE;
+                               break;
+                       case 'U':
+                       case 'u':
+                               aconf->status = CONF_UWORLD;
+                               break;
+                       case 'Y':
+                       case 'y':
+                               aconf->status = CONF_CLASS;
+                               break;
+                       case 'Z':
+                       case 'z':
+                               aconf->status = CONF_ZAP;
+                               break;
+                   default:
+                       (void)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 */
+                   {
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       DupString(aconf->host, tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       DupString(aconf->passwd, tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       DupString(aconf->name, tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       if (aconf->status & CONF_OPERATOR) {
+                         int   *i, flag;
+                         char  *m = "*";
+                         /*
+                          * Now we use access flags to define  
+                          * what an operator can do with their O.   
+                          */
+                         for (m = (*tmp) ? tmp : m; *m; m++) {
+                           for (i = oper_access; (flag = *i); i += 2)
+                             if (*m == (char)(*(i+1))) {
+                               aconf->port |= flag;
+                               break;
+                             }
+                           if (flag == 0)
+                             fprintf(stderr,
+                               "\tWARNING: Unknown oper access level '%c'\n",
+                               *m);  
+                         }
+                         if (!(aconf->port&OFLAG_ISGLOBAL))
+                               aconf->status = CONF_LOCOP;
+                       }
+                       else
+                               aconf->port = atoi(tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       if (!(aconf->status & CONF_CLASS))
+                               aconf->class = get_class(atoi(tmp));
+                       break;
+                   }
+               if (!aconf->class && (aconf->status & (CONF_CONNECT_SERVER|
+                    CONF_NOCONNECT_SERVER|CONF_OPS|CONF_CLIENT)))
+                   {
+                       (void)fprintf(stderr,
+                               "\tWARNING: No class.  Default 0\n");
+                       aconf->class = get_class(0);
+                   }
+               /* Check for bad Z-lines */
+               if (aconf->status == CONF_ZAP)
+               {
+                       char *tempc = aconf->host;
+                       if (!tempc)
+                       {
+                               fprintf(stderr, "\tERROR: Bad Z-line\n");
+                       }
+                       for (; *tempc; tempc++)
+                               if ((*tempc >= '0') && (*tempc <= '9'))
+                                       goto zap_safe;
+                       fprintf(stderr, "\tERROR: Z-line mask too broad\n");
+                       zap_safe:;
+               }
+               /*
+                ** 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)
+                   {
+                       int     class = 0;
+
+                       if (!aconf->host)
+                           {
+                               (void)fprintf(stderr,"\tERROR: no class #\n");
+                               continue;
+                           }
+                       if (!tmp)
+                           {
+                               (void)fprintf(stderr,
+                                       "\tWARNING: missing sendq field\n");
+                               (void)fprintf(stderr, "\t\t default: %d\n",
+                                       MAXSENDQLENGTH);
+                               (void)sprintf(maxsendq, "%d", MAXSENDQLENGTH);
+                           }
+                       else
+                               (void)sprintf(maxsendq, "%d", atoi(tmp));
+                       new_class(atoi(aconf->host));
+                       aconf->class = get_class(atoi(aconf->host));
+                       goto print_confline;
+                   }
+
+               if (aconf->status & CONF_LISTEN_PORT)
+                   {
+                       if (!aconf->host)
+                               (void)fprintf(stderr, "\tERROR: %s\n",
+                                       "null host field in P-line");
+                       else if (index(aconf->host, '/'))
+                               (void)fprintf(stderr, "\t%s %s\n",
+                                       "WARNING: / present in P-line", 
+                                       "for non-UNIXPORT configuration");
+                       aconf->class = get_class(0);
+                       goto print_confline;
+                   }
+
+               if (aconf->status & CONF_SERVER_MASK &&
+                   (!aconf->host || index(aconf->host, '*') ||
+                    index(aconf->host, '?')))
+                   {
+                       (void)fprintf(stderr, "\tERROR: bad host field\n");
+                       continue;
+                   }
+
+               if (aconf->status & CONF_SERVER_MASK && BadPtr(aconf->passwd))
+                   {
+                       (void)fprintf(stderr,
+                                       "\tERROR: empty/no password field\n");
+                       continue;
+                   }
+
+               if (aconf->status & CONF_SERVER_MASK && !aconf->name)
+                   {
+                       (void)fprintf(stderr, "\tERROR: bad name field\n");
+                       continue;
+                   }
+
+               if (aconf->status & (CONF_SERVER_MASK|CONF_OPS))
+                       if (!index(aconf->host, '@'))
+                           {
+                               char    *newhost;
+                               int     len = 3;        /* *@\0 = 3 */
+
+                               len += strlen(aconf->host);
+                               newhost = (char *)MyMalloc(len);
+                               (void)sprintf(newhost, "*@%s", aconf->host);
+                               (void)free(aconf->host);
+                               aconf->host = newhost;
+                           }
+
+               /* parse the connect rules to detect errors, but free
+               ** any allocated storage immediately -- we're just looking
+               ** for errors..  */
+               if (aconf->status & CONF_CRULE)
+                  if ((crule =
+                       (char *) crule_parse (aconf->name)) != NULL)
+                   crule_free (&crule);
+
+               if (!aconf->class)
+                       aconf->class = get_class(0);
+               (void)sprintf(maxsendq, "%d", aconf->class->class);
+
+               if (!aconf->name)
+                       aconf->name = nullfield;
+               if (!aconf->passwd)
+                       aconf->passwd = nullfield;
+               if (!aconf->host)
+                       aconf->host = nullfield;
+               if (aconf->status & (CONF_ME|CONF_ADMIN))
+                   {
+                       if (flags & aconf->status)
+                               (void)fprintf(stderr,
+                                       "ERROR: multiple %c-lines\n",
+                                       toupper(confchar(aconf->status)));
+                       else
+                               flags |= aconf->status;
+                   }
+print_confline:
+               if (debugflag > 8)
+                       (void)printf("(%d) (%s) (%s) (%s) (%d) (%s)\n",
+                             aconf->status, aconf->host, aconf->passwd,
+                             aconf->name, aconf->port, maxsendq);
+               (void)fflush(stdout);
+               if (aconf->status & (CONF_SERVER_MASK|CONF_HUB|CONF_LEAF))
+                   {
+                       aconf->next = ctop;
+                       ctop = aconf;
+                       aconf = NULL;
+                   }
+           }
+        printf("\n");
+       (void)close(fd);
+#ifdef M4_PREPROC
+       (void)wait(0);
+#endif
+       return ctop;
+}
+
+static aClass  *get_class(cn)
+int    cn;
+{
+       static  aClass  cls;
+       int     i = numclasses - 1;
+
+       cls.class = -1;
+       for (; i >= 0; i--)
+               if (classarr[i] == cn)
+                   {
+                       cls.class = cn;
+                       break;
+                   }
+       if (i == -1)
+               (void)fprintf(stderr,"\tWARNING: class %d not found\n", cn);
+       return &cls;
+}
+
+static void    new_class(cn)
+int    cn;
+{
+       numclasses++;
+       if (classarr)
+               classarr = (int *)realloc(classarr, sizeof(int) * numclasses);
+       else
+               classarr = (int *)malloc(sizeof(int));
+       classarr[numclasses-1] = cn;
+}
+
+/*
+ * field breakup for ircd.conf file.
+ */
+static char    *getfield(newline)
+char   *newline;
+{
+       static  char *line = NULL;
+       char    *end, *field;
+       
+       if (newline)
+               line = newline;
+       if (line == NULL)
+               return(NULL);
+
+       field = line;
+       if ((end = (char *)index(line,':')) == NULL)
+           {
+               line = NULL;
+               if ((end = (char *)index(field,'\n')) == NULL)
+                       end = field + strlen(field);
+           }
+       else
+               line = end + 1;
+       *end = '\0';
+       return(field);
+}
+
+
+/*
+** read a string terminated by \r or \n in from a fd
+**
+** Created: Sat Dec 12 06:29:58 EST 1992 by avalon
+** Returns:
+**     0 - EOF
+**     -1 - error on read
+**     >0 - number of bytes returned (<=num)
+** After opening a fd, it is necessary to init dgets() by calling it as
+**     dgets(x,y,0);
+** to mark the buffer as being empty.
+*/
+int    dgets(fd, buf, num)
+int    fd, num;
+char   *buf;
+{
+       static  char    dgbuf[8192];
+       static  char    *head = dgbuf, *tail = dgbuf;
+       register char   *s, *t;
+       register int    n, nr;
+
+       /*
+       ** Sanity checks.
+       */
+       if (head == tail)
+               *head = '\0';
+       if (!num)
+           {
+               head = tail = dgbuf;
+               *head = '\0';
+               return 0;
+           }
+       if (num > sizeof(dgbuf) - 1)
+               num = sizeof(dgbuf) - 1;
+dgetsagain:
+       if (head > dgbuf)
+           {
+               for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
+                       *t++ = *s++;
+               tail = t;
+               head = dgbuf;
+           }
+       /*
+       ** check input buffer for EOL and if present return string.
+       */
+       if (head < tail &&
+           ((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail)
+           {
+               n = MIN(s - head + 1, num);     /* at least 1 byte */
+dgetsreturnbuf:
+               bcopy(head, buf, n);
+               head += n;
+               if (head == tail)
+                       head = tail = dgbuf;
+               return n;
+           }
+
+       if (tail - head >= num)         /* dgets buf is big enough */
+           {
+               n = num;
+               goto dgetsreturnbuf;
+           }
+
+       n = sizeof(dgbuf) - (tail - dgbuf) - 1;
+       nr = read(fd, tail, n);
+       if (nr == -1)
+           {
+               head = tail = dgbuf;
+               return -1;
+           }
+       if (!nr)
+           {
+               if (head < tail)
+                   {
+                       n = MIN(head - tail, num);
+                       goto dgetsreturnbuf;
+                   }
+               head = tail = dgbuf;
+               return 0;
+           }
+       tail += nr;
+       *tail = '\0';
+       for (t = head; (s = index(t, '\n')); )
+           {
+               if ((s > head) && (s > dgbuf))
+                   {
+                       t = s-1;
+                       for (nr = 0; *t == '\\'; nr++)
+                               t--;
+                       if (nr & 1)
+                           {
+                               t = s+1;
+                               s--;
+                               nr = tail - t;
+                               while (nr--)
+                                       *s++ = *t++;
+                               tail -= 2;
+                               *tail = '\0';
+                           }
+                       else
+                               s++;
+                   }
+               else
+                       s++;
+               t = s;
+           }
+       *tail = '\0';
+       goto dgetsagain;
+}
+
+
+static int     validate(top)
+aConfItem *top;
+{
+       Reg1    aConfItem *aconf, *bconf;
+       u_int   otype, valid = 0;
+
+       if (!top)
+               return 0;
+
+       for (aconf = top; aconf; aconf = aconf->next)
+           {
+               if (aconf->status & CONF_MATCH)
+                       continue;
+
+               if (aconf->status & CONF_SERVER_MASK)
+                   {
+                       if (aconf->status & CONF_CONNECT_SERVER)
+                               otype = CONF_NOCONNECT_SERVER;
+                       else if (aconf->status & CONF_NOCONNECT_SERVER)
+                               otype = CONF_CONNECT_SERVER;
+
+                       for (bconf = top; bconf; bconf = bconf->next)
+                           {
+                               if (bconf == aconf || !(bconf->status & otype))
+                                       continue;
+                               if (bconf->class == aconf->class &&
+                                   !mycmp(bconf->name, aconf->name) &&
+                                   !mycmp(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 (!mycmp(bconf->name, aconf->name))
+                                   {
+                                       aconf->status |= CONF_MATCH;
+                                       break;
+                                   }
+                           }
+           }
+
+       (void) fprintf(stderr, "\n");
+       for (aconf = top; aconf; aconf = aconf->next)
+               if (aconf->status & CONF_MATCH)
+                       valid++;
+               else
+                       (void)fprintf(stderr, "Unmatched %c:%s:%s:%s\n",
+                               confchar(aconf->status), aconf->host,
+                               aconf->passwd, aconf->name);
+       return valid ? 0 : -1;
+}
+
+static char    confchar(status)
+u_int  status;
+{
+       static  char    letrs[] = "QICNoOMKARYSLPHXT";
+       char    *s = letrs;
+
+       status &= ~(CONF_MATCH|CONF_ILLEGAL);
+
+       for (; *s; s++, status >>= 1)
+               if (status & 1)
+                       return *s;
+       return '-';
+}
+
+outofmemory()
+{
+       (void)write(2, "Out of memory\n", 14);
+       exit(-1);
+}
+
+
diff --git a/src/cio_init.c b/src/cio_init.c
new file mode 100644 (file)
index 0000000..516c39f
--- /dev/null
@@ -0,0 +1,32 @@
+#include <windows.h>
+#include "Cio.h"
+#include "CioFunc.h"
+#include "common.h"
+ID_CVS("$Id$");
+
+//
+//  FUNCTION: Cio_Init(void)
+//
+//  PURPOSE: Initializes window data and registers window class and other stuff
+//
+BOOL Cio_Init(HINSTANCE hInstance)
+{
+    WNDCLASS  wc;
+
+    // Fill in window class structure with parameters that describe
+    // the main window.
+    wc.style         = CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc   = (WNDPROC)Cio_WndProc;
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 4;
+    wc.hInstance     = hInstance;
+    wc.hIcon         = NULL;
+    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE);
+       wc.lpszMenuName  = NULL;
+    wc.lpszClassName = CIOCLASS;
+
+    if ( !RegisterClass(&wc) ) return FALSE;
+
+    return TRUE;
+}
diff --git a/src/cio_main.c b/src/cio_main.c
new file mode 100644 (file)
index 0000000..24d7e5d
--- /dev/null
@@ -0,0 +1,836 @@
+#include <windows.h>
+#include <memory.h>
+#include <stdio.h>
+#include <crtdbg.h>
+#include "Cio.h"
+#include "CioFunc.h"
+#include "common.h"
+ID_CVS("$Id$");
+
+CioLine        *CioMakeLine(CioLine *Prev, CioLine *Next)
+{
+       CioLine *Line;
+
+       Line = LocalAlloc(LPTR, sizeof(CioLine));
+       _ASSERT(Line);
+       if ( Prev )
+           {
+               Prev->Next = Line;
+               Line->Prev = Prev;
+           }
+       if ( Next )
+           {
+               Next->Prev = Line;
+               Line->Next = Next;
+           }
+
+       return Line;
+}
+
+
+void   CioRemoveLine(CioWndInfo *CWI, CioLine *Line)
+{
+       if ( Line->Next )
+               Line->Next->Prev = Line->Prev;
+       if ( Line->Prev )
+               Line->Prev->Next = Line->Next;
+       else
+               CWI->FirstLine = Line->Next;
+
+       if ( Line->Data )
+               LocalFree(Line->Data);
+       LocalFree(Line);
+}
+
+
+
+//
+//   FUNCTION: Cio_Create(HANDLE, HWND, DWORD, int, int, int, int)
+//
+//   PURPOSE: Creates main CIO window
+//
+HWND Cio_Create(HINSTANCE hInstance, HWND hParent, DWORD Style, int X, int Y, int W, int H)
+{
+       HWND    hWnd;
+
+       if ( hParent == NULL )
+               return NULL;
+
+       hWnd = CreateWindow(CIOCLASS, NULL, WS_CHILD | WS_VSCROLL | Style,
+               X, Y, W, H, hParent, NULL, hInstance, NULL);
+
+       return hWnd;
+}
+
+
+//
+//  FUNCTION: Cio_WndProc(HWND, unsigned, WORD, LONG)
+//
+//  PURPOSE:  Processes messages for a CIO window.
+//
+LRESULT CALLBACK Cio_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       DWORD   Style;
+
+       switch (message)
+           {
+               case WM_CREATE:
+                       return Cio_WndCreate(hWnd);
+
+               case WM_RBUTTONDOWN: // RightClick in windows client area...
+                       return 0;
+
+               case WM_PAINT:
+                       return Cio_WndPaint(hWnd);
+
+               case WM_SIZE:
+                       Style = GetWindowLong(GetParent(hWnd), GWL_STYLE);
+                       if ( Style & WS_MINIMIZE )
+                               return 0;
+                       return Cio_WndSize(hWnd, lParam);
+
+               case WM_VSCROLL:
+                       return Cio_WndScroll(hWnd, wParam);
+
+               case WM_DESTROY:
+                       return Cio_WndDestroy(hWnd);
+
+               case WM_SETFONT:
+                       return Cio_SetFont(hWnd, wParam);
+
+               case CIO_ADDSTRING:
+                       return Cio_WndAddString(hWnd, wParam, (char *)lParam);
+
+               default:
+                       return (DefWindowProc(hWnd, message, wParam, lParam));
+           }
+       return (0);
+}
+
+
+BOOL Cio_WndCreate(HWND hWnd)
+{
+       CioWndInfo      *CWI;
+       LOGFONT         lfFont;
+       TEXTMETRIC      tm;
+       HDC     hdc;
+
+       CWI = LocalAlloc(LPTR, sizeof(CioWndInfo));
+       _ASSERT(CWI);
+       lfFont.lfHeight =         12;
+       lfFont.lfWidth =          0;
+       lfFont.lfEscapement =     0;
+       lfFont.lfOrientation =    0;
+       lfFont.lfWeight =         400;
+       lfFont.lfItalic =         0;
+       lfFont.lfUnderline =      0;
+       lfFont.lfStrikeOut =      0;
+       lfFont.lfCharSet =        ANSI_CHARSET;
+       lfFont.lfOutPrecision =   OUT_STRING_PRECIS;
+       lfFont.lfClipPrecision =  CLIP_STROKE_PRECIS;
+       lfFont.lfQuality =        DRAFT_QUALITY;
+       lfFont.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
+       wsprintf(lfFont.lfFaceName, "FixedSys");
+
+       CWI->hFont = CreateFontIndirect(&lfFont);
+
+       hdc = GetDC(hWnd);
+       SelectObject(hdc, CWI->hFont);
+       GetTextMetrics(hdc, &tm);
+       ReleaseDC(hWnd, hdc);
+
+       CWI->XChar = tm.tmAveCharWidth;
+       CWI->YChar = tm.tmHeight + tm.tmExternalLeading;
+
+       CWI->FirstLine = CWI->CurLine = CioMakeLine(NULL, NULL);
+       CWI->Lines=0;
+
+       SetWindowLong(hWnd, GWL_USER, (DWORD)CWI);
+
+       return 0;
+}
+
+
+BOOL Cio_WndPaint(HWND hWnd)
+{
+       PAINTSTRUCT     ps;
+       CioWndInfo      *CWI;
+       HDC     hdc;
+       HFONT   hOldFont;
+       CioLine *Line;
+       RECT    rect;
+       int     nCol, nEndCol, nMaxCol, nRow, nEndRow, nBegCol, nCount, i=0;
+       int     nVertPos, nHorzPos, nOff, nBegOff, NewColorAt=0;
+       BYTE    Red, Green, Blue, NewColor=0, UnderLine=0;
+       HPEN    hpen;
+
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+       hdc = BeginPaint(hWnd, &ps);
+
+       hOldFont = SelectObject(hdc, CWI->hFont);
+       rect = ps.rcPaint;
+       nCol    = max(0, rect.left / CWI->XChar);
+       nEndCol = rect.right / CWI->XChar;
+       nEndCol = min(CWI->Width, nEndCol+1);
+       nEndRow = max(0, rect.top / CWI->YChar);
+       nRow    = rect.bottom / CWI->YChar;
+       nRow    = min(CWI->Height, nRow+1);
+
+       nBegOff = nCol;
+       nBegCol = nCol;
+
+       /*
+        * Find the first line to use, and work up from there.
+        */
+       Line = CWI->FirstLine;
+       while ( Line && i < CWI->Scroll )
+           {
+               if ( Line->Data )
+                       i++;
+               Line = Line->Next;
+           }
+       i = 0;
+       while ( Line && i < (CWI->Height-nRow) )
+           {
+               if ( Line->Data )
+                       i++;
+               Line = Line->Next;
+           }   
+
+       for ( ; nRow >= nEndRow; nRow-- )
+           {
+               UnderLine=0;
+               while ( Line && !Line->Data )
+                       Line = Line->Next;
+               if ( !Line )
+                       continue;
+
+               nMaxCol = Line->Len;
+               nOff = nBegOff;
+               nCol = 0;
+               nCount = 0;
+               for ( i = 0; i < Line->Len; i++ )
+                   {
+                       if ( Line->Data[i] == 0 )
+                           {
+                               Red   = Line->Data[i+1];
+                               Green = Line->Data[i+2];
+                               Blue  = Line->Data[i+3];
+                               SetTextColor(hdc, RGB(Red, Green, Blue));
+                               SetBkColor(hdc, RGB(255, 255, 255));
+                               i += 3;
+                               nCol += 4;
+                               continue;
+                           }
+                       if ( nCount >= nBegCol )
+                               break;
+                       nCol++;
+                       nCount++;
+                   }
+               if ( i >= Line->Len )
+                       continue;
+
+               for ( ; nCol <= nMaxCol; nCol++ )
+                   {
+                       nCount = nMaxCol-nCol;
+                       for ( i = 0; i < (nMaxCol-nCol); i++ )
+                           {
+                               if ( Line->Data[nCol+i] == 0x1F )
+                                   {
+                                       nCount = i;
+                                       if ( UnderLine == 0 )
+                                           {
+                                               UnderLine = 1;
+                                               break;
+                                           }
+                                       if ( UnderLine == 1 )
+                                           {
+                                               UnderLine = 2;
+                                               break;
+                                           }
+                                       break;
+                                   }
+                               if ( Line->Data[nCol+i] == 0x0F )
+                                   {
+                                       nCount = i;
+                                       UnderLine = 0;
+                                       break;
+                                   }
+                               if ( Line->Data[nCol+i] == 0 )
+                                   {
+                                       NewColor = 1;
+                                       NewColorAt = nCol+i;
+                                       nCount = i;
+                                       i += 3;
+                                       break;
+                                   }
+                           }
+
+                       if ( nCount )
+                           {
+                               nVertPos = nRow * CWI->YChar - CWI->YChar +
+                                       CWI->YJunk;
+                               nHorzPos = nOff * CWI->XChar;
+                               rect.top    = nVertPos;
+                               rect.bottom = nVertPos + CWI->YChar;
+                               rect.left   = nHorzPos;
+                               rect.right  = nHorzPos + (CWI->XChar*nCount);
+                               SetBkMode(hdc, OPAQUE);
+
+                               ExtTextOut(hdc, nHorzPos, nVertPos, ETO_OPAQUE,
+                                       &rect, (LPSTR) Line->Data+nCol,
+                                       nCount, NULL);
+                               nOff += nCount;
+
+                               if ( UnderLine == 2 )
+                                   {
+                                       hpen = CreatePen(PS_SOLID, 0,
+                                               RGB(Red, Green, Blue));
+                                       SelectObject(hdc, hpen);
+                                       MoveToEx(hdc, (int)rect.left,
+                                               (int)rect.bottom-1,
+                                               (LPPOINT)NULL);
+                                       LineTo(hdc, (int)rect.right,
+                                               (int)rect.bottom-1);
+                                       DeleteObject(hpen);
+                                       UnderLine = 0;
+                                   }
+                           }
+                       if ( UnderLine == 1 )
+                               UnderLine = 2;
+
+                       nCol += i;
+                       if ( NewColor )
+                           {
+                               Red   = Line->Data[NewColorAt+1];
+                               Green = Line->Data[NewColorAt+2];
+                               Blue  = Line->Data[NewColorAt+3];
+                               SetTextColor(hdc, RGB(Red, Green, Blue));
+                               SetBkColor(hdc, RGB(255, 255, 255));
+                               NewColor = 0;
+                           }
+                   }
+               Line = Line->Next;
+           }
+    
+       SelectObject(hdc, hOldFont);
+       EndPaint(hWnd, &ps);
+       return 0;
+}
+
+
+BOOL Cio_WndDestroy(HWND hWnd)
+{
+       CioWndInfo  *CWI;
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+       while ( CWI->FirstLine )
+               CioRemoveLine(CWI, CWI->FirstLine);
+
+       DeleteObject(CWI->hFont);
+       LocalFree(CWI);
+
+       return 0;
+}
+
+
+int Cio_WndAddString(HWND hWnd, int Len, char *Buffer)
+{
+       CioWndInfo      *CWI;
+       CioLine *Line;
+       int     TLen=0, DLen=0, Loop=0, LastSpace=0, Scrolled=0, Pad=0;
+       BYTE    Red=0, Grn=0, Blu=0;
+
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+
+       if ( CWI->ScrollMe == TRUE )
+           {
+               Cio_Scroll(hWnd, CWI, 1);
+               Scrolled++;
+               CWI->ScrollMe = FALSE;
+           }
+       if ( Buffer[Len-1] == '\r' )
+           {
+               CWI->ScrollMe = TRUE;
+               Len-=1;
+           }
+
+       while ( Len )
+           {
+               /*
+                * Check the current line to see if we have room to tack
+                * on our string to the end of.  If not, put as much as
+                * possible on, then scroll up a new line.
+                */
+               TLen=DLen=0;
+               Line = CWI->FirstLine;
+               while ( TLen < Line->Len )
+                   {
+                       if ( Line->Data[TLen] == 0 )
+                           {
+                               TLen+=4;
+                               continue;
+                           }
+                       TLen+=1;
+                       DLen+=1;
+                   }
+               Loop=TLen=0;
+               while ( TLen < Len )
+                   {
+                       if ( Buffer[TLen] == 0 )
+                           {
+                               TLen+=4;
+                               continue;
+                           }
+                       TLen+=1;
+                       Loop+=1;
+                   }
+               if ( DLen+Loop > CWI->Width )
+                   {
+                       Cio_Scroll(hWnd, CWI, 1);
+                       Scrolled++;
+                       Loop=TLen=0;
+                       do
+                           {
+                               if ( Buffer[TLen] == 0 )
+                                   {
+                                       Red = Buffer[TLen+1];
+                                       Grn = Buffer[TLen+2];
+                                       Blu = Buffer[TLen+3];
+                                       TLen+=4;
+                                       continue;
+                                   }               
+                               if ( TLen >= Len || DLen+Loop >= CWI->Width )
+                                       break;
+                               if ( Buffer[TLen] == ' ' )
+                                       LastSpace = TLen;
+                               TLen+=1;
+                               Loop+=1;
+                           } while ( TLen < Len && DLen+Loop < CWI->Width );
+
+                       if ( TLen != Len && Buffer[TLen] != ' ' &&
+                            LastSpace && (LastSpace-TLen) < 16 )
+                               TLen = LastSpace;
+
+                       if ( Line->Data != NULL )
+                           {
+                               Line->Data = LocalReAlloc(Line->Data,
+                                       Line->Len+TLen+Pad, LMEM_MOVEABLE);
+                               _ASSERT(Line->Data);
+                               memset(Line->Data, ' ', Pad);
+                               memmove(Line->Data+Line->Len+Pad, Buffer, TLen);
+                               Line->Len += TLen + Pad;
+                           }
+                       else
+                           {
+                               if ( Buffer[0] == 0 )
+                                   {
+                                       Line->Data = LocalAlloc(LPTR, TLen+Pad);
+                                       _ASSERT(Line->Data);
+                                       memset(Line->Data, ' ', Pad);
+                                       memmove(Line->Data+Pad, Buffer, TLen);
+                                       Line->Len = TLen + Pad;
+                                   }
+                               else
+                                   {
+                                       Line->Data = LocalAlloc(LPTR, TLen+4+Pad);
+                                       _ASSERT(Line->Data);
+                                       memset(Line->Data+4, ' ', Pad);
+                                       memmove(Line->Data+4+Pad, Buffer, TLen);
+                                       Line->Len = TLen+4+Pad;
+                                       Line->Data[0] = 0;
+                                       Line->Data[1] = Red;
+                                       Line->Data[2] = Grn;
+                                       Line->Data[3] = Blu;
+                                   }
+                           }
+
+                       if ( TLen == LastSpace )
+                               TLen++;
+                       Pad = 3;
+                       Len -= TLen;
+                       memmove(Buffer, Buffer+TLen, Len);
+                       if ( Buffer[0] == '\r' && Len == 1 )
+                               Len=0;
+                       continue;
+                   } /* if ( DLen+Loop > CWI->Width ) */
+
+               Line = CWI->FirstLine;
+               if ( Line->Data != NULL )
+                   {
+                       Line->Data = LocalReAlloc(Line->Data, Line->Len+TLen+Pad,
+                               LMEM_MOVEABLE);
+                       _ASSERT(Line->Data);
+                       memset(Line->Data, ' ', Pad);
+                       memmove(Line->Data+Line->Len+Pad, Buffer, Len);
+                       Line->Len += Len + Pad;
+                   }
+               else
+                   {
+                       if ( Buffer[0] == 0 )
+                           {
+                               Line->Data = LocalAlloc(LPTR, Len+Pad);
+                               _ASSERT(Line->Data);
+                               memset(Line->Data, ' ', Pad);
+                               memmove(Line->Data+Pad, Buffer, Len);
+                               Line->Len = Len + Pad;
+                           }
+                       else
+                           {
+                               Line->Data = LocalAlloc(LPTR, Len+4+Pad);
+                               _ASSERT(Line->Data);
+                               memset(Line->Data+4, ' ', Pad);
+                               memmove(Line->Data+4+Pad, Buffer, Len);
+                               Line->Len = Len+4+Pad;
+                               Line->Data[0] = 0;
+                               Line->Data[1] = Red;
+                               Line->Data[2] = Grn;
+                               Line->Data[3] = Blu;
+                           }
+                   }
+
+               break;
+           } /* while (Len) */
+
+       if ( !CWI->Scroll )
+           {
+               RECT    rc;
+
+               rc.left = rc.top = 0;
+               rc.right = CWI->Width*CWI->XChar;
+               rc.bottom = CWI->Height*CWI->YChar+CWI->YJunk;
+               ScrollWindow(hWnd, 0, -(Scrolled*CWI->YChar), &rc, NULL);
+               rc.top = (CWI->Height-Scrolled)*CWI->YChar+CWI->YJunk;
+               if ( rc.top < 0 )
+                       rc.top = 0;
+               return Scrolled;
+           }
+       return 0;
+}
+
+
+BOOL Cio_WndSize(HWND hWnd, LPARAM lParam)
+{
+       CioWndInfo      *CWI;
+       SCROLLINFO      si;
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+
+       CWI->Scroll = 0;
+       CWI->Width = LOWORD(lParam) / CWI->XChar;
+       CWI->Height = HIWORD(lParam) / CWI->YChar;
+       CWI->YJunk = HIWORD(lParam) - (CWI->Height * CWI->YChar);
+
+       InvalidateRect(hWnd, NULL, TRUE);
+
+       /* Set the Scroll Bar information. */
+
+       si.cbSize = sizeof(si);
+       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
+       si.nMin   = 1;
+       si.nMax   = CWI->Lines;
+       si.nPage  = CWI->Height-1;
+       si.nPos   = si.nMax;
+       SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+
+       return 0;
+}
+
+
+BOOL Cio_WndScroll(HWND hWnd, WPARAM wParam)
+{
+       CioWndInfo      *CWI;
+       SCROLLINFO      si;
+       int     Amnt=0, nPos=0;
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+       si.cbSize = sizeof(si);
+       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS;
+       GetScrollInfo(hWnd, SB_VERT, &si);
+
+       si.nMax-=si.nPage;
+       si.nMax+=si.nMin;
+       nPos = si.nPos;
+
+       switch(LOWORD (wParam))
+           {
+               case SB_PAGEUP:
+                       Amnt = -(int)si.nPage;
+                       break;
+
+               case SB_PAGEDOWN:
+                       Amnt = si.nPage;
+                       break;
+
+               case SB_LINEUP:
+                       Amnt = -(int)1;
+                       break;
+
+               case SB_LINEDOWN:
+                       Amnt = 1;
+                       break;
+
+               case SB_THUMBTRACK:
+                       break;
+           }
+
+       if ( Amnt )
+           {
+               nPos += Amnt;
+
+               if ( nPos < si.nMin )
+                   {
+                       Amnt -= nPos - si.nMin;
+                       nPos = si.nMin;
+                   }
+
+               if ( nPos > si.nMax )
+                   {
+                       Amnt -= nPos - si.nMax;
+                       nPos = si.nMax;
+                   }
+
+               if ( Amnt )
+                   {
+                       SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
+                       CWI->Scroll = si.nMax-nPos;
+                       InvalidateRect(hWnd, NULL, TRUE);
+                   }
+           }
+
+       return 0;
+}
+
+
+void Cio_Scroll(HWND hWnd, CioWndInfo *CWI, int Scroll)
+{
+       int     i=0, KillAmt=0, StopAt=0;
+       SCROLLINFO      si;
+       CioLine *Line, *Next;
+
+       if ( CWI->Lines+Scroll > 500 && !CWI->Scroll )
+           {
+               Line = CWI->FirstLine;
+               KillAmt = max((CWI->Lines+Scroll)-500, 20);
+               for ( i = 0; Line && i < (CWI->Lines-KillAmt); i++ )
+                       Line = Line->Next;
+
+               while ( Line )
+               {
+                       Next = Line->Next;
+                       CioRemoveLine(CWI, Line);
+                       Line = Next;
+               }
+               CWI->Lines -= KillAmt;
+           }
+
+       for ( i = 0; i < Scroll; i++ )
+               CWI->FirstLine = CioMakeLine(NULL, CWI->FirstLine);
+
+       CWI->Lines+=Scroll;
+       if ( CWI->Scroll )
+               CWI->Scroll += Scroll;
+       
+       /* Set the Scroll Bar information. */
+       si.cbSize = sizeof(si);
+       si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
+       GetScrollInfo(hWnd, SB_VERT, &si);
+
+       si.cbSize = sizeof(si);
+       si.fMask  = SIF_RANGE | SIF_POS | SIF_PAGE | SIF_DISABLENOSCROLL;
+       si.nMin   = 1;
+       si.nMax   = CWI->Lines;
+       si.nPage  = CWI->Height-1;
+       si.nPos   = CWI->Lines - si.nPage - CWI->Scroll;
+       SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
+}
+
+
+BOOL Cio_PrintF(HWND hWnd, char *InBuf, ...)
+{
+       CioWndInfo      *CWI;
+       va_list argptr;
+       char    *Buffer=NULL, *Ptr = NULL;
+       DWORD   Len=0, TLen, Off;
+       int     Scrolled=0;
+       RECT    rc;
+
+
+       if ( (Buffer = LocalAlloc(LPTR, 16384)) == NULL )
+               return FALSE;
+
+       va_start(argptr, InBuf);
+       Len = vsprintf(Buffer, InBuf, argptr);
+       va_end(argptr);
+       if ( Len == 0 )
+           {
+               LocalFree(Buffer);
+               return FALSE;
+           }
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+       Ptr = memchr(Buffer, 0, TLen=Len);
+       while ( Ptr != NULL )
+           {
+               Off = Ptr-Buffer;
+        
+               CWI->FR = Buffer[Off+1];
+               CWI->FG = Buffer[Off+2];
+               CWI->FB = Buffer[Off+3];
+
+               Off += 4;
+               TLen = Len-Off;
+               if ( TLen == 0 )
+                       break;
+               Ptr = memchr(Buffer+Off, 0, TLen);
+           }
+       if ( Buffer[0] != 0 )
+           {
+               memmove(Buffer+4, Buffer, Len);
+               Len+=4;
+               Buffer[0] = 0;
+               Buffer[1] = CWI->FR;
+               Buffer[2] = CWI->FG;
+               Buffer[3] = CWI->FB;
+           }
+
+       rc.left = 0;
+       rc.right = CWI->Width*CWI->XChar;
+       rc.top = rc.bottom = CWI->Height*CWI->YChar;
+
+       do
+           {
+               Ptr = memchr(Buffer, '\r', Len);
+               if ( Ptr )
+                       TLen = (Ptr-Buffer)+1;
+               else
+                       TLen = Len;
+               if ( Buffer[0] != '\r' || CWI->ScrollMe == FALSE )
+                   {
+                       Scrolled = Cio_WndAddString(hWnd, TLen, Buffer);
+                       rc.top -= Scrolled*CWI->YChar;
+                   }
+               Len -= TLen;
+               memmove(Buffer, Buffer+TLen, Len);
+           } while ( Len );
+
+       if ( rc.top < rc.bottom )
+           {
+               if ( rc.top < 0 )
+                       rc.top = 0;
+               InvalidateRect(hWnd, &rc, TRUE);
+               UpdateWindow(hWnd);
+           }
+       LocalFree(Buffer);
+       return TRUE;
+}
+
+
+BOOL Cio_Puts(HWND hWnd, char *InBuf, DWORD Len)
+{
+       CioWndInfo      *CWI;
+       char    *Buffer = NULL, *Ptr = NULL;
+       DWORD   TLen, Off;
+       int     Scrolled=0;
+       RECT    rc;
+
+
+       if ( !Len )
+               return FALSE;
+
+       if ( (Buffer = LocalAlloc(LPTR, 16384)) == NULL )
+               return FALSE;
+       memmove(Buffer, InBuf, Len);
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+       Ptr = memchr(Buffer, 0, TLen=Len);
+       while ( Ptr != NULL )
+           {
+               Off = Ptr-Buffer;
+        
+               CWI->FR = Buffer[Off+1];
+               CWI->FG = Buffer[Off+2];
+               CWI->FB = Buffer[Off+3];
+
+               Off += 4;
+               TLen = Len-Off;
+               if ( TLen == 0 )
+                       break;
+               Ptr = memchr(Buffer+Off, 0, TLen);
+           }
+       if ( Buffer[0] != 0 )
+           {
+               memmove(Buffer+4, Buffer, Len);
+               Len+=4;
+               Buffer[0] = 0;
+               Buffer[1] = CWI->FR;
+               Buffer[2] = CWI->FG;
+               Buffer[3] = CWI->FB;
+           }
+
+       rc.left = 0;
+       rc.right = CWI->Width*CWI->XChar;
+       rc.top = rc.bottom = CWI->Height*CWI->YChar;
+
+       do
+           {
+               Ptr = memchr(Buffer, '\r', Len);
+               if ( Ptr )
+                       TLen = (Ptr-Buffer)+1;
+               else
+                       TLen = Len;
+               if ( Buffer[0] != '\r' || CWI->ScrollMe == FALSE )
+                   {
+                       Scrolled = Cio_WndAddString(hWnd, TLen, Buffer);
+                       rc.top -= Scrolled*CWI->YChar;
+                   }
+               Len -= TLen;
+               memmove(Buffer, Buffer+TLen, Len);
+           } while ( Len );
+
+       if ( rc.top < rc.bottom )
+           {
+               if ( rc.top < 0 )
+                       rc.top = 0;
+               InvalidateRect(hWnd, &rc, TRUE);
+               UpdateWindow(hWnd);
+           }
+       LocalFree(Buffer);
+       return TRUE;
+}
+
+
+BOOL Cio_SetFont(HWND hWnd, WPARAM wParam)
+{
+       CioWndInfo      *CWI;
+       TEXTMETRIC      tm;
+       HFONT   hFont = (HFONT)wParam;
+       HDC     hdc;
+       RECT    rc;
+
+
+       CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+
+       if ( CWI->hFont )
+               DeleteObject(CWI->hFont);
+       CWI->hFont = hFont;
+       hdc = GetDC(hWnd);
+       SelectObject(hdc, CWI->hFont);
+       GetTextMetrics(hdc, &tm);
+       ReleaseDC(hWnd, hdc);
+
+       CWI->XChar = tm.tmAveCharWidth;
+       CWI->YChar = tm.tmHeight + tm.tmExternalLeading;
+
+       /*
+        * Send resize message so it will pick up the new font size.
+        */
+       GetClientRect(hWnd, &rc);
+       SendMessage(hWnd, WM_SIZE, 0, MAKELPARAM(rc.right-rc.left, rc.bottom-rc.top));
+       InvalidateRect(hWnd, NULL, TRUE);
+
+       return TRUE;
+}
+
diff --git a/src/class.c b/src/class.c
new file mode 100644 (file)
index 0000000..de2a346
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *   IRC - Internet Relay Chat, ircd/class.c
+ *   Copyright (C) 1990 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "struct.h"
+#include "common.h"
+#include "numeric.h"
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1990 Darren Reed");
+ID_Notes("1.4 6/28/93");
+
+
+#define BAD_CONF_CLASS         -1
+#define BAD_PING               -2
+#define BAD_CLIENT_CLASS       -3
+
+aClass *classes;
+
+int    get_conf_class(aconf)
+aConfItem      *aconf;
+{
+       if ((aconf) && Class(aconf))
+               return (ConfClass(aconf));
+
+       Debug((DEBUG_DEBUG,"No Class For %s",
+             (aconf) ? aconf->name : "*No Conf*"));
+
+       return (BAD_CONF_CLASS);
+
+}
+
+static int     get_conf_ping(aconf)
+aConfItem      *aconf;
+{
+       if ((aconf) && Class(aconf))
+               return (ConfPingFreq(aconf));
+
+       Debug((DEBUG_DEBUG,"No Ping For %s",
+             (aconf) ? aconf->name : "*No Conf*"));
+
+       return (BAD_PING);
+}
+
+
+
+int    get_client_class(acptr)
+aClient        *acptr;
+{
+       Reg1    Link    *tmp;
+       Reg2    aClass  *cl;
+       int     i = 0, retc = BAD_CLIENT_CLASS;
+
+       if (acptr && !IsMe(acptr)  && (acptr->confs))
+               for (tmp = acptr->confs; tmp; tmp = tmp->next)
+                   {
+                       if (!tmp->value.aconf ||
+                           !(cl = tmp->value.aconf->class))
+                               continue;
+                       if (Class(cl) > retc)
+                               retc = Class(cl);
+                   }
+
+       Debug((DEBUG_DEBUG,"Returning Class %d For %s",retc,acptr->name));
+
+       return (retc);
+}
+
+int    get_client_ping(acptr)
+aClient        *acptr;
+{
+       int     ping = 0, ping2;
+       aConfItem       *aconf;
+       Link    *link;
+
+       link = acptr->confs;
+
+       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;
+                            }
+                       link = link->next;
+                   }
+       else
+           {
+               ping = PINGFREQUENCY;
+               Debug((DEBUG_DEBUG,"No Attached Confs"));
+           }
+       if (ping <= 0)
+               ping = PINGFREQUENCY;
+       Debug((DEBUG_DEBUG,"Client %s Ping %d", acptr->name, ping));
+       return (ping);
+}
+
+int    get_con_freq(clptr)
+aClass *clptr;
+{
+       if (clptr)
+               return (ConFreq(clptr));
+       else
+               return (CONNECTFREQUENCY);
+}
+
+/*
+ * When adding a class, check to see if it is already present first.
+ * if so, then update the information for that class, rather than create
+ * a new entry for it and later delete the old entry.
+ * if no present entry is found, then create a new one and add it in
+ * immeadiately after the first one (class 0).
+ */
+void   add_class(class, ping, confreq, maxli, sendq)
+int    class, ping, confreq, maxli;
+long   sendq;
+{
+       aClass *t, *p;
+
+       t = find_class(class);
+       if ((t == classes) && (class != 0))
+           {
+               p = (aClass *)make_class();
+               NextClass(p) = NextClass(t);
+               NextClass(t) = p;
+           }
+       else
+               p = t;
+       Debug((DEBUG_DEBUG,
+               "Add Class %d: p %x t %x - cf: %d pf: %d ml: %d sq: %l",
+               class, p, t, confreq, ping, maxli, sendq));
+       Class(p) = class;
+       ConFreq(p) = confreq;
+       PingFreq(p) = ping;
+       MaxLinks(p) = maxli;
+       MaxSendq(p) = (sendq > 0) ? sendq : MAXSENDQLENGTH;
+       if (p != t)
+               Links(p) = 0;
+}
+
+aClass *find_class(cclass)
+int    cclass;
+{
+       aClass *cltmp;
+
+       for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
+               if (Class(cltmp) == cclass)
+                       return cltmp;
+       return classes;
+}
+
+void   check_class()
+{
+       Reg1 aClass *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: %ld",
+                       Class(cltmp), ConFreq(cltmp), PingFreq(cltmp),
+                       MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp)));
+               if (MaxLinks(cltmp) < 0)
+                   {
+                       NextClass(cltmp2) = NextClass(cltmp);
+                       if (Links(cltmp) <= 0)
+                               free_class(cltmp);
+                   }
+               else
+                       cltmp2 = cltmp;
+           }
+}
+
+void   initclass()
+{
+       classes = (aClass *)make_class();
+
+       Class(FirstClass()) = 0;
+       ConFreq(FirstClass()) = CONNECTFREQUENCY;
+       PingFreq(FirstClass()) = PINGFREQUENCY;
+       MaxLinks(FirstClass()) = MAXIMUM_LINKS;
+       MaxSendq(FirstClass()) = MAXSENDQLENGTH;
+       Links(FirstClass()) = 0;
+       NextClass(FirstClass()) = NULL;
+}
+
+void   report_classes(sptr)
+aClient        *sptr;
+{
+       Reg1 aClass *cltmp;
+
+       for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
+               sendto_one(sptr, rpl_str(RPL_STATSYLINE), me.name, sptr->name,
+                          'Y', Class(cltmp), PingFreq(cltmp), ConFreq(cltmp),
+                          MaxLinks(cltmp), MaxSendq(cltmp));
+}
+
+long   get_sendq(cptr)
+aClient        *cptr;
+{
+       Reg1    int     sendq = MAXSENDQLENGTH, retc = BAD_CLIENT_CLASS;
+       Reg2    Link    *tmp;
+       Reg2    aClass  *cl;
+
+       if (cptr && !IsMe(cptr)  && (cptr->confs))
+               for (tmp = cptr->confs; tmp; tmp = tmp->next)
+                   {
+                       if (!tmp->value.aconf ||
+                           !(cl = tmp->value.aconf->class))
+                               continue;
+                       if (Class(cl) > retc)
+                               sendq = MaxSendq(cl);
+                   }
+       return sendq;
+}
diff --git a/src/cloak.c b/src/cloak.c
new file mode 100644 (file)
index 0000000..995b576
--- /dev/null
@@ -0,0 +1,324 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/cloak.c
+ *   (C) VirtualWorld code made originally by RogerY (rogery@austnet.org)
+ *   Some coding by Potvin (potvin@shadownet.org)
+ *   Modified by Stskeeps with some TerraX codebits 
+ *    TerraX (devcom@terrax.net) - great job guys!
+ *    Stskeeps (stskeeps@tspre.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 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.
+ */
+
+/*
+#ifdef lint
+static char sccxid[] = "@(#)cloak.c            9.00 7/12/99 UnrealIRCd";
+#endif
+*/
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifndef _WIN32
+#include <utmp.h>
+#endif
+#include "h.h"
+
+ID_CVS("$Id$");
+
+// #define iNAH /* networks.h now */
+/* Hidden host code below */
+
+#define MAXVIRTSIZE     (3 + 5 + 1)
+#define HASHVAL_TOTAL   30011
+#define HASHVAL_PARTIAL 211
+
+extern  aClient me;
+extern  int     seed;
+int     match(char *, char *), find_exception(char *);
+
+extern unsigned char tolowertab[];
+
+int str2array(char **pparv, char *string, char *delim)
+{
+    char *tok;
+    int pparc=0;
+
+    tok=(char *) strtok((char *) string,delim);
+    while(tok != NULL)
+    {
+        pparv[pparc++]=tok;
+        tok= (char *) strtok((char *) NULL,(char *) delim);
+    }
+
+    return pparc;
+}
+
+
+void truncstring(char *stringvar, int firstlast, int amount){
+   if (firstlast)
+   {
+    stringvar+=amount;
+    *stringvar=0;
+    stringvar-=amount;
+   }
+    else
+   {
+    stringvar+=strlen(stringvar);
+    stringvar-=amount;
+   }
+}
+
+#define B_BASE                  1000
+
+int Maskchecksum (char *data, int len)
+{
+       int                     i;
+       int                     j;
+
+       j=0;
+       for (i=0 ; i<len ; i++)
+       {
+         j += *data++ * (i < 16 ? (i+1)*(i+1) : i*(i-15));
+       }
+
+       return (j+B_BASE)%0xffff;
+}
+
+
+/* hidehost
+ * command takes the realhost of a user
+ * and changes the content of it.
+ * new hidehost by vmlinuz
+ * added some extra fixes by stskeeps
+ * originally based on TerraIRCd
+ */
+
+char *hidehost (char *s, int useless)
+{
+//     static char mask[128];
+       char            *mask;
+       static char ipmask[64];
+       int         csum;
+       char        *dot,*tmp;
+    char           *cp;
+       int                     i, isdns;
+    int                dots = 0;
+       
+       mask = MyMalloc(129);
+       memset (mask, 0, 128);
+
+       csum = Maskchecksum (s, strlen(s));
+
+       if (strlen (s) > 127)           /* this isn't likely to happen: s is limited to HOSTLEN+1 (64) */
+       {
+               s[128] = 0;
+       }
+
+       isdns = 0;
+       cp = s;
+       for (i=0; i < strlen(s); i++)
+       {
+               if (*cp == '.') {
+                       dots++;
+               }
+        cp++;
+       }
+
+       for (i=0 ; i<strlen(s) ; i++)
+       {
+               if (s[i] == '.') {
+               continue;
+        }
+               
+               if (isalpha(s[i])) 
+               {
+                       isdns = 1;
+                       break;
+               }
+       }
+       
+       if (isdns)
+       {
+               /* it is a resolved yes.. */
+               if (dots == 1) {       /* mystro.org f.x */
+                       sprintf(mask, "%s%c%d.%s",
+                                                       hidden_host,
+                                       (csum < 0 ? '=' : '-'),
+                                                       (csum < 0 ? -csum : csum), s);
+        }
+               if (dots == 0) {       /* localhost */
+                       sprintf(mask, "%s%c%d",
+                                                       s,
+                               (csum < 0 ? '=' : '-'),
+                                               (csum < 0 ? -csum : csum));
+               }
+
+               if (dots > 1) {
+                       dot = (char *) strchr((char *) s, '.');
+                       
+                       /* mask like *<first dot> */
+                       sprintf(mask, "%s%c%d.%s",
+                                               hidden_host,
+                        (csum < 0 ? '=' : '-'),
+                                               (csum < 0 ? -csum : csum), dot+1);
+        }
+       }
+       else 
+       {
+               strncpy(ipmask, s, sizeof(ipmask));
+               ipmask[sizeof(ipmask)-1]='\0';      /* safety check */
+               dot = (char *) strrchr((char *) ipmask, '.');
+               *dot = '\0';
+               
+               if (dot == NULL)     /* dot should never be NULL: IP needs dots */
+                         sprintf (mask, "%s%c%i",
+                                       hidden_host,
+                                       (csum < 0 ? '=' : '-'),
+                                       (csum < 0 ? -csum : csum));
+                         else
+                                       sprintf (mask, "%s.%s%c%i",
+                                                                       ipmask,
+                                                                       hidden_host,
+                                                                       (csum < 0 ? '=' : '-'),
+                                                                       (csum < 0 ? -csum : csum));
+       }
+
+ok1:           
+       return mask;
+}
+
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       
+/* Regular user host */
+void    make_virthost(char *curr, char *new)
+{
+       char *mask;
+       if (curr == NULL)
+               return;
+       if (new == NULL)
+               return;
+               
+       mask = hidehost(curr, 0);
+       
+       strncpyzt(new, mask, HOSTLEN); /* */
+       return;
+}
+
+/* Netadmin host */
+void   make_netadminhost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", netadmin_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+
+}
+/* Coadmin host */
+void    make_coadminhost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", coadmin_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+}
+/* Techadmin host */
+void    make_techadminhost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", techadmin_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+}
+/* Server admin host */
+void    make_adminhost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", admin_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+}
+/* Service admin host */
+void    make_sadminhost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", sadmin_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+}
+/* Global Oper host */
+void    make_operhost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", oper_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+}
+/* Local Oper host */
+void    make_locophost(char *new)
+{
+    char     tmpnew[HOSTLEN];
+#ifndef iNAH2
+        sprintf(tmpnew, "%s", locop_host);
+        strncpyzt(new, tmpnew, HOSTLEN);
+#endif
+        return;
+}
+
+/* Make SETHOST */
+
+void   make_sethost(char *new, char *new2)
+{
+               char    tmpnew[HOSTLEN];
+               
+               sprintf(tmpnew,"%s", new2);
+               strncpyzt(new, tmpnew, HOSTLEN);
+               return;
+}
+/* make setname */
+void   make_setname(char *new, char *new2)
+{
+               char    tmpnew[REALLEN];
+               
+               sprintf(tmpnew,"%s", new2);
+               strncpyzt(new, tmpnew, REALLEN);
+               return;
+}
+/* make setident */
+
+void   make_setident(char *new, char *new2)
+{
+               char    tmpnew[USERLEN];
+               
+               sprintf(tmpnew, "%s", new2);
+               strncpyzt(new, tmpnew, USERLEN);
+               return;
+}
\ No newline at end of file
diff --git a/src/conftool.c b/src/conftool.c
new file mode 100644 (file)
index 0000000..4318a17
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *  UnrealIRCd Configuration Tool (unrealircd.conf & network.network)
+ *  $Id$
+*/
+
+int main() {
+       printf("|=-=-=-=-=-==-==--=-=-=-=-=-==-==--=-=-=-=-=-==-==|\n");
+       printf("|                                                 |\n");
+       printf("| UnrealIRCd Configuration Tool                   |\n");
+       printf("| Version 1.0 by Techie <stskeeps@tspre.org>      |\n");
+       printf("|                                                 |\n");
+       printf("|-=-=-=-=-=-==-=-=-=-=-=-=-=-==-==-=-=-=-=-=-==-==|\n");
+
+       printf("Actually this is only a demo .. so wait for it to be released;p");
+}
\ No newline at end of file
diff --git a/src/crule.c b/src/crule.c
new file mode 100644 (file)
index 0000000..a575cc3
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * SmartRoute phase 1
+ * connection rule patch
+ * by Tony Vencill (Tonto on IRC) <vencill@bga.com>
+ *
+ * The majority of this file is a recusive descent parser used to convert
+ * connection rules into expression trees when the conf file is read.
+ * All parsing structures and types are hidden in the interest of good
+ * programming style and to make possible future data structure changes
+ * without affecting the interface between this patch and the rest of the
+ * server.  The only functions accessible externally are crule_parse,
+ * crule_free, and crule_eval.  Prototypes for these functions can be
+ * found in h.h.
+ *
+ * Please direct any connection rule or SmartRoute questions to Tonto on
+ * IRC or by email to vencill@bga.com.
+ *
+ * For parser testing, defining CR_DEBUG generates a stand-alone parser
+ * that takes rules from stdin and prints out memory allocation
+ * information and the parsed rule.  This stand alone parser is ignorant
+ * of the irc server and thus cannot do rule evaluation.  Do not define
+ * this flag when compiling the server!  If you wish to generate the
+ * test parser, compile from the ircd directory with a line similar to
+ * cc -o parser -DCR_DEBUG crule.c
+ *
+ * The define CR_CHKCONF is provided to generate routines needed in
+ * chkconf.  These consist of the parser, a different crule_parse that
+ * prints errors to stderr, and crule_free (just for good style and to
+ * more closely simulate the actual ircd environment).  crule_eval and
+ * the rule functions are made empty functions as in the stand-alone
+ * test parser.
+ */
+
+#ifndef CR_DEBUG
+/* ircd functions and types we need */
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+
+char *collapse PROTO((char *pattern));
+extern aClient *client, *local[];
+
+ID_CVS("$Id$");
+ID_Copyright("(C) Tony Vincell");
+
+#else
+/* includes and defines to make the stand-alone test parser */
+#include <stdio.h>
+#include <string.h>
+#define BadPtr(x) (!(x) || (*(x) == '\0'))
+#define DupString(x,y) do{x=(char *)MyMalloc(strlen(y)+1);(void)strcpy(x,y);}while(0)
+#define mycmp strcasecmp
+#endif
+
+#ifndef PROTO
+#if __STDC__
+#       define PROTO(x) x
+#else
+#       define PROTO(x) ()
+#endif
+#endif
+#if defined(CR_DEBUG) || defined(CR_CHKCONF)
+#define MyMalloc malloc
+#undef MyFree
+#undef 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 */
+
+/* some symbols for easy reading */
+enum crule_token
+{CR_UNKNOWN, CR_END, CR_AND, CR_OR, CR_NOT, CR_OPENPAREN, CR_CLOSEPAREN,
+   CR_COMMA, CR_WORD};
+enum crule_errcode
+{CR_NOERR, CR_UNEXPCTTOK, CR_UNKNWTOK, CR_EXPCTAND, CR_EXPCTOR,
+   CR_EXPCTPRIM, CR_EXPCTOPEN, CR_EXPCTCLOSE, CR_UNKNWFUNC, CR_ARGMISMAT};
+
+/* expression tree structure, function pointer, and tree pointer */
+/* local! */
+typedef int (*crule_funcptr) PROTO((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 */
+};
+typedef struct crule_treestruct crule_treeelem;
+typedef crule_treeelem *crule_treeptr;
+
+/* rule function prototypes - local! */
+int crule_connected PROTO((int, void **));
+int crule_directcon PROTO((int, void **));
+int crule_via PROTO((int, void **));
+int crule_directop PROTO((int, void **));
+int crule__andor PROTO((int, void **));
+int crule__not PROTO((int, void **));
+
+/* parsing function prototypes - local! */
+int crule_gettoken PROTO((int *, char **));
+void crule_getword PROTO((char *, int *, int, char **));
+int crule_parseandexpr PROTO((crule_treeptr *, int *, char **));
+int crule_parseorexpr PROTO((crule_treeptr *, int *, char **));
+int crule_parseprimary PROTO((crule_treeptr *, int *, char **));
+int crule_parsefunction PROTO((crule_treeptr *, int *, char **));
+int crule_parsearglist PROTO((crule_treeptr, int *, char **));
+
+#if defined(CR_DEBUG) || defined(CR_CHKCONF)
+/* prototypes for the test parser; if not debugging, these are
+ * defined in h.h */
+char *crule_parse PROTO((char *));
+void crule_free PROTO((char **));
+#ifdef CR_DEBUG
+void print_tree PROTO((crule_treeptr));
+#endif
+#endif
+
+/* 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 */
+};
+
+/* function table - null terminated */
+struct crule_funclistent
+{
+  char name[15];  /* MAXIMUM FUNCTION NAME LENGTH IS 14 CHARS!! */
+  int reqnumargs;
+  crule_funcptr funcptr;
+};
+struct crule_funclistent crule_funclist[] =
+{
+  /* maximum function name length is 14 chars */
+  {"connected", 1, crule_connected},
+  {"directcon", 1, crule_directcon},
+  {"via",       2, crule_via},
+  {"directop",  0, crule_directop},
+  {"",          0, NULL}  /* this must be here to mark end of list */
+};
+
+int crule_connected (numargs, crulearg)
+int numargs;
+void *crulearg[];
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  aClient *acptr;
+
+  /* taken from m_links */
+  for (acptr = client; acptr; acptr = acptr->next)
+    {
+      if (!IsServer(acptr) && !IsMe(acptr))
+       continue;
+      if (match((char *) crulearg[0], acptr->name))
+       continue;
+      return (1);
+    }
+  return (0);
+#endif
+}
+
+int crule_directcon (numargs, crulearg)
+int numargs;
+void *crulearg[];
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  int i;
+  aClient *acptr;
+
+  /* adapted from m_trace and exit_one_client */
+  for (i = 0; i <= highest_fd; i++)
+    {
+      if (!(acptr = local[i]) || !IsServer(acptr))
+       continue;
+      if (match((char *) crulearg[0], acptr->name))
+       continue;
+      return (1);
+    }
+  return (0);
+#endif
+}
+
+int crule_via (numargs, crulearg)
+int numargs;
+void *crulearg[];
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  aClient *acptr;
+
+  /* adapted from m_links */
+  for (acptr = client; acptr; acptr = acptr->next)
+    {
+      if (!IsServer(acptr) && !IsMe(acptr))
+       continue;
+      if (match((char *) crulearg[1], acptr->name))
+       continue;
+      if (match((char *) crulearg[0], (local[acptr->fd])->name))
+       continue;
+      return (1);
+    }
+  return (0);
+#endif
+}
+
+int crule_directop (numargs, crulearg)
+int numargs;
+void *crulearg[];
+{
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  int i;
+  aClient *acptr;
+
+  /* adapted from m_trace */
+  for (i = 0; i <= highest_fd; i++)
+    {
+      if (!(acptr = local[i]) || !IsAnOper(acptr))
+       continue;
+      return (1);
+    }
+  return (0);
+#endif
+}
+
+int crule__andor (numargs, crulearg)
+int numargs;
+void *crulearg[];
+{
+  int result1;
+
+  result1 = ((crule_treeptr) crulearg[0])->funcptr
+    (((crule_treeptr) crulearg[0])->numargs,
+     (void *) ((crule_treeptr) crulearg[0])->arg);
+  if (crulearg[2]) /* or */
+    return (result1 ||
+           ((crule_treeptr) crulearg[1])->funcptr
+           (((crule_treeptr) crulearg[1])->numargs,
+            (void *) ((crule_treeptr) crulearg[1])->arg));
+  else
+    return (result1 &&
+           ((crule_treeptr) crulearg[1])->funcptr
+           (((crule_treeptr) crulearg[1])->numargs,
+            (void *) ((crule_treeptr) crulearg[1])->arg));
+}
+
+int crule__not (numargs, crulearg)
+int numargs;
+void *crulearg[];
+{
+  return (!((crule_treeptr) crulearg[0])->funcptr
+         (((crule_treeptr) crulearg[0])->numargs,
+          (void *) ((crule_treeptr) crulearg[0])->arg));
+}
+
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+int crule_eval (rule)
+char *rule;
+{
+  return (((crule_treeptr) rule)->funcptr
+         (((crule_treeptr) rule)->numargs,
+          ((crule_treeptr) rule)->arg));
+}
+#endif
+
+int crule_gettoken (next_tokp, ruleptr)
+int *next_tokp;
+char **ruleptr;
+{
+  char pending = '\0';
+
+  *next_tokp = CR_UNKNOWN;
+  while (*next_tokp == CR_UNKNOWN)
+    switch (*(*ruleptr)++)
+      {
+      case ' ': case '\t':
+       break;
+      case '&':
+       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;
+      case '!':
+       *next_tokp = CR_NOT;
+       break;
+      case '(':
+       *next_tokp = CR_OPENPAREN;
+       break;
+      case ')':
+       *next_tokp = CR_CLOSEPAREN;
+       break;
+      case ',':
+       *next_tokp = CR_COMMA;
+       break;
+      case '\0':
+       (*ruleptr)--;
+       *next_tokp = CR_END;
+       break;
+      case ':':
+       *next_tokp = CR_END;
+       break;
+      default:
+       if ((isalpha (*(--(*ruleptr)))) || (**ruleptr == '*') ||
+           (**ruleptr == '?') || (**ruleptr == '.'))
+         *next_tokp = CR_WORD;
+       else
+         return (CR_UNKNWTOK);
+       break;
+      }
+  return CR_NOERR;
+}
+
+void crule_getword (word, wordlenp, maxlen, ruleptr)
+char *word;
+int *wordlenp;
+int maxlen;
+char **ruleptr;
+{
+  char *word_ptr;
+
+  word_ptr = word;
+  while ((isalnum (**ruleptr)) || (**ruleptr == '*') ||
+         (**ruleptr == '?') || (**ruleptr == '.'))
+    *word_ptr++ = *(*ruleptr)++;
+  *word_ptr = '\0';
+  *wordlenp = word_ptr - word;
+}
+
+/*
+ * Grammar
+ *   rule:
+ *     orexpr END          END is end of input or :
+ *   orexpr:
+ *     andexpr
+ *     andexpr || orexpr
+ *   andexpr:
+ *     primary
+ *     primary && andexpr
+ *  primary:
+ *    function
+ *    ! primary
+ *    ( orexpr )
+ *  function:
+ *    word ( )             word is alphanumeric string, first character
+ *    word ( arglist )       must be a letter
+ *  arglist:
+ *    word
+ *    word , arglist
+ */
+
+char *crule_parse (rule)
+char *rule;
+{
+  char *ruleptr = rule;
+  int next_tok;
+  crule_treeptr ruleroot = NULL;
+  int errcode = CR_NOERR;
+
+  if ((errcode = crule_gettoken (&next_tok, &ruleptr)) == CR_NOERR)
+    if ((errcode = crule_parseorexpr (&ruleroot, &next_tok,
+                                     &ruleptr)) == CR_NOERR)
+      if (ruleroot != NULL)
+       if (next_tok == CR_END)
+         return ((char *) ruleroot);
+       else
+         errcode = CR_UNEXPCTTOK;
+      else
+       errcode = CR_EXPCTOR;
+  if (ruleroot != NULL)
+    crule_free ((char **) &ruleroot);
+#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
+  Debug ((DEBUG_ERROR, "%s in rule: %s", crule_errstr[errcode], rule));
+#else
+  (void) fprintf (stderr, "%s in rule: %s\n", crule_errstr[errcode], rule);
+#endif
+  return NULL;
+}
+
+int crule_parseorexpr (orrootp, next_tokp, ruleptr)
+crule_treeptr *orrootp;
+int *next_tokp;
+char **ruleptr;
+{
+  int errcode = CR_NOERR;
+  crule_treeptr andexpr;
+  crule_treeptr orptr;
+
+  *orrootp = NULL;
+  while (errcode == CR_NOERR)
+    {
+      errcode = crule_parseandexpr (&andexpr, next_tokp, ruleptr);
+      if ((errcode == CR_NOERR) && (*next_tokp == CR_OR))
+       {
+         orptr = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
+#ifdef CR_DEBUG
+         (void) fprintf (stderr, "allocating or element at %ld\n", orptr);
+#endif
+         orptr->funcptr = crule__andor;
+         orptr->numargs = 3;
+         orptr->arg[2] = (void *) 1;
+         if (*orrootp != NULL)
+           {
+             (*orrootp)->arg[1] = andexpr;
+             orptr->arg[0] = *orrootp;
+           }
+         else
+           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);
+             }
+         else
+           {
+             *orrootp = andexpr;
+             return (errcode);
+           }
+       }
+      if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
+       return (errcode);
+    }
+  return (errcode);
+}
+
+int crule_parseandexpr (androotp, next_tokp, ruleptr)
+crule_treeptr *androotp;
+int *next_tokp;
+char **ruleptr;
+{
+  int errcode = CR_NOERR;
+  crule_treeptr primary;
+  crule_treeptr andptr;
+
+  *androotp = NULL;
+  while (errcode == CR_NOERR)
+    {
+      errcode = crule_parseprimary (&primary, next_tokp, ruleptr);
+      if ((errcode == CR_NOERR) && (*next_tokp == CR_AND))
+       {
+         andptr = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
+#ifdef CR_DEBUG
+         (void) fprintf (stderr, "allocating and element at %ld\n", andptr);
+#endif
+         andptr->funcptr = crule__andor;
+         andptr->numargs = 3;
+         andptr->arg[2] = (void *) 0;
+         if (*androotp != NULL)
+           {
+             (*androotp)->arg[1] = primary;
+             andptr->arg[0] = *androotp;
+           }
+         else
+           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);
+             }
+         else
+           {
+             *androotp = primary;
+             return (errcode);
+           }
+       }
+      if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
+       return (errcode);
+    }
+  return (errcode);
+}
+
+int crule_parseprimary (primrootp, next_tokp, ruleptr)
+crule_treeptr *primrootp;
+int *next_tokp;
+char **ruleptr;
+{
+  crule_treeptr *insertionp;
+  int errcode = CR_NOERR;
+
+  *primrootp = NULL;
+  insertionp = primrootp;
+  while (errcode == CR_NOERR)
+    {
+      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;
+       case CR_NOT:
+         *insertionp = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
+#ifdef CR_DEBUG
+         (void) 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;
+       case CR_WORD:
+         errcode = crule_parsefunction (insertionp, next_tokp, ruleptr);
+         break;
+       default:
+          if (*primrootp == NULL)
+            errcode = CR_NOERR;
+          else
+           errcode = CR_EXPCTPRIM;
+         break;
+       }
+      return (errcode);
+    }
+  return (errcode);
+}
+
+int crule_parsefunction (funcrootp, next_tokp, ruleptr)
+crule_treeptr *funcrootp;
+int *next_tokp;
+char **ruleptr;
+{
+  int errcode = CR_NOERR;
+  char funcname[CR_MAXARGLEN];
+  int namelen;
+  int funcnum;
+
+  *funcrootp = NULL;
+  crule_getword (funcname, &namelen, CR_MAXARGLEN, ruleptr);
+  if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
+    return (errcode);
+  if (*next_tokp == CR_OPENPAREN)
+    {
+      for (funcnum = 0; ; funcnum++)
+       {
+         if (mycmp (crule_funclist[funcnum].name, funcname) == 0)
+           break;
+         if (crule_funclist[funcnum].name[0] == '\0')
+           return (CR_UNKNWFUNC);
+       }
+      if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
+       return (errcode);
+      *funcrootp = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
+#ifdef CR_DEBUG
+      (void) fprintf (stderr, "allocating function element at %ld\n",
+                     *funcrootp);
+#endif
+      (*funcrootp)->funcptr = NULL; /* for freeing aborted trees */
+      if ((errcode = 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))
+       return (CR_ARGMISMAT);
+      if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
+       return (errcode);
+      (*funcrootp)->funcptr = crule_funclist[funcnum].funcptr;
+      return (CR_NOERR);
+    }
+  else
+    return (CR_EXPCTOPEN);
+}
+
+int crule_parsearglist (argrootp, next_tokp, ruleptr)
+crule_treeptr argrootp;
+int *next_tokp;
+char **ruleptr;
+{
+  int errcode = CR_NOERR;
+  char *argelemp = NULL;
+  char currarg[CR_MAXARGLEN];
+  int arglen = 0;
+  char word[CR_MAXARGLEN];
+  int wordlen = 0;
+
+  argrootp->numargs = 0;
+  currarg[0] = '\0';
+  while (errcode == CR_NOERR)
+    {
+      switch (*next_tokp)
+       {
+       case CR_WORD:
+         crule_getword (word, &wordlen, CR_MAXARGLEN, 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)
+         (void) 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;
+       }
+    }
+  return (errcode);
+}
+
+/*
+ * this function is recursive..  i wish i knew a nonrecursive way but
+ * i dont.  anyway, recursion is fun..  :)
+ * DO NOT CALL THIS FUNTION WITH A POINTER TO A NULL POINTER
+ * (ie: if *elem is NULL, you're doing it wrong - seg fault)
+ */
+void crule_free (elem)
+char **elem;
+{
+  int arg, numargs;
+
+  if ((*((crule_treeptr *) elem))->funcptr == crule__not)
+    {
+      /* type conversions and ()'s are fun! ;)  here have an asprin.. */
+      if ((*((crule_treeptr *)elem))->arg[0] != NULL)
+       crule_free ((char **) &((*((crule_treeptr *) elem))->arg[0]));
+    }
+  else if ((*((crule_treeptr *)elem))->funcptr == crule__andor)
+    {
+      crule_free ((char **) &((*((crule_treeptr *) elem))->arg[0]));
+      if ((*((crule_treeptr *)elem))->arg[1] != NULL)
+       crule_free ((char **) &((*((crule_treeptr *) elem))->arg[1]));
+    }
+  else
+    {
+      numargs = (*((crule_treeptr *) elem))->numargs;
+      for (arg = 0; arg < numargs; arg++)
+       MyFree ((char *) (*((crule_treeptr *) elem))->arg[arg]);
+    }
+#ifdef CR_DEBUG
+  (void) fprintf (stderr, "freeing element at %ld\n", *elem);
+#endif
+  MyFree (*elem);
+  *elem = NULL;
+}
+
+#ifdef CR_DEBUG
+void print_tree (printelem)
+crule_treeptr printelem;
+{
+  int funcnum, arg;
+
+  if (printelem->funcptr == crule__not)
+    {
+      printf ("!( ");
+      print_tree ((crule_treeptr) printelem->arg[0]);
+      printf (") ");
+    }
+  else if (printelem->funcptr == crule__andor)
+    {
+      printf ("( ");
+      print_tree ((crule_treeptr) printelem->arg[0]);
+      if (printelem->arg[2])
+       printf ("|| ");
+      else
+       printf ("&& ");
+      print_tree ((crule_treeptr) printelem->arg[1]);
+      printf (") ");
+    }
+  else
+    {
+      for (funcnum = 0; ;funcnum++)
+       {
+         if (printelem->funcptr == crule_funclist[funcnum].funcptr)
+           break;
+         if (crule_funclist[funcnum].funcptr == NULL)
+           {
+             printf ("\nACK!  *koff*  *sputter*\n");
+             exit (1);
+           }
+       }
+      printf ("%s(", crule_funclist[funcnum].name);
+      for (arg = 0; arg < printelem->numargs; arg++)
+       {
+         if (arg != 0)
+           printf (",");
+         printf ("%s", (char *) printelem->arg[arg]);
+       }
+      printf (") ");
+    }
+}
+#endif
+
+#ifdef CR_DEBUG
+void main ()
+{
+  char indata[256];
+  char *rule;
+
+  printf ("rule: ");
+  while (fgets (indata, 256, stdin) != NULL)
+    {
+      indata[strlen (indata) - 1] = '\0'; /* lose the newline */
+      if ((rule = crule_parse (indata)) != NULL)
+       {
+         printf ("equivalent rule: ");
+         print_tree ((crule_treeptr) rule);
+         printf ("\n");
+         crule_free (&rule);
+       }
+      printf ("\nrule: ");
+    }
+  printf ("\n");
+}
+#endif
diff --git a/src/dbuf.c b/src/dbuf.c
new file mode 100644 (file)
index 0000000..226ccef
--- /dev/null
@@ -0,0 +1,351 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, common/dbuf.c
+ *   Copyright (C) 1990 Markku Savela
+ *
+ *   This program is free software; you can 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.
+ */
+
+/* -- Jto -- 20 Jun 1990
+ * extern void free() fixed as suggested by
+ * gruner@informatik.tu-muenchen.de
+ */
+
+/* -- Jto -- 10 May 1990
+ * Changed memcpy into bcopy and removed the declaration of memset
+ * because it was unnecessary.
+ * Added the #includes for "struct.h" and "sys.h" to get bcopy/memcpy
+ * work
+ */
+
+/*
+** For documentation of the *global* functions implemented here,
+** see the header file (dbuf.h).
+**
+*/
+
+#include <stdio.h>
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1990 Markku Savela");
+ID_Notes("2.17 1/30/94 (C) 1990 Markku Savela");
+
+#if !defined(VALLOC) && !defined(valloc)
+# ifndef _WIN32
+#  define      valloc malloc
+# else
+#  define      valloc MyMalloc
+# endif
+#endif
+
+int    dbufalloc = 0, dbufblocks = 0;
+static dbufbuf *freelist = NULL;
+
+/* This is a dangerous define because a broken compiler will set DBUFSIZ
+** to 4, which will work but will be very inefficient. However, there
+** are other places where the code breaks badly if this is screwed
+** up, so... -- Wumpus
+*/
+
+#define DBUFSIZ sizeof(((dbufbuf *)0)->data)
+
+/*
+** dbuf_alloc - allocates a dbufbuf structure either from freelist or
+** creates a new one.
+*/
+static dbufbuf *dbuf_alloc()
+{
+#if defined(VALLOC) && !defined(DEBUGMODE)
+       Reg1    dbufbuf *dbptr, *db2ptr;
+       Reg2    int     num;
+#else
+       Reg1    dbufbuf *dbptr;
+#endif
+
+       dbufalloc++;
+       if ((dbptr = freelist))
+           {
+               freelist = freelist->next;
+               return dbptr;
+           }
+       if (dbufalloc * DBUFSIZ > BUFFERPOOL)
+           {
+               dbufalloc--;
+               return NULL;
+           }
+
+#if defined(VALLOC) && !defined(DEBUGMODE)
+# if defined(SOL20) || defined(_SC_PAGESIZE)
+       num = sysconf(_SC_PAGESIZE)/sizeof(dbufbuf);
+# else
+       num = getpagesize()/sizeof(dbufbuf);
+# endif
+       if (num < 0)
+               num = 1;
+
+       dbufblocks += num;
+
+       dbptr = (dbufbuf *)valloc(num*sizeof(dbufbuf));
+       if (!dbptr)
+               return (dbufbuf *)NULL;
+
+       num--;
+       for (db2ptr = dbptr; num; num--)
+           {
+               db2ptr = (dbufbuf *)((char *)db2ptr + sizeof(dbufbuf));
+               db2ptr->next = freelist;
+               freelist = db2ptr;
+           }
+       return dbptr;
+#else
+       dbufblocks++;
+       return (dbufbuf *)MyMalloc(sizeof(dbufbuf));
+#endif
+}
+/*
+** dbuf_free - return a dbufbuf structure to the freelist
+*/
+static void    dbuf_free(ptr)
+Reg1   dbufbuf *ptr;
+{
+       dbufalloc--;
+       ptr->next = freelist;
+       freelist = ptr;
+}
+/*
+** This is called when malloc fails. Scrap the whole content
+** of dynamic buffer and return -1. (malloc errors are FATAL,
+** there is no reason to continue this buffer...). After this
+** the "dbuf" has consistent EMPTY status... ;)
+*/
+static int dbuf_malloc_error(dyn)
+dbuf *dyn;
+    {
+       dbufbuf *p;
+
+       dyn->length = 0;
+       dyn->offset = 0;
+       while ((p = dyn->head) != NULL)
+           {
+               dyn->head = p->next;
+               dbuf_free(p);
+           }
+       dyn->tail = dyn->head;
+       return -1;
+    }
+
+
+int    dbuf_put(dyn, buf, length)
+dbuf   *dyn;
+char   *buf;
+int    length;
+{
+       Reg1    dbufbuf **h, *d;
+       Reg2    int      off;
+       Reg3    int     chunk;
+
+       if(!length) return 1; /* Nothing to do */
+
+       off = (dyn->offset + dyn->length) % DBUFSIZ;
+       /*
+       ** Locate the last non-empty buffer. If the last buffer is
+       ** full, the loop will terminate with 'd==NULL'. This loop
+       ** assumes that the 'dyn->length' field is correctly
+       ** maintained, as it should--no other check really needed.
+       */
+       if (!dyn->length) h = &(dyn->head);
+       else {
+         if (off) h = &(dyn->tail);
+         else h = &(dyn->tail->next);
+       }
+       /*
+       ** Append users data to buffer, allocating buffers as needed
+       */
+       chunk = DBUFSIZ - off;
+       dyn->length += length;
+       for ( ;length > 0; h = &(d->next))
+           {
+               if ((d = *h) == NULL)
+                   {
+                       if ((d = (dbufbuf *)dbuf_alloc()) == NULL)
+                               return dbuf_malloc_error(dyn);
+                       dyn->tail = d;
+                       *h = d;
+                       d->next = NULL;
+                   }
+               if (chunk > length)
+                       chunk = length;
+               bcopy(buf, d->data + off, chunk);
+               length -= chunk;
+               buf += chunk;
+               off = 0;
+               chunk = DBUFSIZ;
+           }
+       return 1;
+    }
+
+
+char   *dbuf_map(dyn,length)
+dbuf   *dyn;
+int    *length;
+    {
+       if (dyn->head == NULL)
+           {
+               dyn->tail = NULL;
+               *length = 0;
+               return NULL;
+           }
+       *length = DBUFSIZ - dyn->offset;
+       if (*length > dyn->length)
+               *length = dyn->length;
+       return (dyn->head->data + dyn->offset);
+    }
+
+int    dbuf_delete(dyn,length)
+dbuf   *dyn;
+int    length;
+    {
+       dbufbuf *d;
+       int chunk;
+
+       if (length > dyn->length)
+               length = dyn->length;
+       chunk = DBUFSIZ - dyn->offset;
+       while (length > 0)
+           {
+               if (chunk > length)
+                       chunk = length;
+               length -= chunk;
+               dyn->offset += chunk;
+               dyn->length -= chunk;
+               if (dyn->offset == DBUFSIZ || dyn->length == 0)
+                   {
+                       d = dyn->head;
+                       dyn->head = d->next;
+                       dyn->offset = 0;
+                       dbuf_free(d);
+                   }
+               chunk = DBUFSIZ;
+           }
+       if (dyn->head == (dbufbuf *)NULL) {
+               dyn->length = 0;
+               dyn->tail = 0;
+       }
+       return 0;
+    }
+
+int    dbuf_get(dyn, buf, length)
+dbuf   *dyn;
+char   *buf;
+int    length;
+    {
+       int     moved = 0;
+       int     chunk;
+       char    *b;
+
+       while (length > 0 && (b = dbuf_map(dyn, &chunk)) != NULL)
+           {
+               if (chunk > length)
+                       chunk = length;
+               bcopy(b, buf, (int)chunk);
+               (void)dbuf_delete(dyn, chunk);
+               buf += chunk;
+               length -= chunk;
+               moved += chunk;
+           }
+       return moved;
+    }
+
+/*
+** dbuf_getmsg
+**
+** Check the buffers to see if there is a string which is terminted with
+** either a \r or \n prsent.  If so, copy as much as possible (determined by
+** length) into buf and return the amount copied - else return 0.
+*/
+int    dbuf_getmsg(dyn, buf, length)
+dbuf   *dyn;
+char   *buf;
+register int   length;
+{
+       dbufbuf *d;
+       register char   *s;
+       register int    dlen;
+       register int    i;
+       int     copy;
+
+getmsg_init:
+       d = dyn->head;
+       dlen = dyn->length;
+       i = DBUFSIZ - dyn->offset;
+       if (i <= 0)
+               return -1;
+       copy = 0;
+       if (d && dlen)
+               s = dyn->offset + d->data;
+       else
+               return 0;
+
+       if (i > dlen)
+               i = dlen;
+       while (length > 0 && dlen > 0)
+           {
+               dlen--;
+               if (*s == '\n' || *s == '\r')
+                   {
+                       copy = dyn->length - dlen;
+                       /*
+                       ** Shortcut this case here to save time elsewhere.
+                       ** -avalon
+                       */
+                       if (copy == 1)
+                           {
+                               (void)dbuf_delete(dyn, 1);
+                               goto getmsg_init;
+                           }
+                       break;
+                   }
+               length--;
+               if (!--i)
+                   {
+                       if ((d = d->next))
+                           {
+                               s = d->data;
+                               i = MIN(DBUFSIZ, dlen);
+                           }
+                   }
+               else
+                       s++;
+           }
+
+       if (copy <= 0)
+               return 0;
+
+       /*
+       ** copy as much of the message as wanted into parse buffer
+       */
+       i = dbuf_get(dyn, buf, MIN(copy, length));
+       /*
+       ** and delete the rest of it!
+       */
+       if (copy - i > 0)
+               (void)dbuf_delete(dyn, copy - i);
+       if (i >= 0)
+               *(buf+i) = '\0';        /* mark end of messsage */
+
+       return i;
+}
diff --git a/src/dynconf.c b/src/dynconf.c
new file mode 100644 (file)
index 0000000..fc57c96
--- /dev/null
@@ -0,0 +1,373 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, dynconf.c
+ *   (C) 1999 Carsten Munk (Techie/Stskeeps) <cmunk@toybox.flirt.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 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.
+ */
+
+#define DYNCONF_C
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <utmp.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1999 Carsten Munk");
+#define DoDebug fprintf(stderr, "[%s] %s | %li\n", babuf, __FILE__, __LINE__);
+#define AllocCpy(x,y) if ((x) && type == 1) MyFree((x)); x = (char *) MyMalloc(strlen(y) + 1); strcpy(x,y)
+#define XtndCpy(x,y) x = (char *) MyMalloc(strlen(y) + 2); *x = '\0'; strcat(x, "*"); strcpy(x,y)
+
+aConfiguration iConf;
+int     icx = 0;
+void iCstrip(char *line)
+{
+        char *c;
+
+        if ((c = strchr(line, '\n')))   *c = '\0';
+        if ((c = strchr(line, '\r')))   *c = '\0';
+}
+
+/*
+               for (q = p; *q; q++) {
+                       printf("%x ", *q);
+                }
+*/
+
+
+/* Get the unrealircd.conf/*.network file version and check it */
+char *get_version(char *file) {
+       FILE *fd = fopen(file, "r");
+       char buf[24], *tmp = '\0', *buf2 = '\0', *version = '\0';
+
+       /* This should never happen, but we'll keep it just to be safe */
+       if (!fd) {
+#ifdef _WIN32
+               MessageBox(NULL, "UnrealIRCD/32 Init Error", "Unable to load dynamic config (or network) file !! ", MB_OK);
+#else
+               fprintf(stderr, "[error] Couldn't load %s !!!\n", file);
+#endif        
+               exit(-1);
+       }
+/* We only want to read the first line */
+       fgets(buf, 24, fd);
+       tmp = strtok(buf, "\n");
+/* Make sure that it is a valid version line */
+       buf2 = strtok(tmp,"^");
+/* If it isn't exit */
+       if (strcmp(buf2, "ver")) {
+#ifdef _WIN32
+               MessageBox(NULL, "Dynamic config file (or network file) is not valid, visit http://unreal.tspre.org to learn how to upgrade", "UnrealIRCD/32 Init Error", MB_OK);
+#else
+               fprintf(stderr, "%s is invalid, visit http://unreal.tspre.org to learn how to upgrade", file);
+#endif
+               exit(-1);
+       }
+       /* If it is we get the version number */
+       version = strtok(NULL, "");
+       fclose(fd);
+       /* Now return the version */
+       return version;
+}
+
+int            load_conf(char  *file, int type)
+{
+       FILE    *zConf;
+        char    *stat;
+       char    *buf = MyMalloc(1024);
+       char    *babuf = MyMalloc(1024);
+       char    *p, *q;
+       char    *var, *setto;          
+       long    aint;
+       int     v1, v2;
+       /* Since we have no real way of knowing what file we are dealing with, we will check
+        * for *.conf then get the version */
+       if(!match("*.conf",file)) {
+               if (strcmp(get_version(file), "1.1")) {
+#ifdef _WIN32
+       
+                       MessageBox(NULL, "Dynamic config file is not valid, visit http://unreal.tspre.org to learn how to upgrade", "UnrealIRCD/32 Init Error", MB_OK);
+#else
+                       fprintf(stderr, "%s is invalid, visit http://unreal.tspre.org to learn how to upgrade\n", file);
+#endif
+                       exit(-1);
+               }
+}
+
+       zConf = fopen(file, "r");
+       if (zConf == NULL && (type == 0)) {
+#ifdef _WIN32
+               MessageBox(NULL, "UnrealIRCD/32 Init Error", "Unable to load dynamic config (or network) file !! ", MB_OK);
+#else
+               fprintf(stderr, "[error] Couldn't load %s !!!\n", file);
+#endif        
+               exit(-1);
+       }
+       else
+        if (zConf == NULL && (type == 1)) 
+        {
+               sendto_ops("[error] Couldnt load dynconf file %s !!", file);
+        }
+       *buf = '\1';
+        stat = buf;
+               
+       while (stat != NULL)
+       {
+               stat = fgets(buf,1020, zConf);
+               if (*buf == '#')       /* comment */
+                       continue;
+               if (*buf == '/')       /* comment */
+                       continue;
+               iCstrip(buf);    /* strip crlf .. */
+               strcpy(babuf, buf);
+               if (*buf == '\0')
+                       continue;
+               
+               p = strtok(buf, " ");
+               if (strcmp(p, "Include")==0)
+               {
+                               strtok(NULL, " ");
+                setto = strtok(NULL, "");
+                               /* We need this for STATS S */
+                               AllocCpy(INCLUDE, setto);
+#ifndef _WIN32
+#endif
+                               /* Check the version before we read the file */
+                       
+                               if (strcmp(get_version(setto),"2.2"))
+                               {
+#ifdef _WIN32
+                                       MessageBox(NULL, "Network file is not valid, visit http://unreal.tspre.org to learn how to upgrade", "UnrealIRCD/32 Init Error", MB_OK);
+#else
+                                       fprintf(stderr, "%s is invalid, visit http://unreal.tspre.org to learn how to upgrade\n", setto);
+#endif
+                                       exit(-1);
+                               }
+
+                               load_conf(setto,type);
+               }
+               
+                else
+               if (strcmp(p, "Set")==0)
+               {
+                       var = strtok(NULL, " ");
+                       /* Yes it was a good idea when i moved it. */
+                       if (var == NULL)
+                               continue;
+                       if (*var == '\0')
+                               continue;
+
+                       strtok(NULL, " ");
+                       setto = strtok(NULL, "");
+                       if (setto == NULL)
+                               continue;
+                       if (*setto == '\0')
+                               continue;
+       
+                       if (*setto >= '0' && *setto <= '9') {
+                               aint = atol(setto);
+                               if (strcmp(var, "MODE_X")==0)
+                                       MODE_X = aint;
+                                       else
+                               if (strcmp(var, "MODE_I")==0)
+                                       MODE_I = aint;
+                                       else
+                               if (strcmp(var, "TRUEHUB")==0) {
+                                       TRUEHUB = aint;
+#ifndef HUB    
+                                       /* Only display if _not_ called thru /rehash */
+                               if (aint == 1 && type == 0) {
+#ifdef _WIN32
+                                       MessageBox(NULL, "UnrealIRCD/32 Init Error", "I'm a leaf NOT an hub! ", MB_OK);
+                                                                                               
+#else
+                                       fprintf(stderr, "[error] I'm a leaf NOT a hub!\n");
+#endif
+                                       return 0;
+                               }
+#endif
+                       }
+                               if (strcmp(var, "CONFIG_FILE_STOP")==0) {
+                                       if (aint == 1) {
+#ifdef _WIN32
+                                       MessageBox(NULL, "UnrealIRCD/32 Init Error", "Read Config stop code in file", MB_OK);                                                                                   
+#else
+                                               fprintf(stderr, "[fatal error] File stop code recieved in %s - RTFM\n", file);
+#endif
+                                               exit(-1);
+                                       }
+                               }
+
+                               if (strcmp(var, "SHOWOPERS")==0) {
+                                       SHOWOPERS = aint;
+                               }
+                               if (strcmp(var, "SHOWOPERMOTD")==0) {
+                                       SHOWOPERMOTD = aint;
+                               }
+                               if (strcmp(var, "SOCKSBANTIME")==0) {
+                                       iConf.socksbantime = aint;
+                               }
+                               if (strcmp(var, "iNAH")==0) {
+                                               iNAH = aint;
+                                       }
+                               if (strcmp(var, "ALLOW_CHATOPS")==0) {
+                                       ALLOW_CHATOPS = aint;
+                               }
+                               if (strcmp(var, "HIDE_ULINES")==0) {
+                                       HIDE_ULINES = aint;
+                               }                               
+                               if (strcmp(var, "KILLDIFF")==0) {
+                               KILLDIFF = aint;
+               }
+                               continue;
+                }
+/*                      if (strcmp(var, "DOMAINNAME")==0) {
+                               AllocCpy(DOMAINNAME, setto);
+                               XtndCpy(DOMAINNAMEMASK, setto); 
+                        }
+*/
+                        /* uhm networks */
+                        if (strcmp(var, "ircnetwork")==0) {
+                               AllocCpy(ircnetwork, setto);
+                        } 
+                               else
+                        if (strcmp(var, "defserv")==0) {
+                               AllocCpy(defserv, setto);
+                        }
+                               else
+                        if (strcmp(var, "SERVICES_NAME")==0) {
+                               AllocCpy(SERVICES_NAME, setto);
+                        }
+                               else
+                        if (strcmp(var, "oper_host")==0) {
+                               AllocCpy(oper_host, setto);
+                        }
+                               else
+                        if (strcmp(var, "admin_host")==0) {
+                               AllocCpy(admin_host, setto);
+                        }
+                               else
+                        if (strcmp(var, "locop_host")==0) {
+                               AllocCpy(locop_host, setto);
+                        }
+                               else
+                        if (strcmp(var, "sadmin_host")==0) {
+                               AllocCpy(sadmin_host, setto);
+                        }
+                               else
+                        if (strcmp(var, "netadmin_host")==0) {
+                               AllocCpy(netadmin_host, setto);
+                        }                       
+               else
+                        if (strcmp(var, "techadmin_host")==0) {
+                               AllocCpy(techadmin_host, setto);
+                        }                       
+               else
+             if (strcmp(var, "coadmin_host")==0) {
+               AllocCpy(coadmin_host, setto);
+             }
+               else
+             if (strcmp(var, "hidden_host")==0) {
+               AllocCpy(hidden_host, setto);
+             }
+               else
+             if (strcmp(var, "netdomain")==0) {
+               AllocCpy(netdomain, setto);
+             }
+                               else
+                        if (strcmp(var, "helpchan")==0) {
+                               AllocCpy(helpchan, setto);
+                        }
+                               else
+                        if (strcmp(var, "STATS_SERVER")==0) {
+                               AllocCpy(STATS_SERVER, setto);
+                        }
+                               else
+                       if (strcmp(var, "KLINE_ADDRESS")==0) {
+                               AllocCpy(KLINE_ADDRESS, setto);
+                       }
+                               else
+                       if (strcmp(var, "SOCKS_BAN_MESSAGE")==0) {
+                               AllocCpy(iConf.socksbanmessage, setto);
+                       }
+                               else
+                       if (strcmp(var, "SOCKS_QUIT_MESSAGE")==0) {
+                               AllocCpy(iConf.socksquitmessage, setto);
+                       }
+                                               
+         }
+       }
+#ifndef _WIN32
+       fprintf(stderr, "* Loaded %s ..\n", file);
+#endif 
+}
+
+void   doneconf(void) {
+       
+}
+
+/* Report the unrealircd.conf info -codemastr*/
+void report_dynconf (aClient *sptr) 
+{
+       sendto_one(sptr, ":%s %i %s :*** Dynamic Configuration Report ***", me.name, RPL_TEXT, sptr->name);
+       sendto_one(sptr, ":%s %i %s :INCLUDE: %s", me.name, RPL_TEXT, sptr->name, INCLUDE);
+       sendto_one(sptr, ":%s %i %s :KLINE_ADDRESS: %s", me.name, RPL_TEXT, sptr->name, KLINE_ADDRESS);
+       sendto_one(sptr, ":%s %i %s :MODE_X: %i", me.name, RPL_TEXT, sptr->name, MODE_X);
+       sendto_one(sptr, ":%s %i %s :MODE_I: %i", me.name, RPL_TEXT, sptr->name, MODE_I);
+       sendto_one(sptr, ":%s %i %s :TRUEHUB: %i", me.name, RPL_TEXT, sptr->name, TRUEHUB);
+       sendto_one(sptr, ":%s %i %s :SHOWOPERS: %i", me.name, RPL_TEXT, sptr->name, SHOWOPERS);
+       sendto_one(sptr, ":%s %i %s :KILLDIFF: %i", me.name, RPL_TEXT, sptr->name, KILLDIFF);
+       sendto_one(sptr, ":%s %i %s :SHOWOPERMOTD: %i", me.name, RPL_TEXT, sptr->name, SHOWOPERMOTD);
+       sendto_one(sptr, ":%s %i %s :HIDE_ULINES: %i", me.name, RPL_TEXT, sptr->name, HIDE_ULINES);
+       sendto_one(sptr, ":%s %i %s :ALLOW_CHATOPS: %i", me.name, RPL_TEXT, sptr->name, ALLOW_CHATOPS);
+       sendto_one(sptr, ":%s %i %s :SOCKS_BAN_MESSAGE: %s", me.name, RPL_TEXT, sptr->name, iConf.socksbanmessage);
+       sendto_one(sptr, ":%s %i %s :SOCKS_QUIT_MESSAGE: %s", me.name, RPL_TEXT, sptr->name, iConf.socksquitmessage);
+       sendto_one(sptr, ":%s %i %s :SOCKSBANTIME: %i",me.name, RPL_TEXT, sptr->name, iConf.socksbantime);
+}
+
+/* Report the network file info -codemastr */
+void report_network (aClient *sptr)
+{
+sendto_one(sptr, ":%s %i %s :*** Network Configuration Report ***", me.name, RPL_TEXT, sptr->name);
+sendto_one(sptr, ":%s %i %s :NETWORK: %s", me.name, RPL_TEXT, sptr->name, ircnetwork);
+sendto_one(sptr, ":%s %i %s :DEFAULT_SERVER: %s", me.name, RPL_TEXT, sptr->name, defserv);
+sendto_one(sptr, ":%s %i %s :SERVICES_NAME: %s", me.name, RPL_TEXT, sptr->name, SERVICES_NAME);
+sendto_one(sptr, ":%s %i %s :OPER_HOST: %s", me.name, RPL_TEXT, sptr->name, oper_host);
+sendto_one(sptr, ":%s %i %s :ADMIN_HOST: %s", me.name, RPL_TEXT, sptr->name, admin_host);
+sendto_one(sptr, ":%s %i %s :LOCOP_HOST: %s", me.name, RPL_TEXT, sptr->name, locop_host);
+sendto_one(sptr, ":%s %i %s :SADMIN_HOST: %s", me.name, RPL_TEXT, sptr->name, sadmin_host);
+sendto_one(sptr, ":%s %i %s :NETADMIN_HOST: %s", me.name, RPL_TEXT, sptr->name, netadmin_host);
+sendto_one(sptr, ":%s %i %s :COADMIN_HOST: %s", me.name, RPL_TEXT, sptr->name, coadmin_host);
+sendto_one(sptr, ":%s %i %s :TECHADMIN_HOST: %s", me.name, RPL_TEXT, sptr->name, techadmin_host);
+sendto_one(sptr, ":%s %i %s :HIDDEN_HOST: %s", me.name, RPL_TEXT, sptr->name, hidden_host);
+sendto_one(sptr, ":%s %i %s :NETDOMAIN: %s", me.name, RPL_TEXT, sptr->name, netdomain);
+sendto_one(sptr, ":%s %i %s :HELPCHAN: %s", me.name, RPL_TEXT, sptr->name, helpchan);
+sendto_one(sptr, ":%s %i %s :STATS_SERVER: %s", me.name, RPL_TEXT, sptr->name, STATS_SERVER);
+sendto_one(sptr, ":%s %i %s :INAH: %i", me.name, RPL_TEXT, sptr->name, iNAH);
+}
diff --git a/src/fdlist.c b/src/fdlist.c
new file mode 100644 (file)
index 0000000..806a57b
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * fdlist.c   maintain lists of certain important fds 
+ */
+
+/* $Id$ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "config.h"
+#include "fdlist.h"
+
+void
+addto_fdlist(int fd, fdlist * listp)
+{
+   int index;
+
+   if ((index = ++listp->last_entry) >= MAXCONNECTIONS) {
+      /*
+       * list too big.. must exit 
+       */
+      --listp->last_entry;
+
+#ifdef USE_SYSLOG
+      (void) syslog(LOG_CRIT, "fdlist.c list too big.. must exit");
+#endif
+      abort();
+   }
+   else
+      listp->entry[index] = fd;
+   return;
+}
+
+void
+delfrom_fdlist(int fd, fdlist * listp)
+{
+   int i;
+
+   for (i = listp->last_entry; i; i--) {
+      if (listp->entry[i] == fd)
+        break;
+   }
+   if (!i)
+      return;                  /*
+                                * could not find it! 
+                                */
+   /*
+    * swap with last_entry 
+    */
+   if (i == listp->last_entry) {
+      listp->entry[i] = 0;
+      listp->last_entry--;
+      return;
+   }
+   else {
+      listp->entry[i] = listp->entry[listp->last_entry];
+      listp->entry[listp->last_entry] = 0;
+      listp->last_entry--;
+      return;
+   }
+}
+
+void
+init_fdlist(fdlist * listp)
+{
+   listp->last_entry = 0;
+   memset((char *) listp->entry, '\0', sizeof(listp->entry));
+   return;
+}
diff --git a/src/hash.c b/src/hash.c
new file mode 100644 (file)
index 0000000..9641608
--- /dev/null
@@ -0,0 +1,1170 @@
+       /************************************************************************
+ *   IRC - Internet Relay Chat, ircd/hash.c
+ *   Copyright (C) 1991 Darren Reed
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <limits.h>
+#include "numeric.h"
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "hash.h"
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1991 Darren Reed");
+ID_Notes("2.10 7/3/93");
+
+/* Quick & dirty inline version of mycmp for hash-tables -Donwulff */
+#define thecmp(str1, str2, where) { \
+                                    register char *st1=str1, *st2=str2; \
+                                    while (tolower(*st1)==tolower(*st2)) \
+                                    { \
+                                      if (!*st1) goto where; \
+                                      st1++; st2++; \
+                                    } \
+                                  }
+
+#ifdef DEBUGMODE
+static aHashEntry      *clientTable = NULL;
+static aHashEntry      *channelTable = NULL;
+static int     clhits, clmiss;
+static int     chhits, chmiss;
+int    HASHSIZE = 32003;
+int    CHANNELHASHSIZE = 10007;
+#else /* DEBUGMODE */
+static aHashEntry      clientTable[HASHSIZE];
+static aHashEntry      channelTable[CHANNELHASHSIZE];
+#endif /* DEBUGMODE */
+
+static aNotify *notifyTable[NOTIFYHASHSIZE];
+
+/*
+ * Hashing.
+ *
+ *   The server uses a chained hash table to provide quick and efficient
+ * hash table mantainence (providing the hash function works evenly over
+ * the input range).  The hash table is thus not susceptible to problems
+ * of filling all the buckets or the need to rehash.
+ *    It is expected that the hash table would look somehting like this
+ * during use:
+ *                   +-----+    +-----+    +-----+   +-----+
+ *                ---| 224 |----| 225 |----| 226 |---| 227 |---
+ *                   +-----+    +-----+    +-----+   +-----+
+ *                      |          |          |
+ *                   +-----+    +-----+    +-----+
+ *                   |  A  |    |  C  |    |  D  |
+ *                   +-----+    +-----+    +-----+
+ *                      |
+ *                   +-----+
+ *                   |  B  |
+ *                   +-----+
+ *
+ * A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
+ *
+ * The order shown above is just one instant of the server.  Each time a
+ * lookup is made on an entry in the hash table and it is found, the entry
+ * is moved to the top of the chain.
+ */
+
+#ifndef ELFHASH
+/*
+ * hash_nn_name
+ *
+ * Well, extensive profiling seems to indicate that the hash-function
+ * is a major provider to ircd's CPU-usage after all, so we're using
+ * _really_ minimalistic hash-function and make up for it with huge
+ * hash-tables. -Donwulff
+ */
+unsigned int hash_nn_name (hname)
+const char *hname;
+{
+       unsigned int hash_value;
+
+       for ( hash_value = 0; *hname; ++hname)
+           hash_value = ( hash_value << 2 ) ^ tolower(*hname);
+
+       return ( hash_value );
+}
+#else
+/* Take equal propotions from the size of int on all arcitechtures */
+#define BITS_IN_int             ( sizeof(int) * CHAR_BIT )
+#define THREE_QUARTERS         ((int) ((BITS_IN_int * 3) / 4))
+#define ONE_EIGHTH             ((int) (BITS_IN_int / 8))
+#define HIGH_BITS              ( ~((unsigned int)(~0) >> ONE_EIGHTH ))
+
+unsigned int hash_nn_name (hname)
+const char *hname;
+{
+       unsigned int hash_value, i;
+
+       for ( hash_value = 0; *hname; ++hname )
+       {
+           /* Shift hash-value by one eights of int for adding every letter */
+           hash_value = ( hash_value << ONE_EIGHTH ) + tolower(*hname);
+           /* If the next shift would cause an overflow... */
+           if (( i = hash_value & HIGH_BITS ) != 0 )
+               /* Then wrap the upper quarter of bits back to the value */
+               hash_value = ( hash_value ^ 
+                              ( i >> THREE_QUARTERS )) & ~HIGH_BITS;
+       }
+
+       return ( hash_value );
+}
+#endif
+
+/*
+ * clear_*_hash_table
+ *
+ * Nullify the hashtable and its contents so it is completely empty.
+ */
+void   clear_client_hash_table()
+{
+#ifdef DEBUGMODE
+       clhits = 0;
+       clmiss = 0;
+       if (!clientTable)
+               clientTable = (aHashEntry *)MyMalloc(HASHSIZE *
+                                                    sizeof(aHashEntry));
+#endif /* DEBUGMODE */
+
+       bzero((char *)clientTable, sizeof(aHashEntry) * HASHSIZE);
+}
+
+void   clear_channel_hash_table()
+{
+#ifdef DEBUGMODE
+       chmiss = 0;
+       chhits = 0;
+       if (!channelTable)
+               channelTable = (aHashEntry *)MyMalloc(CHANNELHASHSIZE *
+                                                    sizeof(aHashEntry));
+#endif /* DEBUGMODE */
+       bzero((char *)channelTable, sizeof(aHashEntry) * CHANNELHASHSIZE);
+}
+
+void   clear_notify_hash_table(void)
+{
+       bzero((char *)notifyTable, sizeof(notifyTable));
+}
+
+/*
+ * add_to_client_hash_table
+ */
+int    add_to_client_hash_table(name, cptr)
+char   *name;
+aClient        *cptr;
+{
+       int     hashv;
+       aClient *acptr;
+
+       hashv = hash_nn_name(name)%HASHSIZE;
+
+#ifdef DEBUGMODE
+       if(acptr=(aClient *)clientTable[hashv].list) {
+               while(acptr&&mycmp(acptr->name,name)) acptr=acptr->hnext;
+               if(acptr) dumpcore("add_to_client_hash_table %s",name);
+       }
+       cptr->hnext = (aClient *)clientTable[hashv].list;
+       clientTable[hashv].list = (void *)cptr;
+       clientTable[hashv].links++;
+       clientTable[hashv].hits++;
+#else /* DEBUGMODE */
+#ifdef INSERTCHECK
+       if(acptr=(aClient *)clientTable[hashv]) {
+               while(acptr&&mycmp(acptr->name,name)) acptr=acptr->hnext;
+               if(acptr) dumpcore("add_to_client_hash_table %s",name);
+       }
+#endif /* INSERTCHECK */
+       cptr->hnext = (aClient *)clientTable[hashv];
+       clientTable[hashv] = (void *)cptr;
+#endif /* DEBUGMODE */
+       return 0;
+}
+
+/*
+ * add_to_channel_hash_table
+ */
+int    add_to_channel_hash_table(name, chptr)
+char   *name;
+aChannel       *chptr;
+{
+       int     hashv;
+       aChannel        *chan;
+
+       hashv = hash_nn_name(name)%CHANNELHASHSIZE;
+
+#ifdef DEBUGMODE
+       if(chan=(aChannel *)channelTable[hashv].list) {
+               while(chan&&mycmp(chan->chname,name)) chan=chan->hnextch;
+               if(chan) dumpcore("add_to_channel_hash_table %s",name);
+       }
+       chptr->hnextch = (aChannel *)channelTable[hashv].list;
+       channelTable[hashv].list = (void *)chptr;
+       channelTable[hashv].links++;
+       channelTable[hashv].hits++;
+#else /* DEBUGMODE */
+#ifdef INSERTCHECK
+       if(chan=(aChannel *)channelTable[hashv]) {
+               while(chan&&mycmp(chan->chname,name)) chan=chan->hnextch;
+               if(chan) dumpcore("add_to_channel_hash_table %s",name);
+       }
+#endif /* INSERTCHECK */
+       chptr->hnextch = (aChannel *)channelTable[hashv];
+       channelTable[hashv] = (void *)chptr;
+#endif /* DEBUGMODE */
+       return 0;
+}
+
+/*
+ * Rough figure of the datastructures for notify:
+ *
+ * NOTIFY HASH      cptr1
+ *   |                |- nick1
+ * nick1-|- cptr1     |- nick2
+ *   |   |- cptr2                cptr3
+ *   |   |- cptr3   cptr2          |- nick1
+ *   |                |- nick1
+ * nick2-|- cptr2     |- nick2
+ *       |- cptr1
+ *
+ * add-to-notify-hash-table:
+ * del-from-notify-hash-table:
+ * hash-del-notify-list:
+ * hash-check-notify:
+ * hash-get-notify:
+ */
+
+/*
+ * count_watch_memory
+ */
+void   count_watch_memory(count, memory)
+int    *count;
+u_long *memory;
+{
+       int     i = NOTIFYHASHSIZE;
+       aNotify *anptr;
+
+
+       while (i--) {
+               anptr = notifyTable[i];
+               while (anptr) {
+                       (*count)++;
+                       (*memory) += sizeof(aNotify)+strlen(anptr->nick);
+                       anptr = anptr->hnext;
+               }
+       }
+}
+
+/*
+ * add_to_notify_hash_table
+ */
+int    add_to_notify_hash_table(nick, cptr)
+char   *nick;
+aClient        *cptr;
+{
+       int     hashv;
+       aNotify *anptr;
+       Link    *lp;
+
+
+       /* Get the right bucket... */
+       hashv = hash_nn_name(nick)%NOTIFYHASHSIZE;
+
+       /* Find the right nick (header) in the bucket, or NULL... */
+       if ((anptr = (aNotify *)notifyTable[hashv]))
+               while (anptr && mycmp(anptr->nick, nick))
+                       anptr = anptr->hnext;
+
+       /* If found NULL (no header for this nick), make one... */
+       if (!anptr) {
+               anptr = (aNotify *)MyMalloc(sizeof(aNotify)+strlen(nick));
+               anptr->lasttime = 0;
+               strcpy(anptr->nick, nick);
+
+               anptr->notify = NULL;
+
+               anptr->hnext = notifyTable[hashv];
+               notifyTable[hashv] = anptr;
+       }
+
+       /* Is this client already on the notify-list? */
+       if ((lp = anptr->notify))
+               while (lp && (lp->value.cptr != cptr))
+                       lp = lp->next;
+
+       /* No it isn't, so add it in the bucket and client addint it */
+       if (!lp) {
+               lp = anptr->notify;
+               anptr->notify = make_link();
+               anptr->notify->value.cptr = cptr;
+               anptr->notify->next = lp;
+
+               lp = make_link();
+               lp->next = cptr->notify;
+               lp->value.nptr = anptr;
+               cptr->notify = lp;
+               cptr->notifies++;
+       }
+
+       return 0;
+}
+
+/*
+ * hash_check_notify
+ */
+int    hash_check_notify(cptr, reply)
+aClient        *cptr;
+int    reply;
+{
+       int     hashv;
+       aNotify *anptr;
+       Link    *lp;
+
+
+       /* Get us the right bucket */
+       hashv = hash_nn_name(cptr->name)%NOTIFYHASHSIZE;
+
+       /* Find the right header in this bucket */
+       if ((anptr = (aNotify *)notifyTable[hashv]))
+               while (anptr && mycmp(anptr->nick, cptr->name))
+                       anptr = anptr->hnext;
+       if (!anptr)
+               return 0;       /* This nick isn't on notify */
+
+       /* Update the time of last change to item */
+       anptr->lasttime = time(NULL);
+
+       /* Send notifies out to everybody on the list in header */
+       for (lp = anptr->notify; lp; lp = lp->next)
+               sendto_one(lp->value.cptr, rpl_str(reply), me.name,
+                       lp->value.cptr->name, cptr->name,
+                       (IsPerson(cptr)?cptr->user->username:"<N/A>"),
+                       (IsPerson(cptr)?
+                        (IsHidden(cptr) ? cptr->user->virthost : cptr->user->realhost) :"<N/A>"),
+                       anptr->lasttime, cptr->info);
+
+       return 0;
+}
+
+/*
+ * hash_get_notify
+ */
+aNotify        *hash_get_notify(name)
+char   *name;
+{
+       int     hashv;
+       aNotify *anptr;
+
+
+       hashv = hash_nn_name(name)%NOTIFYHASHSIZE;
+
+       if ((anptr = (aNotify *)notifyTable[hashv]))
+               while (anptr && mycmp(anptr->nick, name))
+                       anptr = anptr->hnext;
+
+       return anptr;
+}
+
+/*
+ * del_from_notify_hash_table
+ */
+int    del_from_notify_hash_table(nick, cptr)
+char   *nick;
+aClient        *cptr;
+{
+       int     hashv;
+       aNotify *anptr, *nlast = NULL;
+       Link    *lp, *last = NULL;
+
+
+       /* Get the bucket for this nick... */
+       hashv = hash_nn_name(nick)%NOTIFYHASHSIZE;
+
+       /* Find the right header, maintaining last-link pointer... */
+       if ((anptr = (aNotify *)notifyTable[hashv]))
+               while (anptr && mycmp(anptr->nick, nick)) {
+                       nlast = anptr;
+                       anptr = anptr->hnext;
+               }
+       if (!anptr)
+               return 0;       /* No such notify */
+
+       /* Find this client from the list of notifies... with last-ptr. */
+       if ((lp = anptr->notify))
+               while (lp && (lp->value.cptr != cptr)) {
+                       last = lp;
+                       lp = lp->next;
+               }
+       if (!lp)
+               return 0;       /* No such client to notify */
+
+       /* Fix the linked list under header, then remove the notify entry */
+       if (!last)
+               anptr->notify = lp->next;
+       else
+               last->next = lp->next;
+       free_link(lp);
+
+       /* Do the same regarding the links in client-record... */
+       last = NULL;
+       if ((lp = cptr->notify))
+               while (lp && (lp->value.nptr != anptr)) {
+                       last = lp;
+                       lp = lp->next;
+               }
+
+       /*
+        * Give error on the odd case... probobly not even neccessary
+        *
+        * No error checking in ircd is unneccessary ;) -Cabal95
+        */
+       if (!lp)
+               sendto_ops("WATCH debug error: del_from_notify_hash_table "
+                          "found a watch entry with no client "
+                          "counterpoint processing nick %s on client %s!",
+                          nick, cptr->user);
+       else {
+               if (!last) /* First one matched */
+                       cptr->notify = lp->next;
+               else
+                       last->next = lp->next;
+               free_link(lp);
+       }
+
+       /* In case this header is now empty of notices, remove it */
+       if (!anptr->notify) {
+               if (!nlast)
+                       notifyTable[hashv] = anptr->hnext;
+               else
+                       nlast->hnext = anptr->hnext;
+               MyFree(anptr);
+       }
+
+       /* Update count of notifies on nick */
+       cptr->notifies--;
+
+       return 0;
+}
+
+/*
+ * hash_del_notify_list
+ */
+int    hash_del_notify_list(cptr)
+aClient        *cptr;
+{
+       int     hashv;
+       aNotify *anptr;
+       Link    *np, *lp, *last;
+
+
+       if (!(np = cptr->notify))
+               return 0;       /* Nothing to do */
+
+       cptr->notify = NULL;    /* Break the notify-list for client */
+       while (np) {
+               /* Find the notify-record from hash-table... */
+               anptr = np->value.nptr;
+               last = NULL;
+               for (lp = anptr->notify; lp && (lp->value.cptr != cptr);
+                    lp = lp->next)
+                       last = lp;
+
+               /* Not found, another "worst case" debug error */
+               if (!lp)
+                       sendto_ops("WATCH Debug error: hash_del_notify_list "
+                                  "found a WATCH entry with no table "
+                                  "counterpoint processing client %s!",
+                                  cptr->name);
+               else {
+                       /* Fix the notify-list and remove entry */
+                       if (!last)
+                               anptr->notify = lp->next;
+                       else
+                               last->next = lp->next;
+                       free_link(lp);
+
+                       /*
+                        * If this leaves a header without notifies,
+                        * remove it. Need to find the last-pointer!
+                        */
+                       if (!anptr->notify) {
+                               aNotify *np2, *nl;
+
+                               hashv = hash_nn_name(anptr->nick)%NOTIFYHASHSIZE;
+
+                               nl = NULL;
+                               np2 = notifyTable[hashv];
+                               while (np2 != anptr) {
+                                       nl = np2;
+                                       np2 = np2->hnext;
+                               }
+
+                               if (nl)
+                                       nl->hnext = anptr->hnext;
+                               else
+                                       notifyTable[hashv] = anptr->hnext;
+                               MyFree(anptr);
+                       }
+               }
+
+               lp = np;        /* Save last pointer processed */
+               np = np->next;  /* Jump to the next pointer */
+               free_link(lp);  /* Free the previous */
+       }
+
+       cptr->notifies = 0;
+
+       return 0;
+}
+
+
+/*
+ * del_from_client_hash_table
+ */
+int    del_from_client_hash_table(name, cptr)
+char   *name;
+aClient        *cptr;
+{
+       Reg1    aClient *tmp, *prev = NULL;
+       Reg2    int     hashv;
+
+       hashv = hash_nn_name(name)%HASHSIZE;
+#ifdef DEBUGMODE
+       for (tmp = (aClient *)clientTable[hashv].list; tmp; tmp = tmp->hnext)
+           {
+               if (tmp == cptr)
+                   {
+                       if (prev)
+                               prev->hnext = tmp->hnext;
+                       else
+                               clientTable[hashv].list = (void *)tmp->hnext;
+                       tmp->hnext = NULL;
+                       if (clientTable[hashv].links > 0)
+                           {
+                               clientTable[hashv].links--;
+                               return 1;
+                           } 
+                       else
+                               /*
+                                * Should never actually return from here and
+                                * if we do it is an error/inconsistency in the
+                                * hash table.
+                                */
+                               return -1;
+                       return 0; /* Found, we can return -Donwulff */
+               }
+               prev = tmp;
+       }
+#else /* DEBUGMODE */
+       for (tmp = (aClient *)clientTable[hashv]; tmp; tmp = tmp->hnext) {
+               if (tmp == cptr) {
+                       if (prev)
+                               prev->hnext = tmp->hnext;
+                       else
+                               clientTable[hashv] = (void *)tmp->hnext;
+                       tmp->hnext = NULL;
+                       return 0; /* Found, we can return -Donwulff */
+               }
+               prev = tmp;
+           }
+#endif /* DEBUGMODE */
+       return 0;
+}
+
+/*
+ * del_from_channel_hash_table
+ */
+int    del_from_channel_hash_table(name, chptr)
+char   *name;
+aChannel       *chptr;
+{
+       Reg1    aChannel        *tmp, *prev = NULL;
+       Reg2    int     hashv;
+
+       hashv = hash_nn_name(name)%CHANNELHASHSIZE;
+#ifdef DEBUGMODE
+       for (tmp = (aChannel *)channelTable[hashv].list; tmp;
+            tmp = tmp->hnextch)
+           {
+               if (tmp == chptr)
+                   {
+                       if (prev)
+                               prev->hnextch = tmp->hnextch;
+                       else
+                               channelTable[hashv].list=(void *)tmp->hnextch;
+                       tmp->hnextch = NULL;
+                       if (channelTable[hashv].links > 0)
+                           {
+                               channelTable[hashv].links--;
+                               return 1;
+                           }
+                       else
+                               return -1;
+                       return 0; /* Found, we can return -Donwulff */
+                   }
+               prev = tmp;
+           }
+#else /* DEBUGMODE */
+       for (tmp = (aChannel *)channelTable[hashv]; tmp; tmp = tmp->hnextch) {
+               if (tmp == chptr) {
+                       if (prev)
+                               prev->hnextch = tmp->hnextch;
+                       else
+                               channelTable[hashv]=(void *)tmp->hnextch;
+                       tmp->hnextch = NULL;
+                       return 0; /* Found, we can return -Donwulff */
+               }
+               prev = tmp;
+       }
+#endif /* DEBUGMODE */
+       return 0;
+}
+
+
+/*
+ * hash_get_chan_bucket
+ */
+aChannel       *hash_get_chan_bucket(hashv)
+int    hashv;
+{
+       if (hashv > CHANNELHASHSIZE)
+               return NULL;
+#ifdef DEBUGMODE
+       return (aChannel *)channelTable[hashv].list;
+#else
+       return (aChannel *)channelTable[hashv];
+#endif
+}
+
+
+/*
+ * hash_find_client
+ */
+aClient        *hash_find_client(name, cptr)
+char   *name;
+aClient        *cptr;
+{
+       Reg1    aClient *tmp;
+       Reg2    aClient *prv = NULL;
+#ifdef DEBUGMODE
+       Reg3    aHashEntry      *tmp3;
+#endif /* DEBUGMODE */
+       int     hashv;
+
+       hashv = hash_nn_name(name)%HASHSIZE;
+
+       /*
+        * Got the bucket, now search the chain.
+        */
+#ifdef  DEBUGMODE
+tmp3 = &clientTable[hashv];
+
+       for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+               thecmp(name, tmp->name, c_move_to_top);
+       clmiss++;
+       return (cptr);
+c_move_to_top:
+       clhits++;
+       /*
+        * If the member of the hashtable we found isnt at the top of its
+        * chain, put it there.  This builds a most-frequently used order into
+        * the chains of the hash table, giving speadier lookups on those nicks
+        * which are being used currently.  This same block of code is also
+        * used for channels and servers for the same performance reasons.
+        */
+       if (prv)
+           {
+               aClient *tmp2;
+
+               tmp2 = (aClient *)tmp3->list;
+               tmp3->list = (void *)tmp;
+               prv->hnext = tmp->hnext;
+               tmp->hnext = tmp2;
+           }
+#else /* DEBUGMODE */
+       for (tmp = (aClient *)clientTable[hashv]; tmp; prv = tmp, tmp = tmp->hnext)
+               thecmp(name, tmp->name, c_move_to_top);
+       return (cptr);
+c_move_to_top:
+       if (prv) {
+               aClient *tmp2;
+
+               tmp2 = (aClient *)clientTable[hashv];
+               clientTable[hashv] = (void *)tmp;
+               prv->hnext = tmp->hnext;
+               tmp->hnext = tmp2;
+       }
+#endif /* DEBUGMODE */
+       return (tmp);
+}
+
+/*
+ * hash_find_nickserver
+ */
+aClient        *hash_find_nickserver(name, cptr)
+char   *name;
+aClient *cptr;
+{
+       Reg1    aClient *tmp;
+       Reg2    aClient *prv = NULL;
+#ifdef DEBUGMODE
+       Reg3    aHashEntry      *tmp3;
+#endif /* DEBUGMODE */
+       int     hashv;
+       char    *serv;
+
+       serv = index(name, '@');
+       *serv++ = '\0';
+       hashv = hash_nn_name(name)%HASHSIZE;
+
+       /*
+        * Got the bucket, now search the chain.
+        */
+#ifdef  DEBUGMODE
+tmp3 = &clientTable[hashv];
+       for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+               if (tmp->user &&
+                    mycmp(name, tmp->name) == 0 &&
+                   mycmp(serv, tmp->user->server) == 0)
+                       goto c_move_to_top;
+
+       clmiss++;
+/*     *--serv = '\0'; */ /* This code has no function, perhaps meant @? */
+       return (cptr);     /* For now, just remarking it out... -Donwulff */
+
+c_move_to_top:
+       clhits++;
+       if (prv)
+           {
+               aClient *tmp2;
+
+               tmp2 = (aClient *)tmp3->list;
+               tmp3->list = (void *)tmp;
+               prv->hnext = tmp->hnext;
+               tmp->hnext = tmp2;
+           }
+#else /* DEBUGMODE */
+       for (tmp = (aClient *)clientTable[hashv]; tmp; prv = tmp, tmp = tmp->hnext)
+               if (tmp->user &&
+                   mycmp(name, tmp->name) == 0 &&
+                   mycmp(serv, tmp->user->server) == 0)
+                       goto c_move_to_top;
+/*     *--serv = '\0'; */ /* This code has no function, perhaps meant @? */
+       return (cptr);     /* For now, just remarking it out... -Donwulff */
+
+c_move_to_top:
+       if (prv) {
+               aClient *tmp2;
+
+               tmp2 = (aClient *)clientTable[hashv];
+               clientTable[hashv] = (void *)tmp;
+               prv->hnext = tmp->hnext;
+               tmp->hnext = tmp2;
+       }
+#endif /* DEBUGMODE */
+/*     *--serv = '\0'; */ /* This code has no function, perhaps meant @? */
+       return (tmp);      /* For now, just remarking it out... -Donwulff */
+}
+
+/*
+ * hash_find_server
+ */
+aClient        *hash_find_server(server, cptr)
+char   *server;
+aClient *cptr;
+{
+       Reg1    aClient *tmp, *prv = NULL;
+       Reg2    char    *t;
+       Reg3    char    ch;
+#ifdef DEBUGMODE
+       aHashEntry      *tmp3;
+#endif /* DEBUGMODE */
+
+       int hashv;
+
+       hashv = hash_nn_name(server)%HASHSIZE;
+
+#ifdef  DEBUGMODE
+       tmp3 = &clientTable[hashv];
+
+       for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
+           {
+               if (!IsServer(tmp) && !IsMe(tmp))
+                       continue;
+               thecmp(server, tmp->name, s_move_to_top);
+           }
+#else /* DEBUGMODE */
+       for (tmp = (aClient *)clientTable[hashv]; tmp; prv = tmp, tmp = tmp->hnext) {
+               if (!IsServer(tmp) && !IsMe(tmp))
+                       continue;
+               thecmp(server, tmp->name, s_move_to_top);
+       }
+#endif /* DEBUGMODE */
+       t = ((char *)server + strlen(server));
+       /*
+        * Whats happening in this next loop ? Well, it takes a name like
+        * foo.bar.edu and proceeds to search for *.edu and then *.bar.edu.
+        * This is for checking full server names against masks although
+        * it isnt often done this way in lieu of using match().
+        */
+       for (;;)
+           {
+               t--;
+               for (; t > server; t--)
+                       if (*(t+1) == '.')
+                               break;
+               if (t <= server || *t == '*')
+                       break;
+               ch = *t;
+               *t = '*';
+               /*
+                * Dont need to check IsServer() here since nicknames cant
+                *have *'s in them anyway.
+                */
+               if (((tmp = hash_find_client(t, cptr))) != cptr)
+                   {
+                       *t = ch;
+                       return (tmp);
+                   }
+               *t = ch;
+           }
+#ifdef DEBUGMODE
+       clmiss++;
+       return (cptr);
+s_move_to_top:
+       clhits++;
+
+       if (prv)
+           {
+               aClient *tmp2;
+
+               tmp2 = (aClient *)tmp3->list;
+               tmp3->list = (void *)tmp;
+               prv->hnext = tmp->hnext;
+               tmp->hnext = tmp2;
+           }
+#else /* DEBUGMODE */
+       return (cptr);
+s_move_to_top:
+       if (prv) {
+               aClient *tmp2;
+
+               tmp2 = (aClient *)clientTable[hashv];
+               clientTable[hashv] = (void *)tmp;
+               prv->hnext = tmp->hnext;
+               tmp->hnext = tmp2;
+       }
+#endif /* DEBUGMODE */
+       return (tmp);
+}
+
+/*
+ * hash_find_channel
+ */
+aChannel       *hash_find_channel(name, chptr)
+char   *name;
+aChannel *chptr;
+{
+       int     hashv;
+       Reg1    aChannel        *tmp;
+       Reg2    aChannel        *prv = NULL;
+#ifdef DEBUGMODE
+       aHashEntry      *tmp3;
+#endif /* DEBUGMODE */
+       hashv = hash_nn_name(name)%CHANNELHASHSIZE;
+
+#ifdef  DEBUGMODE
+       tmp3 = &channelTable[hashv];
+
+       for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch)
+               thecmp(name, tmp->chname, c_move_to_top);
+       chmiss++;
+       return chptr;
+c_move_to_top:
+       chhits++;
+       if (prv)
+           {
+               register aChannel *tmp2;
+
+               tmp2 = (aChannel *)tmp3->list;
+               tmp3->list = (void *)tmp;
+               prv->hnextch = tmp->hnextch;
+               tmp->hnextch = tmp2;
+           }
+#else /* DEBUGMODE */
+       for (tmp = (aChannel *)channelTable[hashv]; tmp; prv = tmp, tmp = tmp->hnextch)
+               thecmp(name, tmp->chname, c_move_to_top);
+       return chptr;
+c_move_to_top:
+       if(prv) {
+               register        aChannel        *tmp2;
+
+               tmp2 = (aChannel *)channelTable[hashv];
+               channelTable[hashv] = (void *)tmp;
+               prv->hnextch = tmp->hnextch;
+               tmp->hnextch = tmp2;
+       }
+#endif /* DEBUGMODE */
+       return (tmp);
+}
+
+/*
+ * NOTE: this command is not supposed to be an offical part of the ircd
+ *       protocol.  It is simply here to help debug and to monitor the
+ *       performance of the hash functions and table, enabling a better
+ *       algorithm to be sought if this one becomes troublesome.
+ *       -avalon
+ */
+
+int    m_hash(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+#ifndef DEBUGMODE
+       return 0;
+#else
+       register        int     l, i;
+       register        aHashEntry      *tab;
+       int     deepest = 0, deeplink = 0, showlist = 0, tothits = 0;
+       int     mosthit = 0, mosthits = 0, used = 0, used_now = 0, totlink = 0;
+       int     link_pop[10], size = HASHSIZE;
+       char    ch;
+       aHashEntry      *table;
+
+       if(!IsPrivileged(sptr)) return 0;
+
+       if (parc > 1) {
+               ch = *parv[1];
+               if (islower(ch))
+                       table = clientTable;
+               else {
+                       table = channelTable;
+                       size = CHANNELHASHSIZE;
+               }
+               if (ch == 'L' || ch == 'l')
+                       showlist = 1;
+       } else {
+               ch = '\0';
+               table = clientTable;
+       }
+
+       for (i = 0; i < 10; i++)
+               link_pop[i] = 0;
+       for (i = 0; i < size; i++) {
+               tab = &table[i];
+               l = tab->links;
+               if (showlist)
+                   sendto_one(sptr,
+                          "NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d",
+                          parv[0], i, tab->hits, l);
+               if (l > 0) {
+                       if (l < 10)
+                               link_pop[l]++;
+                       else
+                               link_pop[9]++;
+                       used_now++;
+                       totlink += l;
+                       if (l > deepest) {
+                               deepest = l;
+                               deeplink = i;
+                       }
+               }
+               else
+                       link_pop[0]++;
+               l = tab->hits;
+               if (l) {
+                       used++;
+                       tothits += l;
+                       if (l > mosthits) {
+                               mosthits = l;
+                               mosthit = i;
+                       }
+               }
+       }
+       switch((int)ch)
+       {
+       case 'V' : case 'v' :
+           {
+               register        aClient *acptr;
+               int     bad = 0, listlength = 0;
+
+               for (acptr = client; acptr; acptr = acptr->next) {
+                       if (hash_find_client(acptr->name,acptr) != acptr) {
+                               if (ch == 'V')
+                               sendto_one(sptr, "NOTICE %s :Bad hash for %s",
+                                          parv[0], acptr->name);
+                               bad++;
+                       }
+                       listlength++;
+               }
+               sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d",
+                          parv[0], listlength, bad);
+           }
+       case 'P' : case 'p' :
+               for (i = 0; i < 10; i++)
+                       sendto_one(sptr,"NOTICE %s :Entires with %d links : %d",
+                       parv[0], i, link_pop[i]);
+               return (0);
+       case 'r' :
+           {
+               Reg1    aClient *acptr;
+
+               sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]);
+               clear_client_hash_table();
+               for (acptr = client; acptr; acptr = acptr->next)
+                       (void)add_to_client_hash_table(acptr->name, acptr);
+               break;
+           }
+       case 'R' :
+           {
+               Reg1    aChannel        *acptr;
+
+               sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]);
+               clear_channel_hash_table();
+               for (acptr = channel; acptr; acptr = acptr->nextch)
+                       (void)add_to_channel_hash_table(acptr->chname, acptr);
+               break;
+           }
+       case 'H' :
+               if (parc > 2)
+                       sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
+                                  parv[0], parv[2],
+                       hash_nn_name(parv[2])%CHANNELHASHSIZE);
+               return (0);
+       case 'h' :
+               if (parc > 2)
+                       sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
+                                  parv[0], parv[2],
+                       hash_nn_name(parv[2])%HASHSIZE);
+               return (0);
+/* Quick hack for getting memory statistics from list.c -Donwulff */
+       case 'm' :
+               send_listinfo(sptr, parv[0]);
+               return(0);
+       case 'n' :
+           {
+               aClient *tmp;
+               int     max;
+
+               if (parc <= 2)
+                       return (0);
+               l = atoi(parv[2]) % HASHSIZE;
+               if (parc > 3)
+                       max = atoi(parv[3]) % HASHSIZE;
+               else
+                       max = l;
+               for (;l <= max; l++)
+                       for (i = 0, tmp = (aClient *)clientTable[l].list; tmp;
+                            i++, tmp = tmp->hnext)
+                           {
+                               if (parv[1][2] == '1' && tmp != tmp->from)
+                                       continue;
+                               sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
+                                          parv[0], l, i, tmp->name);
+                           }
+               return (0);
+           }
+       case 'N' :
+           {
+               aChannel *tmp;
+               int     max;
+
+               if (parc <= 2)
+                       return (0);
+               l = atoi(parv[2]) % CHANNELHASHSIZE;
+               if (parc > 3)
+                       max = atoi(parv[3]) % CHANNELHASHSIZE;
+               else
+                       max = l;
+               for (;l <= max; l++)
+                       for (i = 0, tmp = (aChannel *)channelTable[l].list; tmp;
+                            i++, tmp = tmp->hnextch)
+                               sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
+                                          parv[0], l, i, tmp->chname);
+               return (0);
+           }
+       case 'z' :
+           {
+               Reg1    aClient *acptr;
+
+               if (parc <= 2)
+                       return 0;
+               l = atoi(parv[2]);
+               if (l < 256)
+                       return 0;
+               (void)MyFree((char *)clientTable);
+               clientTable = (aHashEntry *)MyMalloc(sizeof(aHashEntry) * l);
+               HASHSIZE = l;
+               clear_client_hash_table();
+               for (acptr = client; acptr; acptr = acptr->next)
+                   {
+                       acptr->hnext = NULL;
+                       (void)add_to_client_hash_table(acptr->name, acptr);
+                   }
+               sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l);
+               break;
+           }
+       case 'Z' :
+           {
+               Reg1    aChannel        *acptr;
+
+               if (parc <= 2)
+                       return 0;
+               l = atoi(parv[2]);
+               if (l < 256)
+                       return 0;
+               (void)MyFree((char *)channelTable);
+               channelTable = (aHashEntry *)MyMalloc(sizeof(aHashEntry) * l);
+               CHANNELHASHSIZE = l;
+               clear_channel_hash_table();
+               for (acptr = channel; acptr; acptr = acptr->nextch)
+                   {
+                       acptr->hnextch = NULL;
+                       (void)add_to_channel_hash_table(acptr->chname, acptr);
+                   }
+               sendto_one(sptr, "NOTICE %s :CHANNELHASHSIZE now %d",
+                          parv[0], l);
+               break;
+           }
+       default :
+               break;
+       }
+       sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d",
+                  parv[0], totlink, used_now, size);
+       if (!used_now)
+               used_now = 1;
+    sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %%Full: %f",
+                 parv[0], (float)((1.0 * totlink) / (1.0 * used_now)),
+                 (float)((1.0 * used_now) / (1.0 * size)));
+       sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d",
+                  parv[0], deeplink, deepest);
+       if (!used)
+               used = 1;
+       sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f",
+                  parv[0], tothits, size-used,
+                  (float)((1.0 * tothits) / (1.0 * used)));
+       sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d",
+                  parv[0], mosthit, mosthits);
+       sendto_one(sptr,"NOTICE %s :Client hits %d miss %d",
+                  parv[0], clhits, clmiss);
+       sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d",
+                  parv[0], chhits, chmiss);
+       return 0;
+#endif /* DEBUGMODE */
+}
diff --git a/src/help.c b/src/help.c
new file mode 100644 (file)
index 0000000..0e625f0
--- /dev/null
@@ -0,0 +1,548 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/help.c
+ *   Copyright (C) 1996 DALnet
+ *
+ *   This program is free software; you can 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.
+ */
+
+/*
+ * Updated to use UnrealIRCd commands -Techie/Stskeeps
+ *
+*/
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("DALnet & Techie");
+ID_Notes("6.20 7/5/99");
+
+void xx(sptr, str, num)
+aClient *sptr;
+char *str;
+int num;
+{
+       if (sptr == NULL) {
+               printf("%s\n", str);
+               return;
+       }
+               sendto_one(sptr, ":%s %i %s :%s", me.name, num, sptr->name, str);
+}
+
+#define HDR(str) xx(sptr, str, 290)
+#define SND(str) xx(sptr, str, 291)
+#define FTR(str) xx(sptr, str, 292)
+#define HLP(str) xx(sptr, str, 293)
+
+/*
+ * This is _not_ the final help.c, we're just testing the functionality...
+ * Return 0 to forward request to helpops... -Donwulff
+ */
+extern struct Message msgtab[];
+int parse_help (sptr, name, help)
+aClient        *sptr;
+char   *name;
+char   *help;
+{
+
+   int i;  
+//     sendto_one(sptr, ":%s NOTICE %s :%s", me.name, sptr->name, help);
+
+  if(BadPtr(help)) {
+HDR(" ***** \ 2UnrealIRCd Help System\ 2 *****");
+SND("  You need to specify your question after the help-command");
+SND("  If the IRC Server is unable to satisfy your help-request");
+SND("  it will be forwarded to appropriate people for handling.");
+SND("  Preceed your question with ! to automatically forward it to");
+SND("  qualified helpers, or ? to never forward it.");
+SND("  Else type /HELPOP CMDS to get some help on the IRCd");
+SND("  /HELPOP ABOUT gets some info about UnrealIRCd");
+  }
+   else if (!myncmp(help, "CMDS", 8)) {
+         HDR(" *** UnrealIRCd Commands *** ");
+         SND(" Currently help is available on these commands ");
+         SND(" Use /HelpOp <command name> to get info about the command");
+         SND(" WATCH      HELPOP    LIST");
+         SND(" PRIVMSG    KNOCK     LICENSE");
+         SND(" SETNAME    MODE      STATSERV");
+         SND(" CREDITS    DALINFO");
+         SND(" ----------------------------");
+         SND(" OPERCMDS   - IRCop Commands");
+         SND(" UMODES     - Usermodes");
+         SND(" CHMODES    - Channelmodes");
+         SND(" OFLAGS     - O:Line flags");
+         SND(" -----------oOo------------");
+   }
+  else if (!myncmp(help, "ABOUT", 8)) {
+       HDR(" *** About UnrealIRCd ***");
+       SND("I started making UnrealIRCd about 3-4 months ago.");
+       SND("First it was called mpx2.0b13.soundforge - as I was");
+       SND("inspired of the 'forge' word. I quickly changed name");
+       SND("after I realized the IRCd had more potential for other");
+       SND("IRC nets. Unreal is based off df4.6.5 and some of");
+       SND("First lemme");
+       SND("introduce myself. My nick is Techie/Stskeeps. I hang");
+       SND("out at Global-IRC.net, DALnet, DragonWings.org and so on");
+       SND("--");
+       SND("Unreal is a hybrid of Dreamforge (as I said) mixed with some");
+       SND("Twilight IRCd, TerraIRCd, TS4 (channel mode +h & +e) features");
+       SND("(IMHO TwilightIRCd is one of the best dreamforge hybrids I've seen!)");
+       SND("Unreal is not a rip-off of other IRCds - I added a lot of features myself!");
+       SND("I really cannot mention some major features as I think a IRCd is a");
+       SND("IRCd when it has got useful commands- and people actually say mine has!");
+       SND("--");
+       SND("Anyways I dunt demand donations or anything. I just do coding for fun");
+       SND("I treat coding like playing with toys. It makes me happy(or is it just");
+       SND("caffeine?;). An addy to send donations is at the Donation file in the IRCd dir");
+       SND("I would be more happy if someone e-mailed me with ideas");
+       SND("to the IRCd.. The whole IRCd is GNU so if you want to rip off any of my ideas");
+       SND("You are generally welcome:) Just remember to do what's said in the Changes file!");
+       SND("-- So.. Enjoy this IRCd:)");
+       SND("   -- Carsten Munk / Techie .. =)");       
+  }
+   else if (!myncmp(help, "WATCH", 8)) {
+      HDR(" *** WATCH Command ***");
+       SND("Watch is a new notify-type system in UnrealIRCd which is both faster");
+       SND("and uses less network resources than any old-style notify");
+       SND("system. You may add entries to your Watch list with the command");
+       SND("/watch +nick1 [+nick2 +nick3 ..., and the server will send");
+       SND("you a message when any nickname in your watch list logs on or off.");
+       SND("Use /watch -nick to remove a nickname from the watch list, and");
+       SND("just /watch to view your watch list.");
+       SND("The watch list DOES NOT REMAIN BETWEEN SESSIONS - you (or your");
+       SND("script or client) must add the nicknames to your watch list every");
+       SND("time you connect to an IRC server. /Watch was made in DreamForge IRCd");
+       SND("which UnrealIRCd in ground is based off");
+   }
+   else if (!myncmp(help, "HELPOP", 8)) {
+       HDR(" *** HELPOP Command ***");
+       SND("HelpOp is a new system of getting IRC Server help. You type either");
+       SND("/HelpOp ? <help system topic>  or /HelpOp ! <question>");
+       SND("The Ã¯?ï in /HelpOp means query the help system and if you get no");
+       SND("response you can choose '!' to send it to the Help Operators online");
+       SND("------------oOo--------------");
+   }
+   else if (!myncmp(help, "LIST", 8)) {
+           HDR(" *** LIST Command ***");
+               SND("New extended /list command options are supported.  To use these");
+               SND("features, you will likely need to prefix the LIST command with");
+               SND("/quote to avoid your client interpreting the command.");
+               SND("");
+               SND("Usage: /quote LIST options");
+               SND("");
+               SND("If you don't include any options, the default is to send you the");
+               SND("entire unfiltered list of channels. Below are the options you can");
+               SND("use, and what channels LIST will return when you use them.");
+               SND(">number  List channels with more than <number> people.");
+               SND("<number  List channels with less than <number> people.");
+               SND("C>number List channels created between now and <number> minutes ago.");
+               SND("C<number List channels created earlier than <number> minutes ago.");
+               SND("T>number List channels whose topics are older than <number> minutes");
+               SND("         (Ie., they have not changed in the last <number> minutes.");
+               SND("T<number List channels whose topics are newer than <number> minutes.");
+               SND("*mask*   List channels that match *mask*");
+               SND("!*mask*  List channels that do not match *mask*");
+               SND("LIST defaults to sending a list of channels with 2 or more members,");
+               SND("so use the >0 option to get the full channel listing.");  
+    }
+       else if (!myncmp(help, "PRIVMSG", 8)) {
+               HDR("*** PRIVMSG Command ***");
+               SND("PRIVMSG and NOTICE, which are used internally by the client for");
+               SND("/msg and /notice, in UnrealIRCd support two additional formats:");
+               SND("/msg @#channel <text> will send the text to channel-ops on the");
+               SND("given channel only. /msg @+#channel <text> will send the text");
+               SND("to both ops and voiced users on the channel. While some clients");
+               SND("may support these as-is, on others (such as ircII), it's necessary");
+               SND("to use/quote privmsg @#channel <text> instead. It's perhaps a");
+               SND("good idea to add the/alias omsg /quote privmsg @$0 $1 into");
+               SND("your script (.ircrc) file in that case.");
+       }
+   else if (!myncmp(help, "KNOCK", 8)) {
+               HDR("**** KNOCK Command ****");
+               SND("/Knock is a new UnrealIRCd command which enables you to");
+               SND("'knock' on a channel if it is +i and these criteria is met");
+               SND("- Channel is not +K (No knocks)");
+               SND("- Channel is not +I (No invites!)");
+               SND("- You're not banned!");
+               SND("- And you are not already there:)");
+               SND("Syntax:");
+               SND(" /Knock #Channel :Reason");
+       }
+
+   else if (!myncmp(help, "LICENSE", 8)) {
+               HDR("*** LICENSE Command ***");
+               SND("This command shows the GNU License");
+               SND("Which is hard-coded into the IRCd");
+               SND("Syntax: /License [optional server]");
+   }
+   else if (!myncmp(help, "SETNAME", 8)) {
+           HDR("*** SetName Command ***");
+           SND("/SetName is a new feature in UnrealIRCd");
+           SND("Which allows users to change their 'Real name'");
+           SND(" (GECOS) directly online at IRC without reconnecting");
+           SND("Syntax:");
+           SND(" /SetName :New Real Name");
+   }
+   else if (!myncmp(help, "MODE", 8)) {
+               HDR("*** MODE Command ***");
+               SND("This is basically the /mode command as it has always");
+               SND("been on IRC. Thou in Channel mode basis it has got an");
+               SND("Extra feature (/mode #Channel ^ ) which reports channel");
+               SND("modes represented in a bitstring (may be handy, maybe not)");
+               SND("UnrealIRCd has got some new channel / usermodes I think you");
+               SND("wish to take a look at");
+               SND("Channel Modes Help: /HelpOp CHMODES");
+               SND("User modes help: /HelpOp UMODES");
+   }
+   else if (!myncmp(help, "STATSERV", 8)) {
+               HDR("*** STATSERV Command ***");
+               SND("This is a alias for the /msg StatServ command,");
+               SND("But is more secure. If the IRC network doesn't have StatServ");
+               SND("It will report it is down.");
+               SND("Syntax:");
+               SND("/StatServ <command>");
+   }
+   else if (!myncmp(help, "CREDITS", 8)) {
+               HDR("*** /Credits Help ***");
+               SND("This command will list the credits I've created");
+               SND("to thank the people who has helped me with making");
+               SND("UnrealIRCd. Anyone who I've forgotten all my kind");
+               SND("thoughts go to -- Techie'99");
+               SND("Syntax:");
+               SND(" /Credits [optional server]");
+   }
+   else if (!myncmp(help, "DALINFO", 8)) {
+               HDR("*** /DALINFO Help ***");
+               SND("This command will list the credits that the");
+               SND("Dreamforge IRCd team/the IRCd developers");
+               SND("from the start when IRCd got developed");
+               SND("Syntax:");
+               SND(" /DALInfo [optional server]");
+   }
+   else if (!myncmp(help, "OPERCMDS", 8)) {
+               HDR("*** IRCop Commands Help ***");
+               SND("This section is the IRCOp's only commands");
+               SND("area:) - These topics are available:");
+               SND("Note: This doesnt include Dreamforge commands");
+               SND("-------------oOo---------------");
+               SND("SETHOST    SETIDENT     SDESC");
+               SND("ADCHAT     NACHAT       TECHAT");
+               SND("GLINE      REMGLINE     STATS");
+               SND("MKPASSWD   SNOTES       SNOTE");
+               SND("ADDLINE    LAG          RPING");
+               SND("ADDMOTD    ADDOMOTD     OPERMOTD");
+               SND("CHGHOST");
+               SND("-------------oOo---------------");
+   }   
+   else if (!myncmp(help, "ADDMOTD", 8)) {
+               HDR("*** ADDMOTD Command Help ***");
+               SND("This will add the text you specify to the MOTD");
+               SND("(the general motd - T:lines doesnt count ..)");
+               SND("Server Admin & Co-Admin only");
+               SND("-");
+               SND("Syntax: /ADDMOTD :text");
+   }
+   else if (!myncmp(help, "ADDOMOTD", 8)) {
+               HDR("*** ADDOMOTD Command Help ***");
+               SND("This will add the text you specify to the Operator MOTD");
+               SND("Server Admin & Co-Admin only");
+               SND("-");
+               SND("Syntax: /ADDOMOTD :text");
+   }
+   else if (!myncmp(help, "CHGHOST", 8)) 
+   {
+       HDR("*** CHGHOST Command help ***");
+       SND("This command makes you able to change other people's virtual hostname");
+       SND("- IRCop only.");
+       SND("Syntax: /CHGHOST <nick> <newhost>");
+   }
+
+   else if (!myncmp(help, "OPERMOTD", 8)) {
+               HDR("*** OPERMOTD Command Help ***");
+               HDR("This is a IRCop only command - shows the IRCd Operator MOTD");
+               HDR("Syntax: /OperMotd");
+   }
+   else if (!myncmp(help, "SETHOST", 8)) {
+               HDR("*** SETHOST Command Help ***");
+               SND("This command is so you can change your");
+               SND("Virtual host (hiddenhost) to everything you want to");
+               SND("Except special characters;). Syntax:");
+               SND("/SetHost <new hostname>)");
+               SND("Example:");
+               SND(" /Sethost ircaddicts.org");
+   }
+   else if (!myncmp(help, "SETIDENT", 8)) {
+               HDR("*** SETIDENT Command Help ***");
+               SND("With this command you can change your");
+               SND("ident (username).");
+               SND("Syntax:");
+               SND("/SetIdent <new ident>");
+               SND("Example:");
+               SND(" /SetIdent root");
+   }
+   else if (!myncmp(help, "SDESC", 8)) {
+               HDR("*** SDesc Command help ***");
+               SND("NOTE: This is a Server Admin/Co Admin only command");
+               SND("With this command you can change your Server Info Line");
+               SND("Without having to squit and reconnect.");
+               SND("Syntax: /SDesc :New description");
+               SND("Example: /SDesc :If you belong to me..");          
+   }
+   else if (!myncmp(help, "ADCHAT", 8)) {
+               HDR("*** AdChat Command Help ***");
+               SND("This command sends to all Admins online (IsAdmin)");
+               SND("Only for Admins. This is a ChatOps style command");
+               SND("Syntax: /AdChat :<text>");
+               SND("Example: /AdChat :Hey guys!");
+   }
+   else if (!myncmp(help, "NACHAT", 8)) {
+               HDR("*** NAChat Command Help ***");
+               SND("This command sends to all NetAdmins & TechAdmins online");
+               SND("Only for Net/Techadmins. This is a ChatOps style command");
+               SND("Syntax: /NAChat :<text>");
+               SND("Example: /NAChat :Hey guys!");
+   }
+
+                 else if (!myncmp(help, "STATS", 8)) {
+               HDR("*** Stats Command Help ***");
+               SND("UnrealIRCd has got a extension called /Stats G");
+               SND("Which will list the current G:Lines");
+               SND("Syntax: /Stats G");
+   }
+   else if (!myncmp(help, "TECHAT", 8)) {
+               HDR("*** TEChat Command Help ***");
+               SND("This command sends to all TechAdmins online");
+               SND("Only for Net/Techadmins. This is a ChatOps style command");
+               SND("Syntax: /TEChat :<text>");
+               SND("Example: /TEChat :Hey guys!");
+   }
+   else if (!myncmp(help, "REMGLINE", 8)) {
+               HDR("*** RemGline Command Help");
+               SND("This command can remove G:Lines");
+               SND("Syntax:");
+               SND(" /RemGline <user@host mask>");
+               SND("Example:");
+               SND(" /RemGline *@*.flirt.org");
+   }
+   else if (!myncmp(help, "GLINE", 8)) {
+               HDR("*** G:line command Help ***");
+               SND("This command provides timed G:Lines. If you match");
+               SND("a G:Line you cannot connect to ANY server at the");
+               SND("IRC network");
+               SND("Syntax:");
+               SND(" /GLINE <user@host mask> <seconds to be banned> :<reason>");
+               SND("Example:");
+               SND(" /GLINE *@*.dal.net 900 :Spammers");
+               SND("  this will ban all users matching *@*.dal.net for 15 minutes");
+               SND("  with reason 'Spammers'");
+   }
+   else if (!myncmp(help, "MKPASSWD", 8)) {
+               HDR("*** MkPasswd Command help ***");
+               SND("This command will encrypt the string it has been given");
+               SND("So u can add it directly to the ircd.conf if you use");
+               SND("Encrypted passwords. /MKPassWd is disabled in UnrealIRCd/32");
+               SND("Syntax : /MkPasswd :string to be encrypted");
+   }
+   else if (!myncmp(help, "SNOTE", 8)) {
+               HDR("*** SNOTE Command Help ***");
+               SND("This will store the parameter of the command to a file");
+               SND("Which then can be read by using /SNOTES LIST");
+               SND("Syntax:  /SNOTE :<message>");
+   }
+   else if (!myncmp(help, "SNOTES", 8)) {
+               HDR("*** SNOTES Command Help ***");
+               SND("This command is made to view notes");
+               SND("Written to the SNOTE file by using /SNOTE");
+               SND("Syntax: /SNOTES LIST");
+               SND("  or /SNOTES <number>");
+  }
+  else if (!myncmp(help, "ADDLINE",8)) {
+               HDR("*** ADDLINE Command Help ***");
+               SND("This command can be used to add lines to the ircd.conf file");
+               SND("Only for Server Admins");
+               SND("Syntax: /AddLine :<line>");
+  }
+  else if (!myncmp(help, "LAG", 8)) {
+               HDR("*** LAG Command Help ***");
+               SND("This command is like a sonar/traceroute for IRC servers");
+               SND("You type in /lag server1.irc.net and it will");
+               SND("reply from every server it passes with time and so on");
+               SND("Useful for looking where lag is and optional TS future/past travels");
+               SND("Syntax: /LAG <servername>");
+  }
+  else if (!myncmp(help, "RPING", 8)) {
+               HDR("*** RPING Command Help ***");
+               SND("This will calculate the milliseconds (lag) between servers");
+               SND("Syntax: /RPING <servermask>");     
+  }
+  else if (!myncmp(help, "TSCTL", 8)) {
+               HDR("*** TSCTL Command Help ***");
+               SND("This is a highly advanced command");
+               SND("Syntax:");
+               SND(" /TSCTL OFFSET +|- <time> - Adjust internal IRC clock");
+               SND(" /TSCTL TIME - Will give TS report");
+  }
+  else if (!myncmp(help, "SAJOIN", 8)) {
+               HDR("*** SAJOIN Command help **");
+               SND("Makes <nick> join channel <channel>");
+               SND("Services Admin only..");
+               SND("Syntax: /SAJOIN nick channel");
+  }
+   else if(!myncmp(help, "UMODES", 8)) {
+               HDR("*** UnrealIRCd Usermodes ***");
+               SND("o = Global IRCop");
+               SND("O = Local IRCop");
+               SND("i = Invisible (Not shown in /who searches)");
+               SND("w = Can listen to wallop messages");
+               SND("g = Can read & send to globops, and locops");
+               SND("h = Available for help");
+               SND("s = Can listen to server notices");
+               SND("k = See's all the /KILL's which were executed");
+               SND("S = For services only. (Protects them)");
+               SND("a = Is a services admin");
+               SND("A = Is a server admin");
+               SND("N = Is a network admin");
+               SND("T = Is a tech admin");
+               SND("C = Is a co admin");
+               SND("c = See's all connects/disconnects on local server");
+               SND("f = Listen to flood alerts from server");
+               SND("r = Identifies the nick as being registered");
+               SND("x = Gives the user hidden hostname");
+               SND("e = Can listen to server messages sent to +e users");
+               SND("b = Can read & send to chatops");
+               SND("W = (IRCops only) Lets you see when people does a /whois on you");
+               SND("q = (Services Admins only) Gets you unable to be");
+               SND("     kicked unless by U:Lines");
+               SND("B = (users) Marks you being a Bot");
+               SND("F = (netadmins&techadmins) Lets you recieve far connect notices + local notices");
+               SND("I = (netadmins&techadmins) Invisible Join/Part. Makes you being hidden at channels");
+               SND("1 = (ircops only) Marks you being a Coder");
+               HDR("---------------------oOo-------------------");             
+   }
+   else if(!myncmp(help, "CHMODES", 8)) {
+               HDR("*** UnrealIRCd Channel Modes ***");
+           SND("p = Private channel");
+           SND("s = Secret channel");
+           SND("i = Invite-only allowed");
+           SND("m = Moderated channel, noone can speak except users with mode +voh");
+           SND("n = No messages from outside channel");
+           SND("t = Only channel operators may set the topic");
+           SND("r = Channel is registered");
+           SND("R = Requires a registered nickname to join the channel");
+           SND("x = No ANSI color can be sent to the channel");
+           SND("q = Channel owner (The big cheese)");
+           SND("Q = No kicks able in channel unless by U:Lines");
+           SND("O = IRCop only channel (setable by Opers)");
+           SND("A = Server Admin | Network Admin | Tech Admin only channel (same as above)");
+           SND("K = /Knock is not allowed");
+           SND("I = /Invite is not allowed");
+           SND("S = Strip all incoming colours away");
+           SND("l <number of max users> = Channel may hold at most <number> of users");
+           SND("b <nick!user@host>      = Bans the nick!user@host from the channel");
+           SND("k <key>                 = Needs the channel key to join the channel");
+           SND("o <nickname>            = Gives operator status to the user");
+           SND("v <nickname>            = Gives voice to the user (May talk if chan is +m)");
+           SND("L <chan2>               = If +l is full, the next user will auto-join <chan2>");
+           SND("a <nickname>            = Gives protection to the user (No kick/drop)");
+               SND("e <exception ban>       = Exception ban - If someone matches it");
+               SND("                          they can join even if some else ban matches!");
+               SND("h <nickname>            = Gives halfop status to the user");           
+               HDR("You can get additional explanation on modes:");
+               SND(" Q h");
+               SND("With /HELPOP mode-<x> where <x> is Q f.x. like mode-Q");
+   }
+   else if (!myncmp(help, "mode-Q", 8)) {
+               HDR("*** Channel mode +Q ***");
+               SND("This is the 'peace' mode. Noone can kick eachother");
+               SND("except by U:Lines. Bans can be placed thou.");
+   }
+   else if (!myncmp(help, "MODE-h", 8)) {
+               HDR("*** Channel halfops (+h) *** ");
+               SND("If you are marked as halfop (% in /names) you can do:");
+               SND(" - Set topic");
+               SND(" - Kick non-ops");
+               SND(" - Set modes +vmntibe");
+   }
+   else if(!myncmp(help, "OFLAGS", 8)) {
+               HDR("*** UnrealIRCd O:Line flags ***");
+               SND("r = Access to /rehash server");
+               SND("R = Access to /restart server");
+               SND("D = Access to /die server");
+               SND("h = Oper can send /help ops - gets +h on oper up");
+               SND("g = Oper can send /globops");
+               SND("w = Oper can send /wallops");
+               SND("l = Oper can send /locops");
+               SND("c = Access to do local /squits and /connects");
+               SND("Y = Access to do remote /squits and /connects");
+               SND("k = Access to do local /kills");
+               SND("K = Access to do global /kills");
+               SND("b = Oper can /kline users from server");
+               SND("B = Oper can /unkline users from server");
+               SND("n = Oper can send local server notices(/notice $servername message)");
+               SND("N = Oper can send global notices(/notice $*.network.net message)");
+               SND("u = Oper can set /umode +c");
+               SND("f = Oper can set /umode +f");
+               SND("o = Local oper, flags included: rhgwlckbBnuf");
+               SND("O = Global oper, flags included: oRDCKN");
+               SND("A = Gets +A on oper up. Is server admin");
+               SND("a = Gets +a on oper up. Is services admin");
+               SND("N = Gets +N on oper up. Is network admin");
+               SND("T = Gets +T on oper up. Is tech admin");
+               SND("C = Gets +C on oper up. Is co admin");
+               SND("z = Can add /zlines");
+               SND("H = Gets +x on oper up.");
+               SND("W = Gets +W on oper up.");    
+               SND("^ = Allows to use umode +I"); 
+               SND("----------oOo-----------");
+   }
+   else if(!myncmp(help, "COMMANDS", 8)) {
+               HDR("***** Full Command List *****");
+               SND("Full command list, in the format: command token");
+               /* Send the command list (with tokens)
+               * -Wizzu
+               */
+               for (i = 0; msgtab[i].cmd; i++)
+               /* The following command is (almost) the same as the SND
+                * macro, but includes variables.  -Wizzu
+                */
+                       if (sptr != NULL)
+                               sendto_one(sptr,":%s 291 %s :%s %s",
+                                       me.name, name, msgtab[i].cmd, msgtab[i].token);
+                       else
+                               printf("%s %s\n",
+                                       msgtab[i].cmd, msgtab[i].token);
+
+               if (sptr != NULL)
+                       sendto_one(sptr, ":%s 291 %s :End of command list - %i commands shown",
+                               me.name, name, (i - 1));
+               else
+                       printf("End of command list - %i commands shown\n",(i -1));
+
+       } 
+
+   else { /* Flood back the user ;) */
+    HLP("If you need help on services, try...");
+    HLP("  \ 2/helpop nickserv\ 2 - for help on registering nicknames.");
+    HLP("  \ 2/helpop chanserv\ 2 - for help on registering channels.");
+    HLP("  \ 2/helpop memoserv\ 2 - for help on sending short messages.");
+    HLP("If you are using ircII, use \ 2/quote helpop\ 2 instead of /helpops.");
+       sendto_one(sptr, ":%s %i %s : ***** Go to %s if you have any further questions *****", me.name, 292, sptr->name, helpchan);
+    return 0;
+  }
+  sendto_one(sptr, ":%s %i %s : ***** Go to %s if you have any further questions *****", me.name, 292, sptr->name, helpchan);
+
+  return 1;
+}
diff --git a/src/ircd.c b/src/ircd.c
new file mode 100644 (file)
index 0000000..daa38ba
--- /dev/null
@@ -0,0 +1,1407 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/ircd.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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ircd.c     2.48 3/9/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+
+/* debug --sts (chdir kludge) */
+// #define UNREAL_DEBUG
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "userload.h"
+#include <sys/stat.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/file.h>
+#include <pwd.h>
+#include <sys/time.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#ifdef HPUX
+#define _KERNEL            /* HPUX has the world's worst headers... */
+#endif
+#ifndef _WIN32
+#include <sys/resource.h>
+#endif
+#ifdef HPUX
+#undef _KERNEL
+#endif
+#include <errno.h>
+#include "h.h"
+#ifndef NO_FDLIST
+#include "fdlist.h"
+#endif
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen");
+ID_Notes("2.48 3/9/94");
+#ifdef __FreeBSD__
+char *malloc_options="h" MALLOC_FLAGS_EXTRA;
+#endif
+
+
+#ifdef SHOWCONNECTINFO
+int    R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns,
+                R_do_id, R_fin_id, R_fail_id;
+#ifdef SOCKSPORT
+int    R_do_socks, R_no_socks, R_good_socks;
+#endif
+
+char   REPORT_DO_DNS[128], REPORT_FIN_DNS[128], REPORT_FIN_DNSC[128],
+       REPORT_FAIL_DNS[128], REPORT_DO_ID[128], REPORT_FIN_ID[128],
+        REPORT_FAIL_ID[128];
+#ifdef SOCKSPORT
+char   REPORT_DO_SOCKS[128], REPORT_NO_SOCKS[128], REPORT_GOOD_SOCKS[128];
+#endif
+#endif
+aClient me;                    /* That's me */
+aClient *client = &me;         /* Pointer to beginning of Client list */
+extern char backupbuf[8192];
+
+#ifndef NO_FDLIST
+fdlist default_fdlist;
+fdlist busycli_fdlist;
+fdlist serv_fdlist;   
+fdlist oper_fdlist;
+float  currentrate;
+float  currentrate2; /* outgoing */
+float  highest_rate = 0;
+float  highest_rate2 = 0;
+int    lifesux = 0;
+
+time_t check_fdlists();
+#endif
+void   server_reboot(char *);
+void   restart PROTO((char *));
+static void    open_debugfile(), setup_signals();
+void   check_lusers(void);
+extern  void   init_glines(void);
+
+char   **myargv;
+int    portnum = -1;               /* Server port number, listening this */
+char   *configfile = CONFIGFILE;       /* Server configuration file */
+int    debuglevel = -1;                /* Server debug level */
+int    bootopt = 0;                    /* Server boot option flags */
+char   *debugmode = "";                /*  -"-    -"-   -"-  */
+char   *sbrk0;                         /* initial sbrk(0) */
+static int     dorehash = 0;
+static char    *dpath = DPATH;
+int    booted = FALSE;
+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  nextkillcheck = 1;      /* next time to check for nickserv kills */
+time_t lastlucheck = 0;
+int    lu_noninv, lu_inv, lu_serv, lu_oper, lu_unknown, lu_channel,
+       lu_lu, lu_lulocal, lu_lserv, lu_clu, lu_mlu, lu_cglobalu, lu_mglobalu;
+/* */
+#ifdef UNREAL_DEBUG
+#undef CHROOTDIR
+#define CHROOT
+#endif
+#ifdef CLONE_CHECK
+        aClone *Clones = NULL;
+        char clonekillhost[100];
+#endif
+
+time_t NOW;
+#if    defined(PROFIL) && !defined(_WIN32)
+extern etext();
+
+VOIDSIG        s_monitor()
+{
+       static  int     mon = 0;
+#ifdef POSIX_SIGNALS
+       struct  sigaction act;
+#endif
+
+       (void)moncontrol(mon);
+       mon = 1 - mon;
+#ifdef POSIX_SIGNALS
+       act.sa_handler = s_rehash;
+       act.sa_flags = 0;
+       (void)sigemptyset(&act.sa_mask);
+       (void)sigaddset(&act.sa_mask, SIGUSR1);
+       (void)sigaction(SIGUSR1, &act, NULL);
+#else
+       (void)signal(SIGUSR1, s_monitor);
+#endif
+}
+#endif
+
+VOIDSIG s_die()
+{
+#ifdef USE_SYSLOG
+       (void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
+#endif
+       flush_connections(me.fd);
+#ifndef _WIN32
+       exit(-1);
+#endif
+}
+
+#ifndef _WIN32
+static VOIDSIG s_rehash()
+#else
+VOIDSIG s_rehash()
+#endif
+{
+#ifdef POSIX_SIGNALS
+       struct  sigaction act;
+#endif
+       dorehash = 1;
+#ifdef POSIX_SIGNALS
+       act.sa_handler = s_rehash;
+       act.sa_flags = 0;
+       (void)sigemptyset(&act.sa_mask);
+       (void)sigaddset(&act.sa_mask, SIGHUP);
+       (void)sigaction(SIGHUP, &act, NULL);
+#else
+# ifndef _WIN32
+       (void)signal(SIGHUP, s_rehash); /* sysV -argv */
+# endif
+#endif
+}
+
+void   restart(mesg)
+char   *mesg;
+{
+#ifdef USE_SYSLOG
+       (void)syslog(LOG_WARNING, "Restarting Server because: %s",mesg);
+#endif
+       server_reboot(mesg);
+}
+
+VOIDSIG s_restart()
+{
+       static int restarting = 0;
+
+#ifdef USE_SYSLOG
+       (void)syslog(LOG_WARNING, "Server Restarting on SIGINT");
+#endif
+       if (restarting == 0)
+           {
+               /* Send (or attempt to) a dying scream to oper if present */
+
+               restarting = 1;
+               server_reboot("SIGINT");
+           }
+}
+
+VOIDSIG s_segv()
+{
+       Reg1    int i;
+       FILE    *log;
+       Reg2    int p;
+       char    corename[512];
+#ifdef USE_SYSLOG
+       (void)syslog(LOG_WARNING, "Server terminating: Segmention fault!!!");
+       (void)closelog();
+#endif
+       sendto_ops("Aieeee!!! Server terminating: Segmention fault (buf: %s)", backupbuf);
+       sendto_serv_butone(&me, ":%s GLOBOPS :AIEEE!!! Server Terminating: Segmention fault (buf: %s)", me.name, backupbuf);
+       log = fopen(lPATH, "a");
+       if (log)
+       {
+               fprintf(log,"%li - Aieeee!!! Server terminating: Segmention fault (buf: %s)\n",time(NULL),backupbuf);
+               fclose(log);
+       }
+       
+#if !defined(_WIN32) && !defined(_AMIGA)
+       p = getpid();
+       if (fork()>0) {
+               kill(p, 3);
+               kill(p, 9);
+       }
+       write_pidfile();
+       (void)sprintf(corename, "core.%d", p);
+       (void)rename("core", corename);
+       sendto_ops("Dumped core to %s - please read Unreal.nfo on what to do!", corename);
+#endif
+       flush_connections(me.fd);
+
+#ifndef _WIN32
+       for (i = 3; i < MAXCONNECTIONS; i++)
+               (void)close(i);
+#else
+       for (i = 0; i < highest_fd; i++)
+               if ( closesocket(i) == -1 ) close(i);
+#endif 
+       exit(-1);
+}
+void   server_reboot(mesg)
+char   *mesg;
+{
+       Reg1    int     i;
+
+       sendto_ops("Aieeeee!!!  Restarting server... %s", mesg);
+       Debug((DEBUG_NOTICE,"Restarting server... %s", mesg));
+       flush_connections(me.fd);
+       /*
+       ** fd 0 must be 'preserved' if either the -d or -i options have
+       ** been passed to us before restarting.
+       */
+#ifdef USE_SYSLOG
+       (void)closelog();
+#endif
+#ifndef _WIN32
+       for (i = 3; i < MAXCONNECTIONS; i++)
+               (void)close(i);
+       if (!(bootopt & (BOOT_TTY|BOOT_DEBUG)))
+               (void)close(2);
+       (void)close(1);
+       if ((bootopt & BOOT_CONSOLE) || isatty(0))
+               (void)close(0);
+       if (!(bootopt & (BOOT_INETD|BOOT_OPER)))
+               (void)execv(MYNAME, myargv);
+#else
+       for (i = 0; i < highest_fd; i++)
+               if ( closesocket(i) == -1 ) close(i);
+
+       (void)execv(myargv[0], myargv);
+#endif
+#ifdef USE_SYSLOG
+       /* Have to reopen since it has been closed above */
+
+       openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
+       syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", MYNAME, myargv[0]);
+       closelog();
+#endif
+#ifndef _WIN32
+       Debug((DEBUG_FATAL,"Couldn't restart server: %s", strerror(errno)));
+#else
+       Debug((DEBUG_FATAL,"Couldn't restart server: %s", strerror(GetLastError())));
+#endif
+       exit(-1);
+}
+
+
+/*
+** try_connections
+**
+**     Scan through configuration and try new connections.
+**     Returns the calendar time when the next call to this
+**     function should be made latest. (No harm done if this
+**     is called earlier or later...)
+*/
+static time_t  try_connections(currenttime)
+time_t currenttime;
+{
+       Reg1    aConfItem *aconf;
+       Reg2    aClient *cptr;
+       aConfItem **pconf;
+       int     connecting, confrq;
+       time_t  next = 0;
+       aClass  *cltmp;
+       aConfItem *cconf, *con_conf;
+       int     con_class = 0;
+
+       connecting = FALSE;
+       Debug((DEBUG_NOTICE,"Connection check at   : %s",
+               myctime(currenttime)));
+       for (aconf = conf; aconf; aconf = aconf->next )
+           {
+               /* Also when already connecting! (update holdtimes) --SRB */
+               if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port <= 0)
+                       continue;
+               cltmp = Class(aconf);
+               /*
+               ** Skip this entry if the use of it is still on hold until
+               ** future. Otherwise handle this entry (and set it on hold
+               ** until next time). Will reset only hold times, if already
+               ** made one successfull connection... [this algorithm is
+               ** a bit fuzzy... -- msa >;) ]
+               */
+
+               if ((aconf->hold > currenttime))
+                   {
+                       if ((next > aconf->hold) || (next == 0))
+                               next = aconf->hold;
+                       continue;
+                   }
+
+               confrq = get_con_freq(cltmp);
+               aconf->hold = currenttime + confrq;
+               /*
+               ** Found a CONNECT config with port specified, scan clients
+               ** and see if this server is already connected?
+               */
+               cptr = find_name(aconf->name, (aClient *)NULL);
+
+               if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
+                   (!connecting || (Class(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;
+                   if (!cconf)
+                     {
+                       con_class = Class(cltmp);
+                       con_conf = aconf;
+                       /* We connect only one at time... */
+                       connecting = TRUE;
+                     }
+                 }
+               if ((next > aconf->hold) || (next == 0))
+                       next = aconf->hold;
+           }
+       if (connecting)
+           {
+               if (con_conf->next)  /* are we already last? */
+                   {
+                       for (pconf = &conf; (aconf = *pconf);
+                            pconf = &(aconf->next))
+                               /* put the current one at the end and
+                                * make sure we try all connections
+                                */
+                               if (aconf == con_conf)
+                                       *pconf = aconf->next;
+                       (*pconf = con_conf)->next = 0;
+                   }
+               if (connect_server(con_conf, (aClient *)NULL,
+                                  (struct hostent *)NULL) == 0)
+                       sendto_ops("Connection to %s[%s] activated.",
+                                  con_conf->name, con_conf->host);
+           }
+       Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
+       return (next);
+}
+
+/* Now find_kill is only called when a kline-related command is used:
+   AKILL/RAKILL/KLINE/UNKLINE/REHASH.  Very significant CPU usage decrease.
+   I made changes to evm_lusers
+ery check_pings call to add new parameter.
+   -- Barubary */
+extern time_t  check_pings(time_t currenttime, int check_kills)
+{              
+       Reg1    aClient *cptr;
+       Reg2    int     killflag;
+       int     ping = 0, i, i1, rflag = 0;
+       time_t  oldest = 0, timeout;
+
+#ifdef PRECISE_CHECK
+    for (i1 = 0; i1 <= 7; i1++) {
+       for (i = 0; i <= highest_fd; i++)
+           {
+               if (!(cptr = local[i]) || IsMe(cptr) || IsLog(cptr))
+                       continue;
+#else
+       for (cptr = &me; cptr; cptr = cptr->prev)
+       {
+               if (IsMe(cptr) || !MyClient(cptr) || IsLog(cptr))
+                       continue;
+#endif
+
+               /*
+               ** Note: No need to notify opers here. It's
+               ** already done when "FLAGS_DEADSOCKET" is set.
+               */
+               if (cptr->flags & FLAGS_DEADSOCKET)
+                   {
+                       (void)exit_client(cptr, cptr, &me, "Dead socket");
+                       continue;
+                   }
+
+               if (check_kills)
+                       killflag = IsPerson(cptr) ? find_kill(cptr) : 0;
+               else
+                       killflag = 0;
+               if (check_kills && !killflag && IsPerson(cptr))
+                       if (find_zap(cptr, 1) || find_tkline_match(cptr, 2)>-1)
+                               killflag = 1;
+               ping = IsRegistered(cptr) ? get_client_ping(cptr) :
+                                           CONNECTTIMEOUT;
+               Debug((DEBUG_DEBUG, "c(%s)=%d p %d k %d r %d a %d",
+                       cptr->name, cptr->status, ping, killflag, rflag,
+                       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 (!killflag && !rflag && IsRegistered(cptr) &&
+                   (ping >= currenttime - cptr->lasttime))
+                       goto ping_timeout;
+               /*
+                * 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 (killflag || rflag ||
+                   ((currenttime - cptr->lasttime) >= (2 * ping) &&
+                    (cptr->flags & FLAGS_PINGSENT)) ||
+                   (!IsRegistered(cptr) &&
+                    (currenttime - cptr->firsttime) >= ping))
+                   {
+                       if (!IsRegistered(cptr) &&
+                           (DoingDNS(cptr) || DoingAuth(cptr)
+#ifdef SOCKSPORT
+|| DoingSocks(cptr)                        
+#endif
+                           ))
+                           {
+                               if (cptr->authfd >= 0)
+                                   {
+#ifndef _WIN32
+                                       (void)close(cptr->authfd);
+#else
+                                       (void)closesocket(cptr->authfd);
+#endif
+                                       cptr->authfd = -1;
+                                       cptr->count = 0;
+                                       *cptr->buffer = '\0';
+                                   }
+#ifdef SOCKSPORT
+                               if (cptr->socksfd >= 0)
+                                   {
+#ifndef _WIN32
+                                       (void)close(cptr->socksfd);
+#else
+                                       (void)closesocket(cptr->socksfd);
+#endif /* _WIN32 */
+                                       cptr->socksfd = -1;
+                                   }
+#endif /* SOCKSPORT */
+
+                                   
+#ifdef SHOWCONNECTINFO
+                               if (DoingDNS(cptr))
+#ifndef _WIN32
+                                       write(cptr->fd, REPORT_FAIL_DNS,
+                                               R_fail_dns);
+#else
+                                       send(cptr->fd, REPORT_FAIL_DNS,
+                                               R_fail_dns, 0);
+#endif
+                               else if (DoingAuth(cptr))
+#ifndef _WIN32
+                                       write(cptr->fd, REPORT_FAIL_ID,
+                                               R_fail_id);
+#else
+                                       send(cptr->fd, REPORT_FAIL_ID,
+                                               R_fail_id, 0);
+#endif
+
+#ifdef SOCKSPORT
+                               else
+#ifndef _WIN32
+                                       write(cptr->fd, REPORT_NO_SOCKS,
+                                               R_no_socks);
+#else
+                                       send(cptr->fd, REPORT_NO_SOCKS,
+                                               R_no_socks, 0);
+
+#endif
+#endif /* SOCKSPORT */
+
+#endif
+                               Debug((DEBUG_NOTICE,
+                                       "DNS/AUTH timeout %s",
+                                       get_client_name(cptr,TRUE)));
+                               del_queries((char *)cptr);
+                               ClearAuth(cptr);
+                               ClearDNS(cptr);
+#ifdef SOCKSPORT
+                               ClearSocks(cptr);
+#endif
+                               SetAccess(cptr);
+                               cptr->firsttime = currenttime;
+                               cptr->lasttime = currenttime;
+                               continue;
+                           }
+                       if (IsServer(cptr) || IsConnecting(cptr) ||
+                           IsHandshake(cptr)) {
+                               sendto_ops("No response from %s, closing link",
+                                          get_client_name(cptr, FALSE));
+                               sendto_serv_butone(&me, ":%s GNOTICE :No response from %s, closing link",
+                                       me.name, get_client_name(cptr, FALSE));
+                       }
+                       /*
+                        * this is used for KILL lines with time restrictions
+                        * on them - send a messgae to the user being killed
+                        * first.
+                        */
+                       if (killflag && IsPerson(cptr))
+                               sendto_ops("Kill line active for %s",
+                                          get_client_name(cptr, FALSE));
+
+                         if (killflag)
+                                (void)exit_client(cptr, cptr, &me,
+                                  "User has been banned");
+                         else
+                                (void)exit_client(cptr, cptr, &me,
+                                  "Ping timeout");
+                       continue;
+                   }
+               else if (IsRegistered(cptr) &&
+                        (cptr->flags & FLAGS_PINGSENT) == 0)
+                   {
+                       /*
+                        * 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 = currenttime - ping;
+                       sendto_one(cptr, "PING :%s", me.name);
+                   }
+ping_timeout:
+               timeout = cptr->lasttime + ping;
+               while (timeout <= currenttime)
+                       timeout += ping;
+               if (timeout < oldest || !oldest)
+                       oldest = timeout;
+           }
+#ifdef PRECISE_CHECK
+       }
+#endif
+
+       if (!oldest || oldest < currenttime)
+               oldest = currenttime + PINGFREQUENCY;
+       Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
+               myctime(oldest), ping, oldest, currenttime));
+
+       return (oldest);
+}
+
+/*
+** bad_command
+**     This is called when the commandline is not acceptable.
+**     Give error message and exit without starting anything.
+*/
+static int     bad_command()
+{
+#ifndef _WIN32
+  (void)printf(
+        "Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-t] [-H]\n",
+#ifdef CMDLINE_CONFIG
+        "[-f config] "
+#else
+        ""
+#endif
+        );
+  (void)printf("Server not started\n\n");
+#else
+  MessageBox(NULL,
+         "Usage: wircd [-h servername] [-p portnumber] [-x loglevel]\n",
+         "UnrealIRCD/32", MB_OK);
+#endif
+  return (-1);
+}
+
+#ifndef _WIN32
+int    main(argc, argv)
+#else
+int    InitwIRCD(argc, argv)
+#endif
+int    argc;
+char   *argv[];
+{
+#ifdef _WIN32
+       WORD    wVersionRequested = MAKEWORD(1, 1);
+       WSADATA wsaData;
+#else
+       uid_t   uid, euid;
+       time_t  delay = 0;
+#endif
+       int     portarg = 0;
+#ifdef  FORCE_CORE
+       struct  rlimit corelim;
+#endif
+#ifndef NO_FDLIST
+       int mainloops=0; /* counter of how many times we have gone through
+                                    the main loop */
+       time_t nextfdlistcheck=0; /*end of priority code */       
+#endif
+       static  time_t lastglinecheck = 0;
+
+#if !defined(_WIN32) && !defined(_AMIGA)
+       sbrk0 = (char *)sbrk((size_t)0);
+       uid = getuid();
+       euid = geteuid();
+# ifdef        PROFIL
+       (void)monstartup(0, etext);
+       (void)moncontrol(1);
+       (void)signal(SIGUSR1, s_monitor);
+# endif
+#endif
+
+#ifdef CHROOTDIR
+       if (chdir(dpath))
+           {
+               perror("chdir");
+               exit(-1);
+           }
+       res_init();
+       if (chroot(DPATH))
+         {
+           (void)fprintf(stderr,"ERROR:  Cannot chdir/chroot\n");
+           exit(5);
+         }
+#endif /*CHROOTDIR*/
+
+       myargv = argv;
+#ifndef _WIN32
+       (void)umask(077);                /* better safe than sorry --SRB */
+#else
+       WSAStartup(wVersionRequested, &wsaData);
+#endif
+       bzero((char *)&me, sizeof(me));
+
+#ifndef _WIN32
+       setup_signals();
+#endif
+       initload();
+
+#ifdef FORCE_CORE
+       corelim.rlim_cur = corelim.rlim_max = RLIM_INFINITY;
+       if (setrlimit(RLIMIT_CORE, &corelim))
+         printf("unlimit core size failed; errno = %d\n", errno);
+#endif
+
+       /*
+       ** All command line parameters have the syntax "-fstring"
+       ** or "-f string" (e.g. the space is optional). String may
+       ** be empty. Flag characters cannot be concatenated (like
+       ** "-fxyz"), it would conflict with the form "-fstring".
+       */
+       while (--argc > 0 && (*++argv)[0] == '-')
+           {
+               char    *p = argv[0]+1;
+               int     flag = *p++;
+
+               if (flag == '\0' || *p == '\0')
+                       if (argc > 1 && argv[1][0] != '-')
+                           {
+                               p = *++argv;
+                               argc -= 1;
+                           }
+                       else
+                               p = "";
+
+               switch (flag)
+                   {
+#ifndef _WIN32
+                    case 'a':
+                       bootopt |= BOOT_AUTODIE;
+                       break;
+                   case 'c':
+                       bootopt |= BOOT_CONSOLE;
+                       break;
+                   case 'q':
+                       bootopt |= BOOT_QUICK;
+                       break;
+                   case 'd' :
+                        (void)setuid((uid_t)uid);
+#else
+                   case 'd':
+#endif
+                       dpath = p;
+                       break;
+#ifndef _WIN32
+                   case 'o': /* Per user local daemon... */
+                        (void)setuid((uid_t)uid);
+                       bootopt |= BOOT_OPER;
+                       break;
+#ifdef CMDLINE_CONFIG
+                   case 'f':
+                        (void)setuid((uid_t)uid);
+                       configfile = p;
+                       break;
+#endif
+                   case 'h':
+                       strncpyzt(me.name, p, sizeof(me.name));
+                       break;
+                       case 'H':
+                               unrealmanual();
+                               exit(0);
+                   case 'i':
+                       bootopt |= BOOT_INETD|BOOT_AUTODIE;
+                       break;
+#endif
+                   case 'p':
+                       if ((portarg = atoi(p)) > 0 )
+                               portnum = portarg;
+                       break;
+                   case 's':
+                       (void)printf("sizeof(aClient) == %u\n", sizeof(aClient));
+                       (void)printf("sizeof(aChannel) == %u\n", sizeof(aChannel));
+                       (void)printf("sizeof(aServer) == %u\n", sizeof(aServer));
+                       exit(0);
+                       break;
+#ifndef _WIN32
+                   case 't':
+                        (void)setuid((uid_t)uid);
+                       bootopt |= BOOT_TTY;
+                       break;
+                   case 'v':
+                       (void)printf("ircd %s\n", version);
+#else
+                   case 'v':
+                       MessageBox(NULL, version, "UnrealIRCD/Win32 version", MB_OK);
+#endif
+                       exit(0);
+                   case 'x':
+#ifdef DEBUGMODE
+# ifndef _WIN32
+                        (void)setuid((uid_t)uid);
+# endif
+                       debuglevel = atoi(p);
+                       debugmode = *p ? p : "0";
+                       bootopt |= BOOT_DEBUG;
+                       break;
+#else
+# ifndef _WIN32
+                       (void)fprintf(stderr,
+                               "%s: DEBUGMODE must be defined for -x y\n",
+                               myargv[0]);
+# else
+                       MessageBox(NULL,
+                               "DEBUGMODE must be defined for -x option",
+                               "UnrealIRCD/32", MB_OK);
+# endif
+                       exit(0);
+#endif
+                   default:
+                       bad_command();
+                       break;
+                   }
+           }
+
+#ifndef        CHROOT
+       if (chdir(dpath))
+           {
+# ifndef _WIN32
+               perror("chdir");
+# else
+               MessageBox(NULL, strerror(GetLastError()), "UnrealIRCD/32: chdir()",
+                       MB_OK);
+# endif
+               exit(-1);
+           }
+#endif
+
+#if !defined(IRC_UID) && !defined(_WIN32)
+       if ((uid != euid) && !euid)
+           {
+               (void)fprintf(stderr,
+                       "ERROR: do not run ircd setuid root. Make it setuid a\
+ normal user.\n");
+               exit(-1);
+           }
+#endif
+
+#if (!defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))) \
+    && !defined(_WIN32)
+# ifndef       AIX
+       (void)setuid((uid_t)uid);
+       (void)setuid((uid_t)euid);
+# endif
+
+       if ((int)getuid() == 0)
+           {
+# if defined(IRC_UID) && defined(IRC_GID)
+
+               /* run as a specified user */
+               (void)fprintf(stderr,"WARNING: running ircd with uid = %d\n",
+                       IRC_UID);
+               (void)fprintf(stderr,"         changing to gid %d.\n",IRC_GID);
+               (void)setuid(IRC_UID);
+               (void)setgid(IRC_GID);
+#else
+               /* check for setuid root as usual */
+               (void)fprintf(stderr,
+                       "ERROR: do not run ircd setuid root. Make it setuid a\
+ normal user.\n");
+               exit(-1);
+# endif        
+           } 
+#endif /*CHROOTDIR/UID/GID/_WIN32*/
+
+#ifndef _WIN32
+       /* didn't set debuglevel */
+       /* but asked for debugging output to tty */
+       if ((debuglevel < 0) &&  (bootopt & BOOT_TTY))
+           {
+               (void)fprintf(stderr,
+                       "you specified -t without -x. use -x <n>\n");
+               exit(-1);
+           }
+#endif
+
+       if (argc > 0)
+               return bad_command(); /* This should exit out */
+       fprintf(stderr, "=====================================================================\n");
+       fprintf(stderr, "= %s loading..\n", version);
+       fprintf(stderr, "=====================================================================\n");
+
+       clear_client_hash_table();
+       clear_channel_hash_table();
+       clear_notify_hash_table();
+       inittoken();
+       initlists();
+       initclass();
+       initwhowas();
+       initstats();
+       booted = FALSE;
+       load_conf(ZCONF, 0);    
+       booted = TRUE;
+       if (dcc_loadconf() == 0)
+       {
+               fprintf(stderr, "* Loaded DCC deny configuration file ..\n");
+       }
+       if (cr_loadconf() == 0)
+       {
+               fprintf(stderr, "* Loaded Channel Restrict configuration file..\n");
+       }
+       if (vhost_loadconf() == 0)
+       {
+               fprintf(stderr, "* Loaded Vhost configuration file..\n");
+       }
+       load_tunefile();
+       make_umodestr();
+       make_cmodestr();
+       fprintf(stderr, "* Dynamic configuration initialized .. booting IRCd.\n");
+       fprintf(stderr, "---------------------------------------------------------------------\n");
+       
+       open_debugfile();
+#ifndef NO_FDLIST
+        init_fdlist(&serv_fdlist);
+        init_fdlist(&busycli_fdlist);
+        init_fdlist(&default_fdlist);
+       init_fdlist(&oper_fdlist);
+        {
+                register int i;
+                for (i=MAXCONNECTIONS+1 ; i>0 ; i--)
+                        default_fdlist.entry[i] = i-1;
+        }                     
+#endif
+       if (portnum < 0)
+               portnum = PORTNUM;
+       me.port = portnum;
+       (void)init_sys();
+       me.flags = FLAGS_LISTEN;
+#ifndef _WIN32
+       if (bootopt & BOOT_INETD)
+           {
+               me.fd = 0;
+               local[0] = &me;
+               me.flags = FLAGS_LISTEN;
+           }
+       else
+#endif
+               me.fd = -1;
+
+#ifdef USE_SYSLOG
+       openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
+#endif
+       if (initconf(bootopt) == -1)
+           {
+               Debug((DEBUG_FATAL, "Failed in reading configuration file %s",
+                       configfile));
+#ifndef _WIN32
+               (void)printf("Couldn't open configuration file %s\n",
+                       configfile);
+#else
+               MessageBox(NULL, "Couldn't open configuration file "CONFIGFILE,
+                       "UnrealIRCD/32", MB_OK);
+#endif
+               exit(-1);
+           }
+       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 = %d", portnum));
+               if (inetport(&me, aconf->passwd, portnum))
+                       exit(1);
+           }
+       else if (inetport(&me, "*", 0))
+               exit(1);
+
+       (void)setup_ping();
+       (void)get_my_name(&me, me.sockhost, sizeof(me.sockhost)-1);
+       if (me.name[0] == '\0')
+               strncpyzt(me.name, me.sockhost, sizeof(me.name));
+       me.hopcount = 0;
+       me.authfd = -1;
+       me.confs = NULL;
+       me.next = NULL;
+       me.user = NULL;
+       me.from = &me;
+#ifdef SOCKSPORT
+       me.socksfd = -1;
+#endif
+       SetMe(&me);
+       make_server(&me);
+       (void)strcpy(me.serv->up, me.name);
+
+       me.lasttime = me.since = me.firsttime = TStime();
+       (void)add_to_client_hash_table(me.name, &me);
+#if !defined(_AMIGA) && !defined(_WIN32)
+       if (fork())
+               exit(0);
+               
+#endif
+
+#ifdef SHOWCONNECTINFO
+       (void)sprintf(REPORT_DO_DNS, ":%s %s", me.name, BREPORT_DO_DNS);
+       (void)sprintf(REPORT_FIN_DNS, ":%s %s", me.name, BREPORT_FIN_DNS);
+       (void)sprintf(REPORT_FIN_DNSC, ":%s %s", me.name, BREPORT_FIN_DNSC);
+       (void)sprintf(REPORT_FAIL_DNS, ":%s %s", me.name, BREPORT_FAIL_DNS);
+       (void)sprintf(REPORT_DO_ID, ":%s %s", me.name, BREPORT_DO_ID);
+       (void)sprintf(REPORT_FIN_ID, ":%s %s", me.name, BREPORT_FIN_ID);
+       (void)sprintf(REPORT_FAIL_ID, ":%s %s", me.name, BREPORT_FAIL_ID);
+#ifdef SOCKSPORT
+       (void)sprintf(REPORT_DO_SOCKS, ":%s %s", me.name, BREPORT_DO_SOCKS);
+       (void)sprintf(REPORT_NO_SOCKS, ":%s %s", me.name, BREPORT_NO_SOCKS);
+       (void)sprintf(REPORT_GOOD_SOCKS, ":%s %s", me.name, BREPORT_GOOD_SOCKS);
+#endif
+
+       R_do_dns = strlen(REPORT_DO_DNS);
+       R_fin_dns = strlen(REPORT_FIN_DNS);
+       R_fin_dnsc = strlen(REPORT_FIN_DNSC);
+       R_fail_dns = strlen(REPORT_FAIL_DNS);
+       R_do_id = strlen(REPORT_DO_ID);
+       R_fin_id = strlen(REPORT_FIN_ID);
+       R_fail_id = strlen(REPORT_FAIL_ID);
+#ifdef SOCKSPORT
+       R_do_socks = strlen(REPORT_DO_SOCKS);
+       R_no_socks = strlen(REPORT_NO_SOCKS);
+       R_good_socks = strlen(REPORT_GOOD_SOCKS);
+#endif /* SOCKSPORT */
+#endif
+#ifdef SOCKSPORT
+              init_socks(&me);
+#endif
+       
+       check_class();
+       if (bootopt & BOOT_OPER)
+           {
+               aClient *tmp = add_connection(&me, 0);
+
+               if (!tmp)
+                       exit(1);
+               SetMaster(tmp);
+           }
+       else
+               write_pidfile();
+
+       Debug((DEBUG_NOTICE,"Server ready..."));
+#ifdef USE_SYSLOG
+       syslog(LOG_NOTICE, "Server Ready");
+#endif
+#ifndef NO_FDLIST
+        check_fdlists(TStime());
+#endif
+        nextkillcheck = TStime() + (time_t)1;
+
+#ifdef _WIN32
+    return 1;
+}
+
+void    SocketLoop(void *dummy)
+{
+       time_t  delay = 0, now;
+       static  time_t lastglinecheck = 0;
+#ifndef NO_FDLIST
+       int mainloops=0; /* counter of how many times we have gone through
+                                    the main loop */
+       time_t nextfdlistcheck=0; /*end of priority code */       
+#endif
+
+       while (1)
+#else
+       for (;;)
+#endif
+           {
+               now = TStime();
+               if (now - lastglinecheck > 4)
+               {
+                       tkl_check_expire();
+                       lastglinecheck = now;
+               }
+               /*
+               ** Run through the hashes and check lusers every
+               ** second
+               ** also check for expiring glines
+               */
+               
+#ifndef NO_FDLIST
+               {
+                       static time_t lasttime=0;
+                       static long lastrecvK, lastsendK;
+                       static int init=0;
+                       static time_t loadcfreq=LOADCFREQ;
+
+                       if (now-lasttime < loadcfreq)
+                               goto done_check;
+                       lasttime = now;
+                       if (me.receiveK - lastrecvK >= LOADRECV)
+                       {
+                               if (!lifesux)
+                               {
+                                     loadcfreq *= 2; /* add hysteresis */
+                                             lifesux = TRUE;
+                                     sendto_ops("Entering high-traffic mode (incoming = %0.2f kb/s, outgoing = %0.2f kb/s currently)", currentrate, currentrate2);
+                               }
+                       }
+                             else
+                       {
+                             loadcfreq = LOADCFREQ;
+                             if (lifesux)
+                             {
+                                     lifesux = 0;
+                                     sendto_ops("Resuming standard operation (incoming = %0.2f kb/s, outgoing = %0.2f kb/s now)", currentrate, currentrate2);
+                             }
+                        }
+                      lastrecvK = me.receiveK;
+                      lastsendK = me.sendK;
+done_check:
+               if (lasttime != now)
+               {
+                        currentrate = ((float)(me.receiveK-lastrecvK))/((float)(now-lasttime));
+                       currentrate2 = ((float)(me.sendK-lastsendK))/((float)(now-lasttime));
+                       if (currentrate > highest_rate)
+                               highest_rate = currentrate;
+                       if (currentrate2 > highest_rate2)
+                               highest_rate2 = currentrate2;
+               }
+                        ;
+               }     
+#endif   
+               if(lastlucheck < now) {
+                       check_lusers();
+                       lastlucheck=now;
+//                     check_expire_gline ();
+               }
+               /*
+               ** We only want to connect if a connection is due,
+               ** not every time through.  Note, if there are no
+               ** active C lines, this call to Tryconnections is
+               ** made once only; it will return 0. - avalon
+               */
+               if (nextconnect && now >= nextconnect)
+                       nextconnect = try_connections(now);
+               /*
+               ** DNS checks. One to timeout queries, one for cache expiries.
+               */
+               if (now >= nextdnscheck)
+                       nextdnscheck = timeout_query_list(now);
+               if (now >= nextexpire)
+                       nextexpire = expire_cache(now);
+               /*
+               ** 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);
+               else
+                       delay = nextping;
+               delay = MIN(nextdnscheck, delay);
+               delay = MIN(nextexpire, delay);
+               delay -= now;
+               /*
+               ** Adjust delay to something reasonable [ad hoc values]
+               ** (one might think something more clever here... --msa)
+               ** We don't really need to check that often and as long
+               ** as we don't delay too long, everything should be ok.
+               ** waiting too long can cause things to timeout...
+               ** i.e. PINGS -> a disconnection :(
+               ** - avalon
+               */
+               if (delay < 1)
+                       delay = 1;
+               else
+                       delay = MIN(delay, TIMESEC);
+#ifdef NO_FDLIST
+              (void)read_message(delay);
+#else
+                (void)read_message(0,&serv_fdlist); /* servers */
+                (void)read_message(1,&busycli_fdlist); /* busy clients */
+               if (lifesux)          
+                       (void)read_message(1,&serv_fdlist);
+                               /* read servs more often */
+               {
+                    static time_t lasttime=0;
+                    if ((lasttime + (lifesux +1) * 2)< (now = TStime()))
+                    { 
+                              read_message(delay,NULL); /*  check everything */
+                              lasttime = now;
+                    } 
+              }
+
+#endif         
+               Debug((DEBUG_DEBUG ,"Got message(s)"));
+               
+               now = TStime();
+               /*
+               ** ...perhaps should not do these loops every time,
+               ** but only if there is some chance of something
+               ** happening (but, note that conf->hold times may
+               ** be changed elsewhere--so precomputed next event
+               ** time might be too far away... (similarly with
+               ** ping times) --msa
+               */
+#ifdef NO_FDLIST
+               if (now >= nextping)
+#else
+               if (now >= nextping && !lifesux)
+#endif
+                       nextping = check_pings(now, 0);
+
+               if (dorehash)
+                   {
+                       (void)rehash(&me, &me, 1);
+                       dorehash = 0;
+                   }
+               /*
+               ** Flush output buffers on all connections now if they
+               ** have data in them (or at least try to flush)
+               ** -avalon
+               */
+#ifndef NO_FDLIST
+                /* check which clients are active */
+                if (now > nextfdlistcheck)
+                       nextfdlistcheck = check_fdlists(now);
+#endif
+               flush_connections(me.fd);
+           }
+    }
+#ifndef NO_FDLIST
+time_t check_fdlists(now)
+time_t now;
+{
+      register aClient *cptr;
+      int pri; /* temp. for priority */
+      register int i,j;
+      j = 0;
+
+      for(i=highest_fd;i>=0; i--)
+      {
+              if (!(cptr=local[i]))
+                      continue;
+              if (IsServer(cptr) || IsListening(cptr) || IsOper(cptr) ||
+                      DoingAuth(cptr))
+              {
+                      busycli_fdlist.entry[++j] = i;
+                      continue;
+              }
+              pri = cptr->priority;
+              if (cptr->receiveM==cptr->lastrecvM)
+                      pri+=2; /* lower a bit */
+              else
+                      pri-=30;
+              if (pri < 0) pri = 0;
+              if (pri > 80) pri = 80;  
+
+              cptr->lastrecvM = cptr->receiveM;
+              cptr->priority = pri;
+              if ((pri <10) || (!lifesux && (pri < 25)))
+                      busycli_fdlist.entry[++j] = i;
+      }
+      busycli_fdlist.last_entry=j; /* rest of the fdlist is garbage */
+                                                                        
+      return (now + FDLISTCHKFREQ + lifesux * FDLISTCHKFREQ);
+}
+#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()
+{
+#ifdef DEBUGMODE
+       int     fd;
+       aClient *cptr;
+
+       if (debuglevel >= 0)
+           {
+               cptr = make_client(NULL, NULL);
+               cptr->fd = 2;
+               SetLog(cptr);
+               cptr->port = debuglevel;
+               cptr->flags = 0;
+               cptr->acpt = cptr;
+               local[2] = cptr;
+               (void)strcpy(cptr->sockhost, me.sockhost);
+# ifndef _WIN32
+               (void)printf("isatty = %d ttyname = %#x\n",
+                       isatty(2), (u_int)ttyname(2));
+               if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
+                   {
+                       (void)truncate(LOGFILE, 0);
+                       if ((fd = open(LOGFILE, O_WRONLY | O_CREAT, 0600)) < 0) 
+                               if ((fd = open("/dev/null", O_WRONLY)) < 0)
+                                       exit(-1);
+                       if (fd != 2)
+                           {
+                               (void)dup2(fd, 2);
+                               (void)close(fd); 
+                           }
+                       strncpyzt(cptr->name, LOGFILE, sizeof(cptr->name));
+                   }
+               else if (isatty(2) && ttyname(2))
+                       strncpyzt(cptr->name, ttyname(2), sizeof(cptr->name));
+               else
+# endif
+                       (void)strcpy(cptr->name, "FD2-Pipe");
+               Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
+                       cptr->name, cptr->port, myctime(time(NULL))));
+           }
+       else
+               local[2] = NULL;
+#endif
+       return;
+}
+
+#ifndef _WIN32
+static void    setup_signals()
+{
+#ifdef POSIX_SIGNALS
+       struct  sigaction act;
+
+       act.sa_handler = SIG_IGN;
+       act.sa_flags = 0;
+       (void)sigemptyset(&act.sa_mask);
+       (void)sigaddset(&act.sa_mask, SIGPIPE);
+       (void)sigaddset(&act.sa_mask, SIGALRM);
+# ifdef        SIGWINCH
+       (void)sigaddset(&act.sa_mask, SIGWINCH);
+       (void)sigaction(SIGWINCH, &act, NULL);
+# endif
+       (void)sigaction(SIGPIPE, &act, NULL);
+       act.sa_handler = dummy;
+       (void)sigaction(SIGALRM, &act, NULL);
+       act.sa_handler = s_rehash;
+       (void)sigemptyset(&act.sa_mask);
+       (void)sigaddset(&act.sa_mask, SIGHUP);
+       (void)sigaction(SIGHUP, &act, NULL);
+       act.sa_handler = s_restart;
+       (void)sigaddset(&act.sa_mask, SIGINT);
+       (void)sigaction(SIGINT, &act, NULL);
+       act.sa_handler = s_die;
+       (void)sigaddset(&act.sa_mask, SIGTERM);
+       (void)sigaction(SIGTERM, &act, NULL);
+/* handling of SIGSEGV as well -sts */
+       act.sa_handler = s_segv;
+       (void)sigaddset(&act.sa_mask, SIGSEGV);
+       (void)sigaction(SIGSEGV, &act, NULL);
+       
+#else
+# ifndef       HAVE_RELIABLE_SIGNALS
+       (void)signal(SIGPIPE, dummy);
+#  ifdef       SIGWINCH
+       (void)signal(SIGWINCH, dummy);
+#  endif
+# else
+#  ifdef       SIGWINCH
+       (void)signal(SIGWINCH, SIG_IGN);
+#  endif
+       (void)signal(SIGPIPE, SIG_IGN);
+# endif
+       (void)signal(SIGALRM, dummy);   
+       (void)signal(SIGHUP, s_rehash);
+       (void)signal(SIGTERM, s_die); 
+       (void)signal(SIGINT, s_restart);
+       (void)signal(SIGSEGV, s_segv);
+#endif
+
+#ifdef RESTARTING_SYSTEMCALLS
+       /*
+       ** 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.
+       */
+       (void)siginterrupt(SIGALRM, 1);
+#endif
+}
+#endif /* !_Win32 */
+
+
+
+
+void check_lusers(void) {
+        aClient *acptr;
+       lu_noninv=lu_inv=lu_serv=lu_oper=lu_unknown=lu_channel=lu_lu=lu_lserv=
+          lu_clu=lu_cglobalu=0;
+        for (acptr = client; acptr; acptr = acptr->next) {
+                switch (acptr->status) {
+                 case STAT_SERVER:
+                        if (MyConnect(acptr))
+                          lu_lserv++;
+                 case STAT_ME:
+                        lu_serv++;
+                        break;
+                 case STAT_CLIENT:
+                        if (IsOper(acptr))
+                          lu_oper++;
+                        if (MyConnect(acptr)) {
+                                lu_lu++;
+                                if (match(DOMAINNAMEMASK, acptr->sockhost) == 0)
+                                  lu_lulocal++;
+                        }
+                        if (!IsInvisible(acptr))
+                          lu_noninv++;
+                        else
+                          lu_inv++;
+                        break;
+                 default:
+                        lu_unknown++;
+                        break;
+                }
+        }
+        lu_clu=lu_lu;
+        lu_cglobalu=lu_noninv + lu_inv;
+        if (lu_clu > lu_mlu)
+          lu_mlu = lu_lu;
+        lu_cglobalu = lu_noninv + lu_inv;
+        if (lu_cglobalu > lu_mglobalu)
+          lu_mglobalu = lu_cglobalu;
+
+        lu_channel=count_channels(&me);
+}
+
diff --git a/src/list.c b/src/list.c
new file mode 100644 (file)
index 0000000..b194024
--- /dev/null
@@ -0,0 +1,581 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/list.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.
+ */
+
+/* -- Jto -- 20 Jun 1990
+ * extern void free() fixed as suggested by
+ * gruner@informatik.tu-muenchen.de
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Added chname initialization...
+ */
+
+/* -- Jto -- 24 May 1990
+ * Moved is_full() to channel.c
+ */
+
+/* -- Jto -- 10 May 1990
+ * Added #include <sys.h>
+ * Changed memset(xx,0,yy) into bzero(xx,yy)
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include "numeric.h"
+#ifdef DBMALLOC
+#include "malloc.h"
+#endif
+void   free_link PROTO((Link *));
+Link   *make_link PROTO(());
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen");
+ID_Notes("2.24 4/20/94");
+
+#ifdef DEBUGMODE
+static struct  liststats {
+       int     inuse;
+} cloc, crem, users, servs, links, classs, aconfs;
+
+#endif
+
+void   outofmemory();
+
+int    flinks = 0;
+Link   *freelink = NULL;
+
+int    numclients = 0;
+
+void   initlists()
+{
+#ifdef DEBUGMODE
+       bzero((char *)&cloc, sizeof(cloc));
+       bzero((char *)&crem, sizeof(crem));
+       bzero((char *)&users, sizeof(users));
+       bzero((char *)&servs, sizeof(servs));
+       bzero((char *)&links, sizeof(links));
+       bzero((char *)&classs, sizeof(classs));
+       bzero((char *)&aconfs, sizeof(aconfs));
+#endif
+}
+
+void   outofmemory()
+{
+       Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
+       restart("Out of Memory");
+}
+
+       
+/*
+** Create a new aClient structure and set it to initial state.
+**
+**     from == NULL,   create local client (a client connected
+**                     to a socket).
+**
+**     from,   create remote client (behind a socket
+**                     associated with the client defined by
+**                     'from'). ('from' is a local client!!).
+*/
+aClient        *make_client(from, servr)
+aClient        *from, *servr;
+{
+       Reg1    aClient *cptr = NULL;
+       Reg2    unsigned size = CLIENT_REMOTE_SIZE;
+
+       /*
+        * Check freelists first to see if we can grab a client without
+        * having to call malloc.
+        */
+       if (!from)
+               size = CLIENT_LOCAL_SIZE;
+
+       if (!(cptr = (aClient *)MyMalloc(size)))
+               outofmemory();
+       bzero((char *)cptr, (int)size);
+
+#ifdef DEBUGMODE
+       if (size == CLIENT_LOCAL_SIZE)
+               cloc.inuse++;
+       else
+               crem.inuse++;
+#endif
+
+       /* Note:  structure is zero (calloc) */
+       cptr->from = from ? from : cptr; /* 'from' of local client is self! */
+       cptr->next = NULL; /* For machines with NON-ZERO NULL pointers >;) */
+       cptr->prev = NULL;
+       cptr->hnext = NULL;
+       cptr->user = NULL;
+       cptr->serv = NULL;
+       cptr->srvptr = servr;
+       cptr->status = STAT_UNKNOWN;
+       cptr->fd = -1;
+       (void)strcpy(cptr->username, "unknown");
+       if (size == CLIENT_LOCAL_SIZE)
+           {
+               cptr->since = cptr->lasttime =
+                 cptr->lastnick = cptr->firsttime = TStime();
+               cptr->confs = NULL;
+               cptr->sockhost[0] = '\0';
+               cptr->buffer[0] = '\0';
+               cptr->authfd = -1;
+#ifdef SOCKSPORT
+               cptr->socksfd = -1;
+#endif
+           }
+       return (cptr);
+}
+
+void   free_client(cptr)
+aClient        *cptr;
+{
+       MyFree((char *)cptr);
+}
+
+/*
+** 'make_user' add's an User information block to a client
+** if it was not previously allocated.
+*/
+anUser *make_user(cptr)
+aClient *cptr;
+{
+       Reg1    anUser  *user;
+
+       user = cptr->user;
+       if (!user)
+           {
+               user = (anUser *)MyMalloc(sizeof(anUser));
+#ifdef DEBUGMODE
+               users.inuse++;
+#endif
+               user->swhois = NULL;
+               user->away = NULL;
+               user->refcnt = 1;
+               user->joined = 0;
+               user->channel = NULL;
+               user->invited = NULL;
+               user->silence = NULL;
+               cptr->user = user;
+           }
+       return user;
+}
+
+aServer        *make_server(cptr)
+aClient        *cptr;
+{
+       Reg1    aServer *serv = cptr->serv;
+
+       if (!serv)
+           {
+               serv = (aServer *)MyMalloc(sizeof(aServer));
+#ifdef DEBUGMODE
+               servs.inuse++;
+#endif
+               serv->user = NULL;
+               serv->nexts = NULL;
+               *serv->by = '\0';
+               *serv->up = '\0';
+               cptr->serv = serv;
+           }
+       return cptr->serv;
+}
+
+/*
+** free_user
+**     Decrease user reference count by one and realease block,
+**     if count reaches 0
+*/
+void   free_user(user, cptr)
+Reg1   anUser  *user;
+aClient        *cptr;
+{
+       if (--user->refcnt <= 0)
+           {
+               if (user->away)
+                       MyFree((char *)user->away);
+               if (user->swhois)
+                       MyFree((char *)user->swhois);
+               /*
+                * sanity check
+                */
+               if (user->joined || user->refcnt < 0 ||
+                   user->invited || user->channel)
+#ifdef DEBUGMODE
+                       dumpcore("%#x user (%s!%s@%s) %#x %#x %#x %d %d",
+                               cptr, cptr ? cptr->name : "<noname>",
+                               user->username, user->realhost, user,
+                               user->invited, user->channel, user->joined,
+                               user->refcnt);
+#else
+                       sendto_ops("* %#x user (%s!%s@%s) %#x %#x %#x %d %d *",
+                               cptr, cptr ? cptr->name : "<noname>",
+                               user->username, user->realhost, user,
+                               user->invited, user->channel, user->joined,
+                               user->refcnt);
+#endif
+               MyFree((char *)user);
+#ifdef DEBUGMODE
+               users.inuse--;
+#endif
+           }
+}
+
+/*
+ * taken the code from ExitOneClient() for this and placed it here.
+ * - avalon
+ */
+void   remove_client_from_list(cptr)
+Reg1   aClient *cptr;
+{
+       checklist();
+       if (cptr->prev)
+               cptr->prev->next = cptr->next;
+       else
+           {
+               client = cptr->next;
+               if (client)
+                       client->prev = NULL;
+           }
+       if (cptr->next)
+               cptr->next->prev = cptr->prev;
+       if (IsPerson(cptr)) /* Only persons can have been added before */
+           {
+               add_history(cptr);
+               off_history(cptr); /* Remove all pointers to cptr */
+           }
+       if (cptr->user)
+               (void)free_user(cptr->user, cptr);
+       if (cptr->serv)
+           {
+               if (cptr->serv->user)
+                       free_user(cptr->serv->user, cptr);
+               MyFree((char *)cptr->serv);
+#ifdef DEBUGMODE
+               servs.inuse--;
+#endif
+           }
+#ifdef DEBUGMODE
+       if (cptr->fd == -2)
+               cloc.inuse--;
+       else
+               crem.inuse--;
+#endif
+       (void)free_client(cptr);
+       numclients--;
+       return;
+}
+
+/*
+ * although only a small routine, it appears in a number of places
+ * as a collection of a few lines...functions like this *should* be
+ * in this file, shouldnt they ?  after all, this is list.c, isnt it ?
+ * -avalon
+ */
+void   add_client_to_list(cptr)
+aClient        *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.
+        */
+       cptr->next = client;
+       client = cptr;
+       if (cptr->next)
+               cptr->next->prev = cptr;
+       return;
+}
+
+/*
+ * Look for ptr in the linked listed pointed to by link.
+ */
+Link   *find_user_link(lp, ptr)
+Reg1   Link    *lp;
+Reg2   aClient *ptr;
+{
+  if (ptr)
+       while (lp)
+          {
+               if (lp->value.cptr == ptr)
+                       return (lp);
+               lp = lp->next;
+           }
+       return NULL;
+}
+
+Link   *find_channel_link(lp, ptr)
+Reg1   Link     *lp;
+Reg2   aChannel *ptr;
+{
+  if (ptr)
+       while (lp)
+          {
+               if (lp->value.chptr == ptr)
+                       return (lp);
+               lp = lp->next;
+           }
+       return NULL;
+}
+
+
+
+/*
+ * Look for a match in a list of strings. Go through the list, and run
+ * match() on it. Side effect: if found, this link is moved to the top of
+ * the list.
+ */
+int    find_str_match_link(lp, str)
+Reg1   Link    **lp; /* Two **'s, since we might modify the original *lp */
+Reg2   char    *str;
+{
+       Link    *ptr, **head = lp;
+
+       if (lp && *lp)
+       {
+               if (!match((*lp)->value.cp, str))
+                       return 1;
+               for (; (*lp)->next; *lp = (*lp)->next)
+                       if (!match((*lp)->next->value.cp, str))
+                       {
+                               Link *temp = (*lp)->next;
+                               *lp = (*lp)->next->next;
+                               temp->next = *head;
+                               *head = temp;
+                               return 1;
+                       }
+               return 0;
+       }
+       return 0;
+}
+
+void   free_str_list(lp)
+Reg1   Link    *lp;
+{
+       Reg2    Link    *next;
+
+
+       while (lp) {
+               next = lp->next;
+               MyFree((char *)lp->value.cp);
+               free_link(lp);
+               lp = next;
+       }
+               
+       return;
+}
+
+
+#define        LINKSIZE        (4072/sizeof(Link))
+
+Link   *make_link()
+{
+       Link    *lp;
+       int     i;
+
+       /* "caching" slab-allocator... ie. we're allocating one pages
+          (hopefully - upped to the Linux default, not dbuf.c) worth of 
+          link-structures at time to avoid all the malloc overhead.
+          All links left free from this process or separately freed 
+          by a call to free_link() are moved over to freelink-list.
+          Impact? Let's see... -Donwulff */
+       if(freelink==NULL) {
+               lp = (Link *)MyMalloc(LINKSIZE*sizeof(Link));
+               freelink=lp+1;
+               flinks+=LINKSIZE;
+               for(i=1;i<(LINKSIZE-1);i++)
+                       (lp+i)->next=lp+i+1; (lp+i)->next=NULL;
+       } else {
+               lp = freelink;
+               freelink=freelink->next;
+       }
+#ifdef DEBUGMODE
+       links.inuse++;
+#endif
+       return lp;
+}
+
+void   free_link(lp)
+Reg1   Link    *lp;
+{
+       lp->next=freelink;
+       freelink=lp;
+#ifdef DEBUGMODE
+       links.inuse--;
+#endif
+}
+
+Ban    *make_ban()
+{
+       Reg1    Ban     *lp;
+
+       lp = (Ban *)MyMalloc(sizeof(Ban));
+#ifdef DEBUGMODE
+       links.inuse++;
+#endif
+       return lp;
+}
+
+void   free_ban(lp)
+Reg1   Ban     *lp;
+{
+       MyFree((char *)lp);
+#ifdef DEBUGMODE
+       links.inuse--;
+#endif
+}
+
+aClass *make_class()
+{
+       Reg1    aClass  *tmp;
+
+       tmp = (aClass *)MyMalloc(sizeof(aClass));
+#ifdef DEBUGMODE
+       classs.inuse++;
+#endif
+       return tmp;
+}
+
+void   free_class(tmp)
+Reg1   aClass  *tmp;
+{
+       MyFree((char *)tmp);
+#ifdef DEBUGMODE
+       classs.inuse--;
+#endif
+}
+
+aSqlineItem    *make_sqline()
+{
+       Reg1    aSqlineItem *asqline;
+
+       asqline = (struct SqlineItem *)MyMalloc(sizeof(aSqlineItem));
+       asqline->next = NULL;
+       asqline->sqline = asqline->reason = NULL;
+
+       return (asqline);
+}
+
+aConfItem      *make_conf()
+{
+       Reg1    aConfItem *aconf;
+
+       aconf = (struct ConfItem *)MyMalloc(sizeof(aConfItem));
+#ifdef DEBUGMODE
+       aconfs.inuse++;
+#endif
+       bzero((char *)&aconf->ipnum, 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;
+       Class(aconf) = 0;
+       return (aconf);
+}
+
+void   delist_conf(aconf)
+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_sqline(asqline)
+aSqlineItem *asqline;
+{
+       del_queries((char *)asqline);
+       MyFree(asqline->sqline);
+       MyFree(asqline->reason);
+       MyFree((char *)asqline);
+       return;
+}
+
+void   free_conf(aconf)
+aConfItem *aconf;
+{
+       del_queries((char *)aconf);
+       MyFree(aconf->host);
+       if (aconf->passwd)
+               bzero(aconf->passwd, strlen(aconf->passwd));
+       MyFree(aconf->passwd);
+       MyFree(aconf->name);
+       MyFree((char *)aconf);
+#ifdef DEBUGMODE
+       aconfs.inuse--;
+#endif
+       return;
+}
+
+#ifdef DEBUGMODE
+void   send_listinfo(cptr, name)
+aClient        *cptr;
+char   *name;
+{
+       int     inuse = 0, mem = 0, tmp = 0;
+
+       sendto_one(cptr, ":%s %d %s :Local: inuse: %d(%d)",
+                  me.name, RPL_STATSDEBUG, name, inuse += cloc.inuse,
+                  tmp = cloc.inuse * CLIENT_LOCAL_SIZE);
+       mem += tmp;
+       sendto_one(cptr, ":%s %d %s :Remote: inuse: %d(%d)",
+                  me.name, RPL_STATSDEBUG, name,
+                  crem.inuse, tmp = crem.inuse * CLIENT_REMOTE_SIZE);
+       mem += tmp;
+       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));
+       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));
+       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));
+       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(aClass));
+       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));
+       mem += tmp;
+       inuse += aconfs.inuse,
+       sendto_one(cptr, ":%s %d %s :Totals: inuse %d %d",
+                  me.name, RPL_STATSDEBUG, name, inuse, mem);
+}
+#endif
diff --git a/src/match.c b/src/match.c
new file mode 100644 (file)
index 0000000..bbc1879
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ *   IRC - Internet Relay Chat, common/match.c
+ *   Copyright (C) 1990 Jarkko Oikarinen
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1990 Jarkko Oikarinen");
+
+/*
+ *  Compare if a given string (name) matches the given
+ *  mask (which can contain wild cards: '*' - match any
+ *  number of chars, '?' - match any single character.
+ *
+ *     return  0, if match
+ *             1, if no match
+ */
+
+u_char touppertab[], tolowertab[];
+#define tolowertab2 tolowertab
+
+/*
+ * match()
+ *  written by binary
+ */
+int match(mask, name)
+char *mask, *name;
+{
+  Reg1 u_char *m; /* why didn't the old one use registers ?!??!?!?! */
+  Reg2 u_char *n;
+  Reg3 u_char cm;
+  Reg4 u_char *mylowertab;
+  u_char *wsn;
+  u_char *wsm;
+       
+  m = (u_char *)mask;
+  
+  cm = *m;
+
+    mylowertab = tolowertab2;
+#define lc(x) mylowertab[x] /* use mylowertab, because registers are FASTER */
+
+  n = (u_char *)name;  
+  if (cm == '*')
+  {
+    if (m[1] == '\0')                  /* mask is just "*", so true */
+      return 0;
+  }
+  else if (cm != '?' && lc(cm) != lc(*n))
+       return 1;                       /* most likely first chars won't match */
+  else
+  {
+       m++;
+       n++;
+  }
+  cm = lc(*m);
+  wsm = (char *)NULL;
+  while (1)
+  {
+      if (cm == '*')                   /* found the * wildcard */
+      {
+          m++;                         /* go to next char of mask */
+          if (!*m)                     /* if at end of mask, */
+              return 0;                        /* function becomes true. */
+          while (*m == '*')            /* while the char at m is "*" */
+          {
+             m++;                      /* go to next char of mask */
+             if (!*m)                  /* if at end of mask, */
+                 return 0;             /* function becomes true. */
+         }
+         cm = *m;
+         if (cm == '\\')               /* don't do ? checking if a \ */
+         {
+           cm = *(++m);                /* just skip this char, no ? checking */
+         }
+         else if (cm == '?')           /* if it's a ? */
+         {
+           do
+           {
+             m++;                      /* go to the next char of both */
+             n++;
+             if (!*n)                  /* if end of test string... */
+               return (!*m ? 0 : 1);   /* true if end of mask str, else false */
+           } while (*m == '?');        /* while we have ?'s */
+           cm = *m;
+            if (!cm)                   /* last char of mask is ?, so it's true */
+             return 0;
+         }
+         cm = lc(cm);
+         while (lc(*n) != cm)
+         {                             /* compare */
+             n++;                      /* go to next char of n */
+             if (!*n)                  /* if at end of n string */
+               return 1;               /* function becomes false. */
+         }
+         wsm = m;                      /* mark after where wildcard found */
+         cm = lc(*(++m));              /* go to next mask char */
+         wsn = n;                      /* mark spot first char was found */
+         n++;                          /* go to next char of n */
+         continue;
+      }
+      if (cm == '?')                   /* found ? wildcard */
+      {
+          cm = lc(*(++m));             /* just skip and go to next */
+          n++;
+          if (!*n)                     /* return true if end of both, */
+               return (cm ? 1 : 0);    /* false if end of test str only */
+          continue;
+      }
+      if (cm == '\\')                  /* next char will not be a wildcard. */
+      {                                        /* skip wild checking, don't continue */
+         cm = lc(*(++m));
+         n++;
+      }
+      /* Complicated to read, but to save CPU time.  Every ounce counts. */
+      if (lc(*n) != cm)                        /* if the current chars don't equal, */
+      {
+          if (!wsm)                    /* if there was no * wildcard, */
+              return 1;                        /* function becomes false. */
+          n = wsn + 1;                 /* start on char after the one we found last */
+          m = wsm;                     /* set m to the spot after the "*" */
+          cm = lc(*m);
+          while (cm != lc(*n))
+          {                            /* compare them */
+              n++;                     /* go to next char of n */
+              if (!*n)                 /* if we reached end of n string, */
+                  return 1;            /* function becomes false. */
+          }
+          wsn = n;                     /* mark spot first char was found */
+      }
+      if (!cm)                         /* cm == cn, so if !cm, then we've */
+       return 0;                       /* reached end of BOTH, so it matches */ 
+      m++;                             /* go to next mask char */
+      n++;                             /* go to next testing char */
+      cm = lc(*m); /* pointers are slower */
+  }
+}
+
+/*
+ * collapse a pattern string into minimal components.
+ * This particular version is "in place", so that it changes the pattern
+ * which is to be reduced to a "minimal" size.
+ */
+char *
+collapse(pattern)
+     char *pattern;
+{
+  Reg1 char *s;
+  Reg2 char *s1;
+  Reg3 char *t;
+  
+  s = pattern;
+  
+  if (BadPtr(pattern))
+    return pattern;
+  /*
+   * Collapse all \** into \*, \*[?]+\** into \*[?]+
+   */
+  for (; *s; s++)
+    if (*s == '\\')
+    {
+      if (!*(s + 1))
+       break;
+      else
+       s++;
+    }
+    else if (*s == '*') {
+      if (*(t = s1 = s + 1) == '*')
+       while (*t == '*')
+         t++;
+      else if (*t == '?')
+       for (t++, s1++; *t == '*' || *t == '?'; t++)
+         if (*t == '?')
+           *s1++ = *t;
+      while ((*s1++ = *t++))
+       ;
+    }
+  return pattern;
+}
+
+
+/*
+ *  Case insensitive comparison of two NULL terminated strings.
+ *
+ *     returns  0, if s1 equal to s2
+ *             <0, if s1 lexicographically less than s2
+ *             >0, if s1 lexicographically greater than s2
+ */
+int
+smycmp(s1, s2)
+     char       *s1;
+     char       *s2;
+{
+  Reg1 u_char        *str1;
+  Reg2 u_char        *str2;
+  Reg3 int            res;
+  
+  str1 = (u_char *)s1;
+  str2 = (u_char *)s2;
+  
+  while ((res = toupper(*str1) - toupper(*str2)) == 0) {
+    if (*str1 == '\0')
+      return 0;
+    str1++;
+    str2++;
+  }
+  return (res);
+}
+
+
+int
+myncmp(str1, str2, n)
+     char       *str1;
+     char       *str2;
+     int         n;
+{
+  Reg1 u_char  *s1;
+  Reg2 u_char  *s2;
+  Reg3 int      res;
+  
+  s1 = (u_char *)str1;
+  s2 = (u_char *)str2;
+  
+  while ((res = toupper(*s1) - toupper(*s2)) == 0)
+  {
+    s1++;
+    s2++;
+    n--;
+    if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
+      return 0;
+  }
+  return (res);
+}
+
+
+u_char tolowertab[] = {
+  0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+  0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+  0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+  0x1e, 0x1f,
+  ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+  '*', '+', ',', '-', '.', '/',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+  ':', ';', '<', '=', '>', '?',
+  '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+  't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^',
+  '_',
+  '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+  't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
+  0x7f,
+  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+  0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+  0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+  0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+  0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+  0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+  0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+  0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+  0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+u_char touppertab[] = {
+  0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
+  0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
+  0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+  0x1e, 0x1f,
+  ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
+  '*', '+', ',', '-', '.', '/',
+  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+  ':', ';', '<', '=', '>', '?',
+  '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
+  'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+  'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
+  0x5f,
+  '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
+  'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+  'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~',
+  0x7f,
+  0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+  0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+  0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
+  0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+  0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+  0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+  0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
+  0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+  0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+  0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+  0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
+  0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+  0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+  0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+  0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+u_char char_atribs[] = {
+/* 0-7 */      CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
+/* 8-12 */     CNTRL, CNTRL|SPACE, CNTRL|SPACE, CNTRL|SPACE, CNTRL|SPACE,
+/* 13-15 */    CNTRL|SPACE, CNTRL, CNTRL,
+/* 16-23 */    CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
+/* 24-31 */    CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL,
+/* space */    PRINT|SPACE,
+/* !"#$%&'( */ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT,
+/* )*+,-./ */  PRINT, PRINT, PRINT, PRINT, PRINT|ALLOW, PRINT|ALLOW, PRINT,
+/* 012 */      PRINT|DIGIT|ALLOW, PRINT|DIGIT|ALLOW, PRINT|DIGIT|ALLOW,
+/* 345 */      PRINT|DIGIT|ALLOW, PRINT|DIGIT|ALLOW, PRINT|DIGIT|ALLOW,
+/* 678 */      PRINT|DIGIT|ALLOW, PRINT|DIGIT|ALLOW, PRINT|DIGIT|ALLOW,
+/* 9:; */      PRINT|DIGIT|ALLOW, PRINT, PRINT,
+/* <=>? */     PRINT, PRINT, PRINT, PRINT,
+/* @ */                PRINT,
+/* ABC */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* DEF */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* GHI */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* JKL */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* MNO */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* PQR */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* STU */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* VWX */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* YZ[ */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA,
+/* \]^ */      PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* _`  */      PRINT|ALLOW,PRINT,
+/* abc */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* def */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* ghi */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* jkl */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* mno */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* pqr */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* stu */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* vwx */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW,
+/* yz{ */      PRINT|ALPHA|ALLOW, PRINT|ALPHA|ALLOW, PRINT|ALPHA,
+/* |}~ */      PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA,
+/* del */      0,
+/* 80-8f */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 90-9f */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* a0-af */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* b0-bf */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* c0-cf */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* d0-df */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* e0-ef */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* f0-ff */    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
diff --git a/src/md5.c b/src/md5.c
new file mode 100644 (file)
index 0000000..ea087ea
--- /dev/null
+++ b/src/md5.c
@@ -0,0 +1,169 @@
+/*     $Id$    */
+
+/*
+ * Copyright (c) 1996 Michael Shalayeff.
+ *
+ * This software derived from one contributed by Colin Plumb.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by Colin Plumb.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * The code for MD5 transform was taken from Colin Plumb's
+ * implementation, which has been placed in the public domain.  The
+ * MD5 cryptographic checksum was devised by Ronald Rivest, and is
+ * documented in RFC 1321, "The MD5 Message Digest Algorithm".
+ * 
+ */
+
+#include <sys/types.h>
+
+#include "struct.h"
+#include "common.h"
+
+ID_CVS("$Id$");
+/*
+ * MD5 transform algorithm, taken from code written by Colin Plumb,
+ * and put into the public domain
+ *
+ * QUESTION: Replace this with SHA, which as generally received better
+ * reviews from the cryptographic community?
+ */
+void
+MD5Init(buf)
+       u_int32_t       buf[4];
+{
+       buf[0] = 0x67452301;
+       buf[1] = 0xefcdab89;
+       buf[2] = 0x98badcfe;
+       buf[3] = 0x10325476;
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* 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 )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.
+ */
+void
+MD5Transform(buf, in)
+       u_int32_t       buf[4];
+       u_int32_t in[16];
+{
+       u_int32_t       a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
+       MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
+       MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
+       MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
+       MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
+       MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
+       MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
+       MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
+       MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
+       MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
+       MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
+       MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
+       MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
+       MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
+       MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
+       MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
+       MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
+       MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
+       MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
+       MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
+       MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
diff --git a/src/packet.c b/src/packet.c
new file mode 100644 (file)
index 0000000..fc8c675
--- /dev/null
@@ -0,0 +1,141 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, common/packet.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 "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "msg.h"
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen");
+ID_Notes("2.12 1/30/94");
+/*
+ * inittoken
+ * Cheat here, blah. Build the lookup tables from msgtab's,
+ * call them msgmap's. Called in main() with other inits.
+ * Yes, I know this is not the right module, but I said I cheat ;)
+ */
+void   inittoken(void)
+{
+       Reg1    int     loopy;
+       Reg2    int     final;
+
+       /* Find the zero-entry */
+       for (final = 0; msgtab[final].cmd; final++)
+               ;
+       /* Point all entries to it */
+       for (loopy = 0; loopy<256; loopy++)
+               msgmap[loopy] = &msgtab[final];
+       /* Build references to existing commands */
+       for (loopy = 0; msgtab[loopy].cmd; loopy++)
+               msgmap[msgtab[loopy].token[0]] = &msgtab[loopy];
+}
+/*
+** dopacket
+**     cptr - pointer to client structure for which the buffer data
+**            applies.
+**     buffer - pointr to the buffer containing the newly read data
+**     length - number of valid bytes of data in the buffer
+**
+** Note:
+**     It is implicitly assumed that dopacket is called only
+**     with cptr of "local" variation, which contains all the
+**     necessary fields (buffer etc..)
+*/
+int    dopacket(cptr, buffer, length)
+Reg3   aClient *cptr;
+char   *buffer;
+Reg4   int     length;
+{
+       register char   *ch1;
+       register char   *ch2;   
+       aClient *acpt = cptr->acpt;
+
+       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 = cptr->buffer + cptr->count;
+       ch2 = buffer;
+
+       while (--length >= 0)
+           {
+               register char g=(*ch1 = *ch2++);
+               /*
+                * Yuck.  Stuck.  To make sure we stay backward compatible,
+                * we must assume that either CR or LF terminates the message
+                * and not CR-LF.  By allowing CR or LF (alone) into the body
+                * of messages, backward compatibility is lost and major
+                * problems will arise. - Avalon
+                */
+               if (g<'\16' && (g == '\n' || g == '\r'))
+                   {
+                       if (ch1 == cptr->buffer)
+                               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;
+                       cptr->count = 0; /* ...just in case parse returns with
+                                        ** FLUSH_BUFFER without removing the
+                                        ** structure pointed by cptr... --msa
+                                        */
+                       if (parse(cptr, cptr->buffer, ch1, msgtab) ==
+                           FLUSH_BUFFER)
+                               /*
+                               ** FLUSH_BUFFER means actually that cptr
+                               ** structure *does* not exist anymore!!! --msa
+                               */
+                               return FLUSH_BUFFER;
+                       /*
+                       ** Socket is dead so exit (which always returns with
+                       ** FLUSH_BUFFER here).  - avalon
+                       */
+                       if (cptr->flags & FLAGS_DEADSOCKET)
+                               return exit_client(cptr, cptr, &me,
+                                                  "Dead Socket");
+                       ch1 = cptr->buffer;
+                   }
+               else if (ch1 < cptr->buffer + (sizeof(cptr->buffer)-1))
+                       ch1++; /* There is always room for the null */
+           }
+       cptr->count = ch1 - cptr->buffer;
+       return 0;
+}
diff --git a/src/parse.c b/src/parse.c
new file mode 100644 (file)
index 0000000..87f0229
--- /dev/null
@@ -0,0 +1,594 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, common/parse.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.
+ */
+
+/* -- Jto -- 03 Jun 1990
+ * Changed the order of defines...
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)parse.c   2.33 1/30/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+#include "struct.h"
+#include "common.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen");
+ID_Notes("2.33 1/30/94");
+#undef RAWDEBUG
+
+char   backupbuf[8192];
+
+#define MSGTAB
+#include "msg.h"
+#undef MSGTAB
+#include "sys.h"
+#include "numeric.h"
+#include "h.h"
+
+/*
+ * NOTE: parse() should not be called recursively by other functions!
+ */
+static char    *para[MAXPARA+1];
+
+static char    sender[HOSTLEN+1];
+static int     cancel_clients PROTO((aClient *, aClient *, char *));
+static void    remove_unknown PROTO((aClient *, char *));
+/*
+**  Find a client (server or user) by name.
+**
+**  *Note*
+**     Semantics of this function has been changed from
+**     the old. 'name' is now assumed to be a null terminated
+**     string and the search is the for server and user.
+*/
+aClient *find_client(name, cptr)
+char   *name;
+Reg1   aClient *cptr;
+    {
+       if (name)
+               cptr = hash_find_client(name, cptr);
+
+       return cptr;
+    }
+
+aClient        *find_nickserv(name, cptr)
+char   *name;
+Reg1   aClient *cptr;
+    {
+       if (name)
+               cptr = hash_find_nickserver(name, cptr);
+
+       return cptr;
+    }
+
+
+/*
+**  Find server by name.
+**
+**     This implementation assumes that server and user names
+**     are unique, no user can have a server name and vice versa.
+**     One should maintain separate lists for users and servers,
+**     if this restriction is removed.
+**
+**  *Note*
+**     Semantics of this function has been changed from
+**     the old. 'name' is now assumed to be a null terminated
+**     string.
+*/
+aClient *find_server(name, cptr)
+char   *name;
+Reg1   aClient *cptr;
+{
+       if (name)
+               cptr = hash_find_server(name, cptr);
+       return cptr;
+}
+
+aClient *find_name(name, cptr)
+char   *name;
+aClient *cptr;
+{
+       Reg1 aClient *c2ptr = cptr;
+
+       if (!collapse(name))
+               return c2ptr;
+
+       if ((c2ptr = hash_find_server(name, cptr)))
+               return (c2ptr);
+       if (!index(name, '*'))
+               return c2ptr;
+       for (c2ptr = client; c2ptr; c2ptr = c2ptr->next)
+           {
+               if (!IsServer(c2ptr) && !IsMe(c2ptr))
+                       continue;
+               if (match(name, c2ptr->name) == 0)
+                       break;
+               if (index(c2ptr->name, '*'))
+                       if (match(c2ptr->name, name) == 0)
+                                       break;
+           }
+       return (c2ptr ? c2ptr : cptr);
+}
+
+/*
+**  Find person by (nick)name.
+*/
+aClient *find_person(name, cptr)
+char   *name;
+aClient *cptr;
+    {
+       Reg1    aClient *c2ptr = cptr;
+
+       c2ptr = find_client(name, c2ptr);
+
+       if (c2ptr && IsClient(c2ptr) && c2ptr->user)
+               return c2ptr;
+       else
+               return cptr;
+    }
+
+/*
+ * parse a buffer.
+ *
+ * NOTE: parse() should not be called recusively by any other fucntions!
+ */
+int    parse(cptr, buffer, bufend, mptr)
+aClient *cptr;
+char   *buffer, *bufend;
+struct Message *mptr;
+    {
+       Reg1    aClient *from = cptr;
+       Reg2    char *ch, *s;
+       Reg3    int     len, i, numeric, paramcount, noprefix = 0;
+       Reg4    int     token,mfound;
+#ifdef DEBUGMODE
+       time_t  then, ticks;
+       int     retval;
+#endif
+       struct Message *bmptr;
+       
+       Debug((DEBUG_ERROR,"Parsing: %s (from %s)", buffer,(*cptr->name  ? cptr->name : "*")));
+       if (IsDead(cptr))
+               return 0;
+
+#ifdef RAWDEBUG
+               sendto_ops("Debug: parse(): %s", buffer);
+#endif
+       backupbuf[0] = '\0';
+       strcpy(backupbuf, buffer);
+       s = sender;
+       *s = '\0';
+       for (ch = buffer; *ch == ' '; ch++)
+               ;
+       para[0] = from->name;
+       if (*ch == ':')
+           {
+               /*
+               ** Copy the prefix to 'sender' assuming it terminates
+               ** with SPACE (or NULL, which is an error, though).
+               */
+               for (++ch, i = 0; *ch && *ch != ' '; ++ch )
+                       if (s < (sender + sizeof(sender)-1))
+                               *s++ = *ch; /* leave room for NULL */
+               *s = '\0';
+               /*
+               ** Actually, only messages coming from servers can have
+               ** the prefix--prefix silently ignored, if coming from
+               ** a user client...
+               **
+               ** ...sigh, the current release "v2.2PL1" generates also
+               ** null prefixes, at least to NOTIFY messages (e.g. it
+               ** puts "sptr->nickname" as prefix from server structures
+               ** where it's null--the following will handle this case
+               ** as "no prefix" at all --msa  (": NOTICE nick ...")
+               */
+               if (*sender && IsServer(cptr))
+                   {
+                       from = find_client(sender, (aClient *) NULL);
+                       if (!from || match(from->name, sender))
+                               from = find_server(sender, (aClient *)NULL);
+                       else if (!from && index(sender, '@'))
+                               from = find_nickserv(sender, (aClient *)NULL);
+
+                       para[0] = sender;
+
+                       /* Hmm! If the client corresponding to the
+                        * prefix is not found--what is the correct
+                        * action??? Now, I will ignore the message
+                        * (old IRC just let it through as if the
+                        * prefix just wasn't there...) --msa
+                        */
+                       if (!from)
+                           {
+                               Debug((DEBUG_ERROR,
+                                       "Unknown prefix (%s)(%s) from (%s)",
+                                       sender, buffer, cptr->name));
+                               ircstp->is_unpf++;
+                               remove_unknown(cptr, sender);
+                               return -1;
+                           }
+                       if (from->from != cptr)
+                           {
+                               ircstp->is_wrdi++;
+                               Debug((DEBUG_ERROR,
+                                       "Message (%s) coming from (%s)",
+                                       buffer, cptr->name));
+                               return cancel_clients(cptr, from, ch);
+                           }
+                   }
+               while (*ch == ' ')
+                       ch++;
+           }
+       else
+         noprefix = 1;
+       if (*ch == '\0')
+           {
+               ircstp->is_empt++;
+               Debug((DEBUG_NOTICE, "Empty message from host %s:%s",
+                     cptr->name, from->name));
+               return(-1);
+           }
+       /*
+       ** Extract the command code from the packet.  Point s to the end
+       ** of the command code and calculate the length using pointer
+       ** arithmetic.  Note: only need length for numerics and *all*
+       ** numerics must have paramters and thus a space after the command
+       ** code. -avalon
+       */
+       s = (char *)index(ch, ' '); /* s -> End of the command code */
+       len = (s) ? (s - ch) : 0;
+       if (len == 3 &&
+           isdigit(*ch) && isdigit(*(ch + 1)) && isdigit(*(ch + 2)))
+           {
+               mptr = NULL;
+               numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10
+                       + (*(ch + 2) - '0');
+               paramcount = MAXPARA;
+               ircstp->is_num++;
+           }
+       else
+           {
+               if (s)
+                       *s++ = '\0';
+
+               /* xx or x = token :P */
+               if ((strlen(ch) < 3) && IsServer(cptr))
+               {
+                       token = 1;
+               }
+               else
+               {
+                       token = 0;
+               }
+               bmptr = mptr;
+               
+               /* run a fast token search through if token */
+               mfound = 0; 
+               if (token == 1) 
+               {
+                       for (; mptr->cmd; mptr++)
+                       {
+                               if (strcmp(mptr->token, ch)==0)
+                               {
+                                       mfound = 1;
+                                       break;
+                               }
+                       }
+               }
+               
+               /* no token match .. grr :P */
+               if (mfound == 0) 
+               {
+                       mptr = bmptr;
+                       for (; mptr->cmd; mptr++)
+                       {
+                               if (mycmp(mptr->cmd, ch)==0)
+                                       break;
+                       }
+               }
+/*             if (ch[1] == '\0'  && IsToken(cptr))
+                       mptr = msgmap[(u_char)*ch];
+               else
+*/
+               if (!mptr->cmd)
+                   {
+                       /*
+                       ** Note: Give error message *only* to recognized
+                       ** persons. It's a nightmare situation to have
+                       ** two programs sending "Unknown command"'s or
+                       ** equivalent to each other at full blast....
+                       ** If it has got to person state, it at least
+                       ** seems to be well behaving. Perhaps this message
+                       ** should never be generated, though...  --msa
+                       ** Hm, when is the buffer empty -- if a command
+                       ** code has been found ?? -Armin
+                       */
+                       if (buffer[0] != '\0')
+                           {
+                               if (IsPerson(from))
+                                       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, TRUE)));
+                           }
+                       ircstp->is_unco++;
+                       return(-1);
+                   }
+               paramcount = mptr->parameters;
+               i = bufend - ch; /* Is this right? -Donwulff */
+               mptr->bytes += i;
+               if ((mptr->flags & 1) && !(IsServer(cptr) || IsService(cptr)))
+                       cptr->since += (2 + i / 120);
+                                       /* Allow only 1 msg per 2 seconds
+                                        * (on average) to prevent dumping.
+                                        * to keep the response rate up,
+                                        * bursts of up to 5 msgs are allowed
+                                        * -SRB
+                                        */
+           }
+       /*
+       ** Must the following loop really be so devious? On
+       ** surface it splits the message to parameters from
+       ** blank spaces. But, if paramcount has been reached,
+       ** the rest of the message goes into this last parameter
+       ** (about same effect as ":" has...) --msa
+       */
+
+       /* Note initially true: s==NULL || *(s-1) == '\0' !! */
+
+       i = 0;
+       if (s)
+           {
+               if (paramcount > MAXPARA)
+                       paramcount = MAXPARA;
+               for (;;)
+                   {
+                       /*
+                       ** Never "FRANCE " again!! ;-) Clean
+                       ** out *all* blanks.. --msa
+                       */
+                       while (*s == ' ')
+                               *s++ = '\0';
+
+                       if (*s == '\0')
+                               break;
+                       if (*s == ':')
+                           {
+                               /*
+                               ** The rest is single parameter--can
+                               ** include blanks also.
+                               */
+                               para[++i] = s + 1;
+                               break;
+                           }
+                       para[++i] = s;
+                       if (i >= paramcount)
+                               break;
+                       for (; *s != ' ' && *s; s++)
+                               ;
+                   }
+           }
+       para[++i] = NULL;
+       if (mptr == NULL)
+               return (do_numeric(numeric, cptr, from, i, para));
+       mptr->count++;
+       if (IsRegisteredUser(cptr) &&
+#ifdef IDLE_FROM_MSG
+           mptr->func == m_private)
+#else
+           mptr->func != m_ping && mptr->func != m_pong)
+#endif
+               from->user->last = TStime();
+
+       /* Lame protocol 4 stuff... this if can be removed when all are 2.9 */
+       if (noprefix && IsServer(cptr) && i >= 2 && mptr->func == m_squit &&
+           (!(from = find_server(para[1], (aClient *)NULL)) ||
+           from->from != cptr))
+       {
+         Debug((DEBUG_DEBUG,"Ignoring protocol 4 \"%s %s %s ...\"",
+             para[0], para[1], para[2]));
+         return 0;
+        }
+
+#ifndef DEBUGMODE
+       return (*mptr->func)(cptr, from, i, para);
+#else
+       then = clock();
+       retval = (*mptr->func)(cptr, from, i, para);
+       if (retval != FLUSH_BUFFER) {
+               ticks = (clock()-then);
+               if (IsServer(cptr))
+                       mptr->rticks += ticks;
+               else
+                       mptr->lticks += ticks;
+               cptr->cputime += ticks;
+       }
+
+       return retval;
+#endif
+    }
+
+/*
+ * field breakup for ircd.conf file.
+ */
+char   *getfield(newline)
+char   *newline;
+{
+       static  char *line = NULL;
+       char    *end, *field;
+       
+       if (newline)
+               line = newline;
+       if (line == NULL)
+               return(NULL);
+
+       field = line;
+       if ((end = (char *)index(line,':')) == NULL)
+           {
+               line = NULL;
+               if ((end = (char *)index(field,'\n')) == NULL)
+                       end = field + strlen(field);
+           }
+       else
+               line = end + 1;
+       *end = '\0';
+       return(field);
+}
+
+static int     cancel_clients(cptr, sptr, cmd)
+aClient        *cptr, *sptr;
+char   *cmd;
+{
+       char *cmdpriv;  
+       /*
+        * kill all possible points that are causing confusion here,
+        * I'm not sure I've got this all right...
+        * - avalon
+        * No you didn't...
+        * - Run
+        */
+       /* This little bit of code allowed paswords to nickserv to be 
+        * seen.  A definite no-no.  --Russell
+       sendto_ops("Message (%s) for %s[%s!%s@%s] from %s", cmd,
+                  sptr->name, sptr->from->name, sptr->from->username,
+                  sptr->from->sockhost, get_client_name(cptr, TRUE));*/
+       /*
+        * Incorrect prefix for a server from some connection.  If it is a
+        * client trying to be annoying, just QUIT them, if it is a server
+        * then the same deal.
+        */
+       if (IsServer(sptr) || IsMe(sptr))
+           {
+               /*
+                * First go at tracking down what really causes the
+                * dreaded Fake Direction error.  It should not be possible
+                * ever to happen.  Assume nothing here since this is an
+                * impossibility.
+                *
+                * Check for valid fields, then send out globops with
+                * the msg command recieved, who apperently sent it,
+                * where it came from, and where it was suppose to come
+                * from.  We send the msg command to find out if its some
+                * bug somebody found with an old command, maybe some
+                * weird thing like, /ping serverto.* serverfrom.* and on
+                * the way back, fake direction?  Don't know, maybe this
+                * will tell us.  -Cabal95
+                *
+                * Take #2 on Fake Direction.  Most of them seem to be
+                * numerics.  But sometimes its getting fake direction on
+                * SERVER msgs.. HOW??  Display the full message now to
+                * figure it out... -Cabal95
+                *
+                * Okay I give up.  Can't find it.  Seems like it will
+                * exist untill ircd is completely rewritten. :/ For now
+                * just completely ignore them.  Needs to be modified to
+                * send these messages to a special oper channel. -Cabal95
+                *
+               aClient *from;
+               char    *fromname=NULL, *sptrname=NULL, *cptrname=NULL, *s;
+
+               while (*cmd == ' ')
+                       cmd++;
+               if (s = index(cmd, ' '))
+                       *s++ = '\0';
+               if (!strcasecmp(cmd, "PRIVMSG") ||
+                   !strcasecmp(cmd, "NOTICE") ||
+                   !strcasecmp(cmd, "PASS"))
+                       s = NULL;
+               if (sptr && sptr->name)
+                       sptrname = sptr->name;
+               if (cptr && cptr->name)
+                       cptrname = cptr->name;
+               if (sptr && sptr->from && sptr->from->name)
+                       fromname = sptr->from->name;
+
+               sendto_serv_butone(NULL, ":%s GLOBOPS :"
+                       "Fake Direction: Message[%s %s] from %s via %s "
+                       "instead of %s (Tell Cabal95)", me.name, cmd,
+                       (s ? s : ""),
+                       (sptr->name!=NULL)?sptr->name:"<unknown>",
+                       (cptr->name!=NULL)?cptr->name:"<unknown>",
+                       (fromname!=NULL)?fromname:"<unknown>");
+               sendto_ops(
+                       "Fake Direction: Message[%s %s] from %s via %s "
+                       "instead of %s (Tell Cabal95)", cmd,
+                       (s ? s : ""),
+                       (sptr->name!=NULL)?sptr->name:"<unknown>",
+                       (cptr->name!=NULL)?cptr->name:"<unknown>",
+                       (fromname!=NULL)?fromname:"<unknown>");
+
+               /*
+                * We don't drop the server anymore.  Just ignore
+                * the message and go about your business.  And hope
+                * we don't get flooded. :-)  -Cabal95
+               sendto_ops("Dropping server %s", cptr->name);
+               return exit_client(cptr, cptr, &me, "Fake Direction");
+                */
+               return 0;
+           }
+       /*
+        * Ok, someone is trying to impose as a client and things are
+        * confused.  If we got the wrong prefix from a server, send out a
+        * kill, else just exit the lame client.
+        */
+       if (IsServer(cptr))
+           {
+               /*
+               ** It is NOT necessary to send a KILL here...
+               ** We come here when a previous 'NICK new'
+               ** nick collided with an older nick, and was
+               ** ignored, and other messages still were on
+               ** the way (like the following USER).
+               ** We simply ignore it all, a purge will be done
+               ** automatically by the server 'cptr' as a reaction
+               ** on our 'NICK older'. --Run
+               */
+               return 0; /* On our side, nothing changed */
+           }
+       return exit_client(cptr, cptr, &me, "Fake prefix");
+}
+
+static void    remove_unknown(cptr, sender)
+aClient        *cptr;
+char   *sender;
+{
+       if (!IsRegistered(cptr) || IsClient(cptr))
+               return;
+       /*
+        * Not from a server so don't need to worry about it.
+        */
+       if (!IsServer(cptr))
+               return;
+
+       /*
+        * Do kill if it came from a server because it means there is a ghost
+        * user on the other server which needs to be removed. -avalon
+        */
+       if (!index(sender, '.'))
+               sendto_one(cptr, ":%s KILL %s :%s (%s(?) <- %s)",
+                          me.name, sender, me.name, sender,
+                          get_client_name(cptr, FALSE));
+       else
+               sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)",
+                          me.name, sender, get_client_name(cptr, FALSE));
+}
diff --git a/src/res.c b/src/res.c
new file mode 100644 (file)
index 0000000..d24dbf3
--- /dev/null
+++ b/src/res.c
@@ -0,0 +1,1741 @@
+/*
+ * 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.
+ */
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "h.h"
+
+#include <signal.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif
+#include "nameser.h"
+#include "resolv.h"
+
+#ifndef lint
+static  char sccsid[] = "@(#)res.c     2.38 4/13/94 (C) 1992 Darren Reed";
+#endif
+
+ID_CVS("$Id$");
+ID_Copyright("(C) 1992 Darren Reed");
+ID_Notes("2.38 4/13/94");
+
+#undef DEBUG   /* because there is a lot of debug code in here :-) */
+
+extern int     dn_expand PROTO((char *, char *, char *, char *, int));
+extern int     dn_skipname PROTO((char *, char *));
+extern int     res_mkquery PROTO((int, char *, int, int, char *, int,
+                                  struct rrec *, char *, int));
+
+#ifndef _WIN32
+extern int     errno, h_errno;
+#endif
+extern int     highest_fd;
+extern aClient *local[];
+
+static char    hostbuf[512]; /* tq lamego/ptlink ircd */
+static char    dot[] = ".";
+static int     incache = 0;
+static CacheTable      hashtable[ARES_CACSIZE];
+static aCache  *cachetop = NULL;
+static ResRQ   *last, *first;
+
+static void    rem_cache PROTO((aCache *));
+static void    rem_request PROTO((ResRQ *));
+static int     do_query_name PROTO((Link *, char *, ResRQ *));
+static int     do_query_number PROTO((Link *, struct in_addr *, ResRQ *));
+static void    resend_query PROTO((ResRQ *));
+static int     proc_answer PROTO((ResRQ *, HEADER *, char *, char *));
+static int     query_name PROTO((char *, int, int, ResRQ *));
+static aCache  *make_cache PROTO((ResRQ *));
+static aCache  *find_cache_name PROTO((char *));
+static aCache  *find_cache_number PROTO((ResRQ *, char *));
+static int     add_request PROTO((ResRQ *));
+static ResRQ   *make_request PROTO((Link *));
+static int     send_res_msg PROTO((char *, int, int));
+static ResRQ   *find_id PROTO((int));
+static int     hash_number PROTO((unsigned char *));
+static void    update_list PROTO((ResRQ *, aCache *));
+static int     hash_name PROTO((char *));
+
+#ifdef _WIN32
+static void    async_dns(void *parm);
+#endif
+
+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;
+} reinfo;
+
+int    init_resolver(op)
+int    op;
+{
+       int     ret = 0;
+
+#ifdef LRAND48
+       srand48(TStime());
+#endif
+       if (op & RES_INITLIST)
+           {
+               bzero((char *)&reinfo, sizeof(reinfo));
+               first = last = NULL;
+           }
+       if (op & RES_CALLINIT)
+           {
+               ret = res_init();
+               if (!_res.nscount)
+                   {
+                       _res.nscount = 1;
+                       _res.nsaddr_list[0].sin_addr.s_addr =
+                               inet_addr("127.0.0.1");
+                   }
+           }
+
+       if (op & RES_INITSOCK)
+        {
+#ifndef _WIN32
+               int on = 0;
+               ret = resfd = socket(AF_INET, SOCK_DGRAM, 0);
+               set_non_blocking(resfd, &me);
+                (void) setsockopt(ret, SOL_SOCKET, SO_BROADCAST,
+                    (char *)&on, sizeof(on));
+#else
+               /* We use Windows internal resolv functions so we have nothing
+                * to do here
+                */
+#endif
+        }
+#ifdef DEBUG
+       if (op & RES_INITDEBG);
+               _res.options |= RES_DEBUG;
+#endif
+       if (op & RES_INITCACH)
+           {
+               bzero((char *)&cainfo, sizeof(cainfo));
+               bzero((char *)hashtable, sizeof(hashtable));
+           }
+       if (op == 0)
+               ret = resfd;
+       return ret;
+}
+
+static int     add_request(new)
+ResRQ *new;
+{
+       if (!new)
+               return -1;
+       if (!first)
+               first = last = new;
+       else
+           {
+               last->next = new;
+               last = new;
+           }
+       new->next = NULL;
+       reinfo.re_requests++;
+       return 0;
+}
+
+/*
+ * 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(old)
+ResRQ  *old;
+{
+       Reg1    ResRQ   **rptr, *r2ptr = NULL;
+       Reg2    int     i;
+       Reg3    char    *s;
+
+       if (!old)
+               return;
+#ifdef _WIN32
+       while (old->locked)
+               Sleep(0);
+#endif
+       for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next)
+               if (*rptr == old)
+                   {
+                       *rptr = old->next;
+                       if (last == old)
+                               last = r2ptr;
+                       break;
+                   }
+#ifdef DEBUG
+       Debug((DEBUG_INFO,"rem_request:Remove %#x at %#x %#x",
+               old, *rptr, r2ptr));
+#endif
+       r2ptr = old;
+#ifndef _WIN32
+       if (r2ptr->he.h_name)
+               MyFree((char *)r2ptr->he.h_name);
+       for (i = 0; i < MAXALIASES; i++)
+               if ((s = r2ptr->he.h_aliases[i]))
+                       MyFree(s);
+#else
+       if (r2ptr->he)
+               MyFree(r2ptr->he);
+#endif
+       if (r2ptr->name)
+               MyFree(r2ptr->name);
+       MyFree(r2ptr);
+
+       return;
+}
+
+/*
+ * Create a DNS request record for the server.
+ */
+static ResRQ   *make_request(lp)
+Link   *lp;
+{
+       Reg1    ResRQ   *nreq;
+
+       nreq = (ResRQ *)MyMalloc(sizeof(ResRQ));
+       bzero((char *)nreq, sizeof(ResRQ));
+       nreq->next = NULL; /* where NULL is non-zero ;) */
+       nreq->sentat = TStime();
+       nreq->retries = 3;
+       nreq->resend = 1;
+       nreq->srch = -1;
+       if (lp)
+               bcopy((char *)lp, (char *)&nreq->cinfo, sizeof(Link));
+       else
+               bzero((char *)&nreq->cinfo, sizeof(Link));
+       nreq->timeout = 4;      /* start at 4 and exponential inc. */
+#ifndef _WIN32
+       nreq->he.h_addrtype = AF_INET;
+       nreq->he.h_name = NULL;
+       nreq->he.h_aliases[0] = NULL;
+#else
+       nreq->he = (struct hostent *)MyMalloc(MAXGETHOSTSTRUCT);
+       bzero((char *)nreq->he, MAXGETHOSTSTRUCT);
+       nreq->he->h_addrtype = AF_INET;
+       nreq->he->h_name = NULL;
+#endif
+       (void)add_request(nreq);
+       return nreq;
+}
+
+/*
+ * Remove queries from the list which have been there too long without
+ * being resolved.
+ */
+time_t timeout_query_list(now)
+time_t now;
+{
+       Reg1    ResRQ   *rptr, *r2ptr;
+       Reg2    time_t  next = 0, tout;
+       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;
+#ifndef _WIN32
+               if (now >= tout)
+#else
+               if (now >= tout && !rptr->locked)
+#endif
+                       if (--rptr->retries <= 0)
+                           {
+#ifdef DEBUG
+                               Debug((DEBUG_ERROR,"timeout %x now %d cptr %x",
+                                       rptr, now, rptr->cinfo.value.cptr));
+#endif
+                               reinfo.re_timeouts++;
+                               cptr = rptr->cinfo.value.cptr;
+                               switch (rptr->cinfo.flags)
+                               {
+                               case ASYNC_CLIENT :
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+                                       write(cptr->fd, REPORT_FAIL_DNS,
+                                               R_fail_dns);
+#else
+                                       send(cptr->fd, REPORT_FAIL_DNS,
+                                               R_fail_dns, 0);
+#endif
+#endif
+                                       ClearDNS(cptr);
+                                       if (!DoingAuth(cptr))
+                                               SetAccess(cptr);
+                                       break;
+                               case ASYNC_SERVER :
+                                       sendto_ops("Host %s unknown",
+                                                  rptr->name);
+                                       ClearDNS(cptr);
+                                       if (check_server(cptr, NULL,
+                                                        NULL, NULL, 1))
+                                               (void)exit_client(cptr, cptr,
+                                                       &me, "No Permission");
+                                       break;
+                               case ASYNC_CONNECT :
+                                       sendto_ops("Host %s unknown",
+                                                  rptr->name);
+                                       break;
+                               }
+                               rem_request(rptr);
+                               continue;
+                           }
+                       else
+                           {
+                               rptr->sentat = now;
+                               rptr->timeout += rptr->timeout;
+#ifndef _WIN32
+                               resend_query(rptr);
+#endif
+                               tout = now + rptr->timeout;
+#ifdef DEBUG
+                               Debug((DEBUG_INFO,"r %x now %d retry %d c %x",
+                                       rptr, now, rptr->retries,
+                                       rptr->cinfo.value.cptr));
+#endif
+                           }
+               if (!next || tout < next)
+                       next = tout;
+           }
+       Debug((DEBUG_DNS,"Next timeout_query_list() at %s, %d",
+           myctime((next > now) ? next : (now + AR_TTL)),
+           (next > now) ? (next - now) : AR_TTL));
+       return (next > now) ? next : (now + AR_TTL);
+}
+
+/*
+ * del_queries - called by the server to cleanup outstanding queries for
+ * which there no longer exist clients or conf lines.
+ */
+void   del_queries(cp)
+char   *cp;
+{
+       Reg1    ResRQ   *rptr, *r2ptr;
+
+       for (rptr = first; rptr; rptr = r2ptr)
+           {
+               r2ptr = rptr->next;
+               if (cp == rptr->cinfo.value.cp)
+                       rem_request(rptr);
+           }
+}
+
+#ifndef _WIN32
+/*
+ * sends msg to all nameservers found in the "_res" structure.
+ * This should reflect /etc/resolv.conf. We will get responses
+ * which arent needed but is easier than checking to see if nameserver
+ * isnt present. Returns number of messages successfully sent to 
+ * nameservers or -1 if no successful sends.
+ */
+static int     send_res_msg(msg, len, rcount)
+char   *msg;
+int    len, rcount;
+{
+       Reg1    int     i;
+       int     sent = 0, max;
+
+       if (!msg)
+               return -1;
+
+       max = MIN(_res.nscount, rcount);
+       if (_res.options & RES_PRIMARY)
+               max = 1;
+       if (!max)
+               max = 1;
+
+       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++;
+                   }
+               else
+                       Debug((DEBUG_ERROR,"s_r_m:sendto: %d on %d",
+                               errno, resfd));
+           }
+
+       return (sent) ? sent : -1;
+}
+#endif /*_WIN32*/
+
+/*
+ * find a dns request id (id is determined by dn_mkquery)
+ */
+static ResRQ   *find_id(id)
+int    id;
+{
+       Reg1    ResRQ   *rptr;
+
+       for (rptr = first; rptr; rptr = rptr->next)
+               if (rptr->id == id)
+                       return rptr;
+       return NULL;
+}
+
+struct hostent *gethost_byname(name, lp)
+char   *name;
+Link   *lp;
+{
+       Reg1    aCache  *cp;
+
+       reinfo.re_na_look++;
+       if ((cp = find_cache_name(name)))
+#ifndef _WIN32
+               return (struct hostent *)&(cp->he);
+#else
+               return (struct hostent *)cp->he;
+#endif
+       if (!lp)
+               return NULL;
+       (void)do_query_name(lp, name, NULL);
+       return NULL;
+}
+
+struct hostent *gethost_byaddr(addr, lp)
+char   *addr;
+Link   *lp;
+{
+       aCache  *cp;
+
+       reinfo.re_nu_look++;
+       if ((cp = find_cache_number(NULL, addr)))
+#ifndef _WIN32
+               return (struct hostent *)&(cp->he);
+#else
+               return (struct hostent *)cp->he;
+#endif
+       if (!lp)
+               return NULL;
+       (void)do_query_number(lp, (struct in_addr *)addr, NULL);
+       return NULL;
+}
+
+static int     do_query_name(lp, name, rptr)
+Link   *lp;
+char   *name;
+Reg1   ResRQ   *rptr;
+{
+#ifndef _WIN32
+       char    hname[HOSTLEN+1];
+       int     len;
+
+       (void)strncpy(hname, name, sizeof(hname) - 1);
+       len = strlen(hname);
+
+       if (rptr && !index(hname, '.') && _res.options & RES_DEFNAMES)
+           {
+               (void)strncat(hname, dot, sizeof(hname) - len - 1);
+               len++;
+               (void)strncat(hname, _res.defdname, sizeof(hname) - len -1);
+           }
+#endif
+       /*
+        * Store the name passed as the one to lookup and generate other host
+        * names to pass onto the nameserver(s) for lookups.
+        */
+       if (!rptr)
+           {
+               rptr = make_request(lp);
+               rptr->type = T_A;
+               rptr->name = (char *)MyMalloc(strlen(name) + 1);
+               (void)strcpy(rptr->name, name);
+           }
+#ifndef _WIN32
+       return (query_name(hname, C_IN, T_A, rptr));
+#else
+
+       rptr->id = _beginthread(async_dns, 0, (void *)rptr);
+       rptr->sends++;
+       return 0;
+#endif
+}
+
+/*
+ * Use this to do reverse IP# lookups.
+ */
+static int     do_query_number(lp, numb, rptr)
+Link   *lp;
+struct in_addr *numb;
+Reg1   ResRQ   *rptr;
+{
+#ifndef _WIN32
+       char    ipbuf[32];
+       Reg2    u_char  *cp;
+
+       cp = (u_char *)&numb->s_addr;
+       (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
+               (u_int)(cp[3]), (u_int)(cp[2]),
+               (u_int)(cp[1]), (u_int)(cp[0]));
+#endif
+       if (!rptr)
+           {
+               rptr = make_request(lp);
+               rptr->type = T_PTR;
+               rptr->addr.s_addr = numb->s_addr;
+#ifndef _WIN32
+               bcopy((char *)&numb->s_addr,
+                       (char *)&rptr->he.h_addr, sizeof(struct in_addr));
+               rptr->he.h_length = sizeof(struct in_addr);
+#else
+               rptr->he->h_length = sizeof(struct in_addr);
+#endif
+           }
+#ifndef _WIN32
+       return (query_name(ipbuf, C_IN, T_PTR, rptr));
+#else
+       rptr->id = _beginthread(async_dns, 0, (void *)rptr);
+       rptr->sends++;
+       return 0;
+#endif
+}
+
+#ifndef _WIN32
+/*
+ * generate a query based on class, type and name.
+ */
+static int     query_name(name, class, type, rptr)
+char   *name;
+int    class, type;
+ResRQ  *rptr;
+{
+       struct  timeval tv;
+       char    buf[MAXPACKET];
+       int     r,s,k = 0;
+       HEADER  *hptr;
+
+        Debug((DEBUG_DNS,"query_name: na %s cl %d ty %d", name, class, type));
+       bzero(buf, sizeof(buf));
+       r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
+                       buf, sizeof(buf));
+       if (r <= 0)
+           {
+               h_errno = NO_RECOVERY;
+               return r;
+           }
+       hptr = (HEADER *)buf;
+#ifdef LRAND48
+        do {
+               hptr->id = htons(ntohs(hptr->id) + k + lrand48() & 0xffff);
+#else
+       (void) gettimeofday(&tv, NULL);
+       do {
+               /* htons/ntohs can be assembler macros, which cannot
+                  be nested. Thus two lines.   -Vesa               */
+               u_short nstmp = ntohs(hptr->id) + k +
+                               (u_short)(tv.tv_usec & 0xffff);
+               hptr->id = htons(nstmp);
+#endif /* LRAND48 */
+               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;
+           }
+       else
+               rptr->sent += s;
+       return 0;
+}
+
+static void    resend_query(rptr)
+ResRQ  *rptr;
+{
+       if (rptr->resend == 0)
+               return;
+       reinfo.re_resends++;
+       switch(rptr->type)
+       {
+       case T_PTR:
+               (void)do_query_number(NULL, &rptr->addr, rptr);
+               break;
+       case T_A:
+               (void)do_query_name(NULL, rptr->name, rptr);
+               break;
+       default:
+               break;
+       }
+       return;
+}
+
+/*
+ * process name server reply.
+ */
+static int     proc_answer(rptr, hptr, buf, eob)
+ResRQ  *rptr;
+char   *buf, *eob;
+HEADER *hptr;
+{
+       Reg1    char    *cp, **alias;
+       Reg2    struct  hent    *hp;
+       int     class, type, dlen, len, ans = 0, n;
+       struct  in_addr dr, *adr;
+
+       cp = buf + sizeof(HEADER);
+       hp = (struct hent *)&(rptr->he);
+       adr = &hp->h_addr;
+       while (adr->s_addr)
+               adr++;
+       alias = hp->h_aliases;
+       while (*alias)
+               alias++;
+#ifdef SOL20           /* 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)
+                       break;
+               else
+                       cp += (n + QFIXEDSZ);
+       /*
+        * proccess each answer sent to us blech.
+        */
+       while (hptr->ancount-- > 0 && cp && cp < eob) {
+               n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf));
+               if (n <= 0)
+                       break;
+
+               cp += n;
+               type = (int)_getshort(cp);
+               cp += sizeof(short);
+               class = (int)_getshort(cp);
+               cp += sizeof(short);
+               rptr->ttl = _getlong(cp);
+#ifndef        LINUX_ALPHA
+               cp += sizeof(rptr->ttl);
+#else
+       /* This should really use the GETLONG macro which advances
+        * the pointer for us, but I don't know if that'll break other
+        * systems. sizeof(_getlong) does not always equal sizeof(time_t).
+        * This is the case on Linux alpha. 4 is the current standard
+        * for this portion of the resolver reply it would seem.
+       * heydowns@borg.com
+        */
+               cp += 4;
+
+#endif
+               dlen =  (int)_getshort(cp);
+               cp += sizeof(short);
+               rptr->type = type;
+
+               len = strlen(hostbuf);
+               /* name server never returns with trailing '.' */
+               if (!index(hostbuf,'.') && (_res.options & RES_DEFNAMES))
+                   {
+                       (void)strcat(hostbuf, dot);
+                       len++;
+                       (void)strncat(hostbuf, _res.defdname,
+                               sizeof(hostbuf) - 1 - len);
+                       len = MIN(len + strlen(_res.defdname),
+                                 sizeof(hostbuf) - 1);
+                   }
+
+               switch(type)
+               {
+               case T_A :
+                       hp->h_length = dlen;
+                       if (ans == 1)
+                               hp->h_addrtype =  (class == C_IN) ?
+                                                       AF_INET : AF_UNSPEC;
+                       bcopy(cp, (char *)&dr, dlen);
+                       adr->s_addr = dr.s_addr;
+                       Debug((DEBUG_INFO,"got ip # %s for %s",
+                               inetntoa((char *)adr), hostbuf));
+                       if (!hp->h_name)
+                           {
+                               hp->h_name =(char *)MyMalloc(len+1);
+                               (void)strcpy(hp->h_name, hostbuf);
+                           }
+                       ans++;
+                       adr++;
+                       cp += dlen;
+                       break;
+               case T_PTR :
+                       if((n = dn_expand(buf, eob, cp, hostbuf,
+                                         sizeof(hostbuf) )) < 0)
+                           {
+                               cp = NULL;
+                               break;
+                           }
+                       cp += n;
+                       len = strlen(hostbuf);
+                       Debug((DEBUG_INFO,"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 >= &(hp->h_aliases[MAXALIASES-1]))
+                                       break;
+                               *alias = (char *)MyMalloc(len + 1);
+                               (void)strcpy(*alias++, hostbuf);
+                               *alias = NULL;
+                           }
+                       else
+                           {
+                               hp->h_name = (char *)MyMalloc(len + 1);
+                               (void)strcpy(hp->h_name, hostbuf);
+                           }
+                       ans++;
+                       break;
+               case T_CNAME :
+                       cp += dlen;
+                       Debug((DEBUG_INFO,"got cname %s", hostbuf));
+                       if (alias >= &(hp->h_aliases[MAXALIASES-1]))
+                               break;
+                       *alias = (char *)MyMalloc(len + 1);
+                       (void)strcpy(*alias++, hostbuf);
+                       *alias = NULL;
+                       ans++;
+                       break;
+               default :
+#ifdef DEBUG
+                       Debug((DEBUG_INFO,"proc_answer: type:%d for:%s",
+                             type, hostbuf));
+#endif
+                       break;
+               }
+       }
+       return ans;
+}
+#endif /*_WIN32*/
+
+/*
+ * read a dns reply from the nameserver and process it.
+ */
+#ifndef _WIN32
+struct hostent *get_res(lp)
+char   *lp;
+#else
+struct hostent *get_res(lp, id)
+char   *lp;
+long   id;
+#endif
+{
+#ifndef _WIN32
+       static  char    buf[sizeof(HEADER) + MAXPACKET];
+       Reg1    HEADER  *hptr;
+       struct  sockaddr_in     sin;
+       int     rc, a, len = sizeof(sin), max;
+#else
+       Reg3    struct hostent  *he;
+#endif
+       Reg2    ResRQ   *rptr = NULL;
+       aCache  *cp;
+
+#ifndef _WIN32
+       rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin,
+                     &len);
+       if (rc == -1 || rc <= sizeof(HEADER))
+               goto getres_err;
+       /*
+        * 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
+#endif
+       reinfo.re_replies++;
+       /*
+        * response for an id which we have already received an answer for
+        * just ignore this response.
+        */
+#ifndef _WIN32
+       rptr = find_id(hptr->id);
+#else
+       rptr = find_id(id);
+#endif
+       if (!rptr)
+               goto getres_err;
+#ifndef _WIN32
+       /*
+        * 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 ||
+                   !bcmp((char *)&sin.sin_addr,
+                         (char *)&_res.nsaddr_list[a].sin_addr,
+                         sizeof(struct in_addr)))
+                       break;
+       if (a == max)
+           {
+               reinfo.re_unkrep++;
+               goto getres_err;
+           }
+
+       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;
+           }
+       a = proc_answer(rptr, hptr, buf, buf+rc);
+#ifdef DEBUG
+       Debug((DEBUG_INFO,"get_res:Proc answer = %d",a));
+#endif
+       if (a && rptr->type == T_PTR)
+           {
+               struct  hostent *hp2 = NULL;
+
+               Debug((DEBUG_DNS, "relookup %s <-> %s",
+                       rptr->he.h_name, inetntoa((char *)&rptr->he.h_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(rptr->he.h_name, &rptr->cinfo)))
+                       if (lp)
+                               bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
+               /*
+                * 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
+                */
+               if (!hp2 && rptr->he.h_aliases[0])
+                       for (a = 0; rptr->he.h_aliases[a]; a++)
+                           {
+                               Debug((DEBUG_DNS, "Copied CNAME %s for %s",
+                                       rptr->he.h_aliases[a],
+                                       rptr->he.h_name));
+                               last->he.h_aliases[a] = rptr->he.h_aliases[a];
+                               rptr->he.h_aliases[a] = NULL;
+                           }
+
+               rem_request(rptr);
+               return hp2;
+           }
+
+       if (a > 0)
+           {
+               if (lp)
+                       bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
+               cp = make_cache(rptr);
+#ifdef DEBUG
+       Debug((DEBUG_INFO,"get_res:cp=%#x rptr=%#x (made)",cp,rptr));
+#endif
+
+               rem_request(rptr);
+           }
+       else
+               if (!rptr->sent)
+                       rem_request(rptr);
+       return cp ? (struct hostent *)&cp->he : NULL;
+
+getres_err:
+       /*
+        * Reprocess an error if the nameserver didnt tell us to "TRY_AGAIN".
+        */
+       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)
+                       bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
+           }
+#else /*_WIN32*/
+       he = rptr->he;
+
+       if (he && he->h_name && ((struct in_addr *)he->h_addr)->s_addr &&
+           rptr->locked < 2)
+           {
+               /*
+                * We only need to re-check the DNS if its a "byaddr" call,
+                * the "byname" calls will work correctly. -Cabal95
+                */
+               char    tempname[120];
+               int     i;
+               long    amt;
+               struct  hostent *hp, *he = rptr->he;
+
+               strcpy(tempname, he->h_name);
+               hp = gethostbyname(tempname);
+               if (hp && !bcmp(hp->h_addr, he->h_addr, sizeof(struct in_addr)))
+                   {
+                   }
+               else
+                       rptr->he->h_name = NULL;
+           }
+       if (lp)
+               bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
+       cp = make_cache(rptr);
+# ifdef DEBUG
+       Debug((DEBUG_INFO,"get_res:cp=%#x rptr=%#x (made)", cp, rptr));
+# endif
+       rptr->locked = 0;
+       rem_request(rptr);
+       return cp ? (struct hostent *)cp->he : NULL;
+
+getres_err:
+       if (lp && rptr)
+               bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
+#endif
+       return (struct hostent *)NULL;
+}
+
+static int     hash_number(ip)
+Reg1 unsigned char *ip;
+{
+       Reg1    u_int   hashv = 0;
+
+       /* could use loop but slower */
+       hashv += (int)*ip++;
+       hashv += hashv + (int)*ip++;
+       hashv += hashv + (int)*ip++;
+       hashv += hashv + (int)*ip++;
+       hashv %= ARES_CACSIZE;
+       return (hashv);
+}
+
+static int     hash_name(name)
+register       char    *name;
+{
+       Reg1    u_int   hashv = 0;
+
+       if (name == NULL) {
+               sendto_realops ("Caught NULL pointer in hash_name().  (Bad thing -- tell rwg.)");
+               return (0);
+       }
+
+       for (; *name && *name != '.'; name++)
+               hashv += *name;
+       hashv %= ARES_CACSIZE;
+       return (hashv);
+}
+
+/*
+** Add a new cache item to the queue and hash table.
+*/
+static aCache  *add_to_cache(ocp)
+Reg1   aCache  *ocp;
+{
+       Reg1    aCache  *cp = NULL;
+       Reg2    int     hashv;
+
+#ifdef DEBUG
+       Debug((DEBUG_INFO,
+             "add_to_cache:ocp %#x he %#x name %#x addrl %#x 0 %#x",
+               ocp, &ocp->he, ocp->he.h_name, ocp->he.h_addr_list,
+               ocp->he.h_addr_list[0]));
+#endif
+       ocp->list_next = cachetop;
+       cachetop = ocp;
+
+#ifndef _WIN32
+       hashv = hash_name(ocp->he.h_name);
+#else
+       hashv = hash_name(ocp->he->h_name);
+#endif
+       ocp->hname_next = hashtable[hashv].name_list;
+       hashtable[hashv].name_list = ocp;
+
+#ifndef _WIN32
+       hashv = hash_number((u_char *)ocp->he.h_addr);
+#else
+       hashv = hash_number((u_char *)ocp->he->h_addr);
+#endif
+       ocp->hnum_next = hashtable[hashv].num_list;
+       hashtable[hashv].num_list = ocp;
+
+#ifdef DEBUG
+       Debug((DEBUG_INFO, "add_to_cache:added %s[%08x] cache %#x.",
+# ifndef _WIN32
+               ocp->he.h_name, ocp->he.h_addr_list[0], ocp));
+# else
+               ocp->he->h_name, ocp->he->h_addr_list[0], ocp));
+# endif
+       Debug((DEBUG_INFO,
+               "add_to_cache:h1 %d h2 %x lnext %#x namnext %#x numnext %#x",
+# ifndef _WIN32
+               hash_name(ocp->he.h_name), hashv, ocp->list_next,
+# else
+               hash_name(ocp->he->h_name), hashv, ocp->list_next,
+# endif
+               ocp->hname_next, ocp->hnum_next));
+#endif
+
+       /*
+        * LRU deletion of excessive cache entries.
+        */
+       if (++incache > MAXCACHED)
+           {
+               for (cp = cachetop; cp->list_next; cp = cp->list_next)
+                       ;
+               rem_cache(cp);
+           }
+       cainfo.ca_adds++;
+
+       return ocp;
+}
+
+/*
+** 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(rptr, cachep)
+ResRQ  *rptr;
+aCache *cachep;
+{
+       Reg1    aCache  **cpp, *cp = cachep;
+       Reg2    char    *s, *t, **base;
+       Reg3    int     i, j;
+       int     addrcount;
+
+       /*
+       ** 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))
+               if (cp == *cpp)
+                       break;
+       if (!*cpp)
+               return;
+       *cpp = cp->list_next;
+       cp->list_next = cachetop;
+       cachetop = cp;
+#ifndef _WIN32
+       if (!rptr)
+               return;
+
+#ifdef DEBUG
+       Debug((DEBUG_DEBUG,"u_l:cp %#x na %#x al %#x ad %#x",
+               cp,cp->he.h_name,cp->he.h_aliases,cp->he.h_addr));
+       Debug((DEBUG_DEBUG,"u_l:rptr %#x h_n %#x", rptr, rptr->he.h_name));
+#endif
+       /*
+        * Compare the cache entry against the new record.  Add any
+        * previously missing names for this entry.
+        */
+       for (i = 0; cp->he.h_aliases[i]; i++)
+               ;
+       addrcount = i;
+       for (i = 0, s = rptr->he.h_name; s && i < MAXALIASES;
+            s = rptr->he.h_aliases[i++])
+           {
+               for (j = 0, t = cp->he.h_name; t && j < MAXALIASES;
+                    t = cp->he.h_aliases[j++])
+                       if (!mycmp(t, s))
+                               break;
+               if (!t && j < MAXALIASES-1)
+                   {
+                       base = cp->he.h_aliases;
+
+                       addrcount++;
+                       base = (char **)MyRealloc((char *)base,
+                                       sizeof(char *) * (addrcount + 1));
+                       cp->he.h_aliases = base;
+#ifdef DEBUG
+                       Debug((DEBUG_DNS,"u_l:add name %s hal %x ac %d",
+                               s, cp->he.h_aliases, addrcount));
+#endif
+                       base[addrcount-1] = s;
+                       base[addrcount] = NULL;
+                       if (i)
+                               rptr->he.h_aliases[i-1] = NULL;
+                       else
+                               rptr->he.h_name = NULL;
+                   }
+           }
+       for (i = 0; cp->he.h_addr_list[i]; i++)
+               ;
+       addrcount = i;
+
+       /*
+        * Do the same again for IP#'s.
+        */
+       for (s = (char *)&rptr->he.h_addr.s_addr;
+            ((struct in_addr *)s)->s_addr; s += sizeof(struct in_addr))
+           {
+               for (i = 0; (t = cp->he.h_addr_list[i]); i++)
+                       if (!bcmp(s, t, sizeof(struct in_addr)))
+                               break;
+               if (i >= MAXADDRS || addrcount >= MAXADDRS)
+                       break;
+               /*
+                * Oh man this is bad...I *HATE* it. -avalon
+                *
+                * Whats it do ?  Reallocate two arrays, one of pointers
+                * to "char *" and the other of IP addresses.  Contents of
+                * the IP array *MUST* be preserved and the pointers into
+                * it recalculated.
+                */
+               if (!t)
+                   {
+                       base = cp->he.h_addr_list;
+                       addrcount++;
+                       t = (char *)MyRealloc(*base,
+                                       addrcount * sizeof(struct in_addr));
+                       base = (char **)MyRealloc((char *)base,
+                                       (addrcount + 1) * sizeof(char *));
+                       cp->he.h_addr_list = base;
+#ifdef DEBUG
+                       Debug((DEBUG_DNS,"u_l:add IP %x hal %x ac %d",
+                               ntohl(((struct in_addr *)s)->s_addr),
+                               cp->he.h_addr_list,
+                               addrcount));
+#endif
+                       for (; addrcount; addrcount--)
+                           {
+                               *base++ = t;
+                               t += sizeof(struct in_addr);
+                           }
+                       *base = NULL;
+                       bcopy(s, *--base, sizeof(struct in_addr));
+                   }
+           }
+#endif /*_WIN32*/
+       return;
+}
+
+static aCache  *find_cache_name(name)
+char   *name;
+{
+       Reg1    aCache  *cp;
+       Reg2    char    *s;
+       Reg3    int     hashv, i;
+
+       hashv = hash_name(name);
+
+       cp = hashtable[hashv].name_list;
+#ifdef DEBUG
+       Debug((DEBUG_DNS,"find_cache_name:find %s : hashv = %d",name,hashv));
+#endif
+
+       for (; cp; cp = cp->hname_next)
+#ifndef _WIN32
+               for (i = 0, s = cp->he.h_name; s; s = cp->he.h_aliases[i++])
+#else
+               for (i = 0, s = cp->he->h_name; s; s = cp->he->h_aliases[i++])
+#endif
+                       if (mycmp(s, name) == 0)
+                           {
+                               cainfo.ca_na_hits++;
+                               update_list(NULL, cp);
+                               return cp;
+                           }
+
+       for (cp = cachetop; cp; cp = cp->list_next)
+           {
+               /*
+                * if no aliases or the hash value matches, we've already
+                * done this entry and all possiblilities concerning it.
+                */
+#ifndef _WIN32
+               if (!*cp->he.h_aliases)
+                       continue;
+               if (hashv == hash_name(cp->he.h_name))
+                       continue;
+               for (i = 0, s = cp->he.h_aliases[i]; s && i < MAXALIASES; i++)
+                       if (!mycmp(name, s)) {
+#else
+               if (!cp->he->h_aliases)
+                       continue;
+               if (hashv == hash_name(cp->he->h_name))
+                       continue;
+               for (i = 0, s = cp->he->h_aliases[i]; s && i < MAXALIASES; i++)
+                       if (!mycmp(name, s)) {
+#endif
+                               cainfo.ca_na_hits++;
+                               update_list(NULL, cp);
+                               return cp;
+                           }
+           }
+       return NULL;
+}
+
+/*
+ * find a cache entry by ip# and update its expire time
+ */
+static aCache  *find_cache_number(rptr, numb)
+ResRQ  *rptr;
+char   *numb;
+{
+       Reg1    aCache  *cp;
+       Reg2    int     hashv,i;
+#ifdef DEBUG
+       struct  in_addr *ip = (struct in_addr *)numb;
+#endif
+
+       hashv = hash_number((u_char *)numb);
+
+       cp = hashtable[hashv].num_list;
+#ifdef DEBUG
+       Debug((DEBUG_DNS,"find_cache_number:find %s[%08x]: hashv = %d",
+               inetntoa(numb), ntohl(ip->s_addr), hashv));
+#endif
+
+       for (; cp; cp = cp->hnum_next)
+#ifndef _WIN32
+               for (i = 0; cp->he.h_addr_list[i]; i++)
+                       if (!bcmp(cp->he.h_addr_list[i], numb,
+                                 sizeof(struct in_addr)))
+#else
+               for (i = 0; cp->he->h_addr_list && cp->he->h_addr_list[i]; i++)
+                       if (!bcmp(cp->he->h_addr_list[i], numb,
+                                 sizeof(struct in_addr)))
+#endif
+                           {
+                               cainfo.ca_nu_hits++;
+                               update_list(rptr, cp);
+                               return cp;
+                           }
+
+       for (cp = cachetop; cp; cp = cp->list_next)
+           {
+               /*
+                * single address entry...would have been done by hashed
+                * search above...
+                */
+#ifndef _WIN32
+               if (!cp->he.h_addr_list[1])
+#else
+               if (!cp->he->h_addr_list[1])
+#endif
+                       continue;
+               /*
+                * if the first IP# has the same hashnumber as the IP# we
+                * are looking for, its been done already.
+                */
+#ifndef _WIN32
+               if (hashv == hash_number((u_char *)cp->he.h_addr_list[0]))
+                       continue;
+               for (i = 1; cp->he.h_addr_list[i]; i++)
+                       if (!bcmp(cp->he.h_addr_list[i], numb,
+                                 sizeof(struct in_addr)))
+#else
+               if (hashv == hash_number((u_char *)cp->he->h_addr_list[0]))
+                       continue;
+               for (i = 1; cp->he->h_addr_list && cp->he->h_addr_list[i]; i++)
+                       if (!bcmp(cp->he->h_addr_list[i], numb,
+                                 sizeof(struct in_addr)))
+#endif
+                           {
+                               cainfo.ca_nu_hits++;
+                               update_list(rptr, cp);
+                               return cp;
+                           }
+           }
+       return NULL;
+}
+
+static aCache  *make_cache(rptr)
+ResRQ  *rptr;
+{
+       Reg1    aCache  *cp;
+       Reg2    int     i, n;
+       Reg3    struct  hostent *hp;
+       Reg3    char    *s, **t;
+
+       /*
+       ** shouldn't happen but it just might...
+       */
+#ifndef _WIN32
+       if (!rptr->he.h_name || !rptr->he.h_addr.s_addr)
+#else
+       if (!rptr->he->h_name || !((struct in_addr *)rptr->he->h_addr)->s_addr)
+#endif
+               return NULL;
+       /*
+       ** Make cache entry.  First check to see if the cache already exists
+       ** and if so, return a pointer to it.
+       */
+#ifndef _WIN32
+       if ((cp = find_cache_number(rptr, (char *)&rptr->he.h_addr.s_addr)))
+               return cp;
+       for (i = 1; rptr->he.h_addr_list[i].s_addr; i++)
+               if ((cp = find_cache_number(rptr,
+                               (char *)&(rptr->he.h_addr_list[i].s_addr))))
+#else
+       if ((cp = find_cache_number(rptr, (char *)&((struct in_addr *)rptr->he->h_addr)->s_addr)))
+               return cp;
+       for (i = 1; rptr->he->h_addr_list[i] &&
+            ((struct in_addr *)rptr->he->h_addr_list[i])->s_addr; i++)
+               if ((cp = find_cache_number(rptr,
+                               (char *)&((struct in_addr *)rptr->he->h_addr_list[i])->s_addr )))
+#endif
+                       return cp;
+
+       /*
+       ** a matching entry wasnt found in the cache so go and make one up.
+       */ 
+       cp = (aCache *)MyMalloc(sizeof(aCache));
+       bzero((char *)cp, sizeof(aCache));
+#ifdef _WIN32
+       cp->he = (struct hostent *)MyMalloc(MAXGETHOSTSTRUCT);
+       res_copyhostent(rptr->he, cp->he);
+#else
+       hp = &cp->he;
+       for (i = 0; i < MAXADDRS; i++)
+               if (!rptr->he.h_addr_list[i].s_addr)
+                       break;
+
+       /*
+       ** build two arrays, one for IP#'s, another of pointers to them.
+       */
+       t = hp->h_addr_list = (char **)MyMalloc(sizeof(char *) * (i+1));
+       bzero((char *)t, sizeof(char *) * (i+1));
+
+       s = (char *)MyMalloc(sizeof(struct in_addr) * i);
+       bzero(s, sizeof(struct in_addr) * i);
+
+       for (n = 0; n < i; n++, s += sizeof(struct in_addr))
+           {
+               *t++ = s;
+               bcopy((char *)&(rptr->he.h_addr_list[n].s_addr), s,
+                     sizeof(struct in_addr));
+           }
+       *t = (char *)NULL;
+
+       /*
+       ** an array of pointers to CNAMEs.
+       */
+       for (i = 0; i < MAXALIASES; i++)
+               if (!rptr->he.h_aliases[i])
+                       break;
+       i++;
+       t = hp->h_aliases = (char **)MyMalloc(sizeof(char *) * i);
+       for (n = 0; n < i; n++, t++)
+           {
+               *t = rptr->he.h_aliases[n];
+               rptr->he.h_aliases[n] = NULL;
+           }
+
+       hp->h_addrtype = rptr->he.h_addrtype;
+       hp->h_length = rptr->he.h_length;
+       hp->h_name = rptr->he.h_name;
+#endif
+       if (rptr->ttl < 600)
+           {
+               reinfo.re_shortttl++;
+               cp->ttl = 600;
+           }
+       else
+               cp->ttl = rptr->ttl;
+       cp->expireat = TStime() + cp->ttl;
+#ifndef _WIN32
+       rptr->he.h_name = NULL;
+#else
+       rptr->he->h_name = NULL;
+#endif
+#ifdef DEBUG
+       Debug((DEBUG_INFO,"make_cache:made cache %#x", cp));
+#endif
+       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.
+ */
+static void    rem_cache(ocp)
+aCache *ocp;
+{
+       Reg1    aCache  **cp;
+#ifndef _WIN32
+       Reg2    struct  hostent *hp = &ocp->he;
+#else
+       Reg2    struct  hostent *hp = ocp->he;
+#endif
+       Reg3    int     hashv;
+       Reg4    aClient *cptr;
+
+#ifdef DEBUG
+       Debug((DEBUG_DNS, "rem_cache: ocp %#x hp %#x l_n %#x aliases %#x",
+               ocp, hp, ocp->list_next, hp->h_aliases));
+#endif
+       /*
+       ** Cleanup any references to this structure by destroying the
+       ** pointer.
+       */
+       for (hashv = highest_fd; hashv >= 0; hashv--)
+               if ((cptr = local[hashv]) && (cptr->hostp == hp))
+                       cptr->hostp = NULL;
+       /*
+        * remove cache entry from linked list
+        */
+       for (cp = &cachetop; *cp; cp = &((*cp)->list_next))
+               if (*cp == ocp)
+                   {
+                       *cp = ocp->list_next;
+                       break;
+                   }
+       /*
+        * remove cache entry from hashed name lists
+        */
+       hashv = hash_name(hp->h_name);
+#ifdef DEBUG
+       Debug((DEBUG_DEBUG,"rem_cache: h_name %s hashv %d next %#x first %#x",
+               hp->h_name, hashv, ocp->hname_next,
+               hashtable[hashv].name_list));
+#endif
+       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
+        */
+       hashv = hash_number((u_char *)hp->h_addr);
+#ifdef DEBUG
+       Debug((DEBUG_DEBUG,"rem_cache: h_addr %s hashv %d next %#x first %#x",
+               inetntoa(hp->h_addr), hashv, ocp->hnum_next,
+               hashtable[hashv].num_list));
+#endif
+       for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next))
+               if (*cp == ocp)
+                   {
+                       *cp = ocp->hnum_next;
+                       break;
+                   }
+
+#ifdef _WIN32
+       MyFree((char *)hp);
+#else
+       /*
+        * free memory used to hold the various host names and the array
+        * of alias pointers.
+        */
+       if (hp->h_name)
+               MyFree(hp->h_name);
+       if (hp->h_aliases)
+           {
+               for (hashv = 0; hp->h_aliases[hashv]; hashv++)
+                       MyFree(hp->h_aliases[hashv]);
+               MyFree((char *)hp->h_aliases);
+           }
+
+       /*
+        * free memory used to hold ip numbers and the array of them.
+        */
+       if (hp->h_addr_list)
+           {
+               if (*hp->h_addr_list)
+                       MyFree((char *)*hp->h_addr_list);
+               MyFree((char *)hp->h_addr_list);
+           }
+#endif /*_WIN32*/
+       MyFree((char *)ocp);
+
+       incache--;
+       cainfo.ca_dels++;
+
+       return;
+}
+
+/*
+ * 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(now)
+time_t now;
+{
+       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);
+}
+
+/*
+ * remove all dns cache entries.
+ */
+void   flush_cache()
+{
+       Reg1    aCache  *cp;
+
+       while ((cp = cachetop))
+               rem_cache(cp);
+}
+
+int    m_dns(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    aCache  *cp;
+       Reg2    int     i;
+
+       if (parv[1] && *parv[1] == 'l') {
+               for(cp = cachetop; cp; cp = cp->list_next)
+                   {
+                       sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
+                                  parv[0], cp->expireat - TStime(), cp->ttl,
+#ifndef _WIN32
+                                  cp->he.h_name, inetntoa(cp->he.h_addr));
+                       for (i = 0; cp->he.h_aliases[i]; i++)
+                               sendto_one(sptr,"NOTICE %s : %s = %s (CN)",
+                                          parv[0], cp->he.h_name,
+                                          cp->he.h_aliases[i]);
+                       for (i = 1; cp->he.h_addr_list[i]; i++)
+                               sendto_one(sptr,"NOTICE %s : %s = %s (IP)",
+                                          parv[0], cp->he.h_name,
+                                          inetntoa(cp->he.h_addr_list[i]));
+#else
+                                  cp->he->h_name, inetntoa(cp->he->h_addr));
+                       for (i = 0; cp->he->h_aliases[i]; i++)
+                               sendto_one(sptr,"NOTICE %s : %s = %s (CN)",
+                                          parv[0], cp->he->h_name,
+                                          cp->he->h_aliases[i]);
+                       for (i = 1; cp->he->h_addr_list[i]; i++)
+                               sendto_one(sptr,"NOTICE %s : %s = %s (IP)",
+                                          parv[0], cp->he->h_name,
+                                          inetntoa(cp->he->h_addr_list[i]));
+#endif
+                   }
+               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);
+       return 0;
+}
+
+u_long cres_mem(sptr)
+aClient        *sptr;
+{
+       register aCache *c = cachetop;
+       register struct hostent *h;
+       register int    i;
+       u_long  nm = 0, im = 0, sm = 0, ts = 0;
+
+       for ( ;c ; c = c->list_next)
+           {
+               sm += sizeof(*c);
+#ifndef _WIN32
+               h = &c->he;
+#else
+               h = c->he;
+#endif
+               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);
+           }
+       ts = ARES_CACSIZE * sizeof(CacheTable);
+       sendto_one(sptr, ":%s %d %s :RES table %d",
+                  me.name, RPL_STATSDEBUG, sptr->name, ts);
+       sendto_one(sptr, ":%s %d %s :Structs %d IP storage %d Name storage %d",
+                  me.name, RPL_STATSDEBUG, sptr->name, sm, im, nm);
+       return ts + sm + im + nm;
+}
+
+#ifdef _WIN32
+/*
+ * Main thread function for handling DNS requests.
+ */
+void   async_dns(void *parm)
+{
+       ResRQ   *rptr = (ResRQ *)parm;
+       struct hostent  *hp, *he = rptr->he;
+       int     i, x;
+       long    amt;
+
+       if (rptr->type == T_A)
+           {
+               rptr->locked = 2;
+               hp = gethostbyname(rptr->name);
+           }
+       else
+           {
+               rptr->locked = 1;
+               hp = gethostbyaddr((char *)(&rptr->addr.s_addr), 4, PF_INET);
+           }
+       if ( !hp )
+           {
+               /*
+                * Now heres a stupid check to forget, this apprently is
+                * what hasbeen causing most of the crashes.  I hope anyway.
+                */
+               do_dns_async(rptr->id);
+               _endthread();
+           }
+       if ( (hp->h_aliases[0] && (hp->h_aliases[0]-(char *)hp)>MAXGETHOSTSTRUCT) ||
+            (hp->h_addr_list[0] && (hp->h_addr_list[0]-(char *)hp)>MAXGETHOSTSTRUCT))
+           {
+               /*
+                * Seems windows does some weird, aka stupid, stuff with DNS.
+                * If the address is resolved from the HOSTS file, then the
+                * pointers will exceed MAXGETHOSTSTRUCT. Good and bad. Good
+                * because its an easy way to tell if the Admin is spoofing
+                * with his HOSTS file, bad because it also causes invalid
+                * pointers without this check. -Cabal95
+                */
+               do_dns_async(rptr->id);
+               _endthread();
+           }
+
+       res_copyhostent(hp, rptr->he);
+       do_dns_async(rptr->id);
+       _endthread();
+}
+
+int    res_copyhostent(struct hostent *from, struct hostent *to)
+{
+       int     amt, x, i;
+
+       to->h_addrtype = from->h_addrtype;
+       to->h_length = from->h_length;
+       /*
+        * Get to "primary" offset in to hostent buffer and copy over
+        * to hostname.
+        */
+       amt = (long)to + sizeof(struct hostent);
+       to->h_name = (char *)amt;
+       strcpy(to->h_name, from->h_name);
+       amt += strlen(to->h_name)+1;
+       /* Setup tto alias list */
+       if (amt&0x3)
+               amt = (amt&0xFFFFFFFC)+4;       
+       to->h_aliases = (char **)amt;
+       for (x = 0; from->h_aliases[x]; x++)
+               ;
+       x *= sizeof(char *);
+       amt += sizeof(char *);
+       for (i = 0; from->h_aliases[i]; i++)
+           {
+               to->h_aliases[i] = (char *)(amt+x);
+               strcpy(to->h_aliases[i], from->h_aliases[i]);
+               amt += strlen(to->h_aliases[i])+1;
+               if (amt&0x3)
+                       amt = (amt&0xFFFFFFFC)+4;       
+           }
+       to->h_aliases[i] = NULL;
+       /* Setup tto IP address list */
+       to->h_addr_list = (char **)amt;
+       for (x = 0; from->h_addr_list[x]; x++)
+               ;
+       x *= sizeof(char *);
+       for (i = 0; from->h_addr_list[i]; i++)
+           {
+               amt += 4;
+               to->h_addr_list[i] = (char *)(amt+x);
+               ((struct in_addr *)to->h_addr_list[i])->s_addr = ((struct in_addr *)from->h_addr_list[i])->s_addr;
+           }
+       to->h_addr_list[i] = NULL;
+}
+#endif /*_WIN32*/
diff --git a/src/res_comp.c b/src/res_comp.c
new file mode 100644 (file)
index 0000000..7a1ba42
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_comp.c 6.18 (Berkeley) 6/27/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "common.h"
+#include "sys.h"
+#include "nameser.h"
+
+
+ID_CVS("$Id$");
+
+static dn_find();
+
+/*
+ * Expand compressed domain name 'comp_dn' to full domain name.
+ * 'msg' is a pointer to the begining of the message,
+ * 'eomorig' points to the first location after the message,
+ * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
+ * Return size of compressed name or -1 if there was an error.
+ */
+dn_expand(msg, eomorig, comp_dn, exp_dn, length)
+       u_char *msg, *eomorig, *comp_dn, *exp_dn;
+       int length;
+{
+       register u_char *cp, *dn;
+       register int n, c;
+       u_char *eom;
+       int len = -1, checked = 0;
+
+       dn = exp_dn;
+       cp = comp_dn;
+       eom = exp_dn + length;
+       /*
+        * fetch next label in domain name
+        */
+       while (n = *cp++) {
+               /*
+                * Check for indirection
+                */
+               switch (n & INDIR_MASK) {
+               case 0:
+                       if (dn != exp_dn) {
+                               if (dn >= eom)
+                                       return (-1);
+                               *dn++ = '.';
+                       }
+                       if (dn+n >= eom)
+                               return (-1);
+                       checked += n + 1;
+                       while (--n >= 0) {
+                               if ((c = *cp++) == '.') {
+                                       if (dn + n + 2 >= eom)
+                                               return (-1);
+                                       *dn++ = '\\';
+                               }
+                               *dn++ = c;
+                               if (cp >= eomorig)      /* out of range */
+                                       return(-1);
+                       }
+                       break;
+
+               case INDIR_MASK:
+                       if (len < 0)
+                               len = cp - comp_dn + 1;
+                       cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
+                       if (cp < msg || cp >= eomorig)  /* out of range */
+                               return(-1);
+                       checked += 2;
+                       /*
+                        * Check for loops in the compressed name;
+                        * if we've looked at the whole message,
+                        * there must be a loop.
+                        */
+                       if (checked >= eomorig - msg)
+                               return (-1);
+                       break;
+
+               default:
+                       return (-1);                    /* flag error */
+               }
+       }
+       *dn = '\0';
+       if (len < 0)
+               len = cp - comp_dn;
+       return (len);
+}
+
+/*
+ * Compress domain name 'exp_dn' into 'comp_dn'.
+ * Return the size of the compressed name or -1.
+ * 'length' is the size of the array pointed to by 'comp_dn'.
+ * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
+ * is a pointer to the beginning of the message. The list ends with NULL.
+ * 'lastdnptr' is a pointer to the end of the arrary pointed to
+ * by 'dnptrs'. Side effect is to update the list of pointers for
+ * labels inserted into the message as we compress the name.
+ * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
+ * is NULL, we don't update the list.
+ */
+dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
+       u_char *exp_dn, *comp_dn;
+       int length;
+       u_char **dnptrs, **lastdnptr;
+{
+       register u_char *cp, *dn;
+       register int c, l;
+       u_char **cpp, **lpp, *sp, *eob;
+       u_char *msg;
+
+       dn = exp_dn;
+       cp = comp_dn;
+       eob = cp + length;
+       if (dnptrs != NULL) {
+               if ((msg = *dnptrs++) != NULL) {
+                       for (cpp = dnptrs; *cpp != NULL; cpp++)
+                               ;
+                       lpp = cpp;      /* end of list to search */
+               }
+       } else
+               msg = NULL;
+       for (c = *dn++; c != '\0'; ) {
+               /* look to see if we can use pointers */
+               if (msg != NULL) {
+                       if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
+                               if (cp+1 >= eob)
+                                       return (-1);
+                               *cp++ = (l >> 8) | INDIR_MASK;
+                               *cp++ = l % 256;
+                               return (cp - comp_dn);
+                       }
+                       /* not found, save it */
+                       if (lastdnptr != NULL && cpp < lastdnptr-1) {
+                               *cpp++ = cp;
+                               *cpp = NULL;
+                       }
+               }
+               sp = cp++;      /* save ptr to length byte */
+               do {
+                       if (c == '.') {
+                               c = *dn++;
+                               break;
+                       }
+                       if (c == '\\') {
+                               if ((c = *dn++) == '\0')
+                                       break;
+                       }
+                       if (cp >= eob) {
+                               if (msg != NULL)
+                                       *lpp = NULL;
+                               return (-1);
+                       }
+                       *cp++ = c;
+               } while ((c = *dn++) != '\0');
+               /* catch trailing '.'s but not '..' */
+               if ((l = cp - sp - 1) == 0 && c == '\0') {
+                       cp--;
+                       break;
+               }
+               if (l <= 0 || l > MAXLABEL) {
+                       if (msg != NULL)
+                               *lpp = NULL;
+                       return (-1);
+               }
+               *sp = l;
+       }
+       if (cp >= eob) {
+               if (msg != NULL)
+                       *lpp = NULL;
+               return (-1);
+       }
+       *cp++ = '\0';
+       return (cp - comp_dn);
+}
+
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+dn_skipname(comp_dn, eom)
+       u_char *comp_dn, *eom;
+{
+       register u_char *cp;
+       register int n;
+
+       cp = comp_dn;
+       while (cp < eom && (n = *cp++)) {
+               /*
+                * check for indirection
+                */
+               switch (n & INDIR_MASK) {
+               case 0:         /* normal case, n == len */
+                       cp += n;
+                       continue;
+               default:        /* illegal type */
+                       return (-1);
+               case INDIR_MASK:        /* indirection */
+                       cp++;
+               }
+               break;
+       }
+       return (cp - comp_dn);
+}
+
+/*
+ * Search for expanded name from a list of previously compressed names.
+ * Return the offset from msg if found or -1.
+ * dnptrs is the pointer to the first name on the list,
+ * not the pointer to the start of the message.
+ */
+static
+dn_find(exp_dn, msg, dnptrs, lastdnptr)
+       u_char *exp_dn, *msg;
+       u_char **dnptrs, **lastdnptr;
+{
+       register u_char *dn, *cp, **cpp;
+       register int n;
+       u_char *sp;
+
+       for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
+               dn = exp_dn;
+               sp = cp = *cpp;
+               while (n = *cp++) {
+                       /*
+                        * check for indirection
+                        */
+                       switch (n & INDIR_MASK) {
+                       case 0:         /* normal case, n == len */
+                               while (--n >= 0) {
+                                       if (*dn == '.')
+                                               goto next;
+                                       if (*dn == '\\')
+                                               dn++;
+                                       if (*dn++ != *cp++)
+                                               goto next;
+                               }
+                               if ((n = *dn++) == '\0' && *cp == '\0')
+                                       return (sp - msg);
+                               if (n == '.')
+                                       continue;
+                               goto next;
+
+                       default:        /* illegal type */
+                               return (-1);
+
+                       case INDIR_MASK:        /* indirection */
+                               cp = msg + (((n & 0x3f) << 8) | *cp);
+                       }
+               }
+               if (*dn == '\0')
+                       return (sp - msg);
+       next:   ;
+       }
+       return (-1);
+}
+
+/*
+ * Routines to insert/extract short/long's. Must account for byte
+ * order and non-alignment problems. This code at least has the
+ * advantage of being portable.
+ *
+ * used by sendmail.
+ */
+
+u_short
+_getshort(msgp)
+       u_char *msgp;
+{
+       register u_char *p = (u_char *) msgp;
+#ifdef vax
+       /*
+        * vax compiler doesn't put shorts in registers
+        */
+       register u_long u;
+#else
+       register u_short u;
+#endif
+
+       u = *p++ << 8;
+       return ((u_short)(u | *p));
+}
+
+u_long
+_getlong(msgp)
+       u_char *msgp;
+{
+       register u_char *p = (u_char *) msgp;
+       register u_long u;
+
+       u = *p++; u <<= 8;
+       u |= *p++; u <<= 8;
+       u |= *p++; u <<= 8;
+       return (u | *p);
+}
+
+
+putshort(s, msgp)
+       register u_short s;
+       register u_char *msgp;
+{
+
+       msgp[1] = s;
+       msgp[0] = s >> 8;
+}
+
+putlong(l, msgp)
+       register u_long l;
+       register u_char *msgp;
+{
+
+       msgp[3] = l;
+       msgp[2] = (l >>= 8);
+       msgp[1] = (l >>= 8);
+       msgp[0] = l >> 8;
+}
diff --git a/src/res_init.c b/src/res_init.c
new file mode 100644 (file)
index 0000000..4612154
--- /dev/null
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 1985, 1989 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_init.c 6.14.1 (Berkeley) 6/27/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif
+#include <stdio.h>
+#include "config.h"    /* To get #define SOL20         Vesa */
+#include "sys.h"
+#include "common.h"
+#include "nameser.h"
+#include "resolv.h"
+
+ID_CVS("$Id$");
+/*
+ * Resolver state default settings
+ */
+
+struct state _res = {
+       RES_TIMEOUT,                    /* retransmition time interval */
+       4,                              /* number of times to retransmit */
+       RES_DEFAULT,                    /* options flags */
+       1,                              /* number of name servers */
+};
+
+/*
+ * Set up default settings.  If the configuration file exist, the values
+ * there will have precedence.  Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * The configuration file should only be used if you want to redefine your
+ * domain or run without a server on your machine.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+res_init()
+{
+#ifndef _WIN32
+       register FILE *fp;
+       register char *cp, *dp, **pp;
+       extern u_long inet_addr();
+#else
+       register char *cp, **pp;
+#endif
+       register int n;
+       char buf[BUFSIZ];
+       extern char *getenv();
+       int nserv = 0;    /* number of nameserver records read from file */
+       int norder = 0;
+       int haveenv = 0;
+       int havesearch = 0;
+
+       _res.nsaddr.sin_addr.s_addr = INADDR_ANY;
+       _res.nsaddr.sin_family = AF_INET;
+#ifdef TESTNET
+       _res.nsaddr.sin_port = htons(NAMESERVER_PORT + 10000);
+#else
+       _res.nsaddr.sin_port = htons(NAMESERVER_PORT);
+#endif
+       _res.nscount = 1;
+
+       /* Allow user to override the local domain definition */
+       if ((cp = getenv("LOCALDOMAIN")) != NULL) {
+               (void)strncpy(_res.defdname, cp, sizeof(_res.defdname));
+               haveenv++;
+       }
+
+#ifndef _WIN32
+       if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
+           /* read the config file */
+           while (fgets(buf, sizeof(buf), fp) != NULL) {
+               /* read default domain name */
+               if (!strncmp(buf, "domain", sizeof("domain") - 1)) {
+                   if (haveenv)        /* skip if have from environ */
+                           continue;
+                   cp = buf + sizeof("domain") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+                   if ((cp = index(_res.defdname, '\n')) != NULL)
+                           *cp = '\0';
+                   havesearch = 0;
+                   continue;
+               }
+               /* set search list */
+               if (!strncmp(buf, "search", sizeof("search") - 1)) {
+                   if (haveenv)        /* skip if have from environ */
+                           continue;
+                   cp = buf + sizeof("search") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
+                   if ((cp = index(_res.defdname, '\n')) != NULL)
+                           *cp = '\0';
+                   /*
+                    * Set search list to be blank-separated strings
+                    * on rest of line.
+                    */
+                   cp = _res.defdname;
+                   pp = _res.dnsrch;
+                   *pp++ = cp;
+                   for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
+                           if (*cp == ' ' || *cp == '\t') {
+                                   *cp = 0;
+                                   n = 1;
+                           } else if (n) {
+                                   *pp++ = cp;
+                                   n = 0;
+                           }
+                   }
+                   /* null terminate last domain if there are excess */
+                   while (*cp != '\0' && *cp != ' ' && *cp != '\t')
+                           cp++;
+                   *cp = '\0';
+                   *pp++ = 0;
+                   havesearch = 1;
+                   continue;
+               }
+               /* read nameservers to query */
+               if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) &&
+                  nserv < MAXNS) {
+                   cp = buf + sizeof("nameserver") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                           cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                           continue;
+                   if ((_res.nsaddr_list[nserv].sin_addr.s_addr =
+                       inet_addr(cp)) == (unsigned)-1) {
+                           _res.nsaddr_list[nserv].sin_addr.s_addr
+                               = INADDR_ANY;
+                           continue;
+                   }
+                   _res.nsaddr_list[nserv].sin_family = AF_INET;
+#ifdef TESTNET
+                   _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT +
+                       10000);
+#else
+                   _res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT);
+#endif
+                   nserv++;
+                   continue;
+               }
+               /* read service order */
+               if (!strncmp(buf, "order", sizeof("order") - 1)) {
+                       cp = buf + sizeof("order") - 1;
+                   while (*cp == ' ' || *cp == '\t')
+                       cp++;
+                   if ((*cp == '\0') || (*cp == '\n'))
+                       continue;
+                   norder = 0;
+                   do {
+                       if ((dp = index(cp, ',')) != NULL)
+                           *dp = '\0';
+                       if (norder >= MAXSERVICES)
+                           continue;
+                       if (!strncmp(cp, "bind", sizeof("bind") - 1))
+                           _res.order[norder++] = RES_SERVICE_BIND;
+                       else if (!strncmp(cp, "local", sizeof("local") - 1))
+                           _res.order[norder++] = RES_SERVICE_LOCAL;
+                       cp = dp + 1;
+                   } while (dp != NULL);
+                   _res.order[norder] = RES_SERVICE_NONE;
+                   continue;
+               }
+           }
+           if (nserv > 1) 
+               _res.nscount = nserv;
+           (void) fclose(fp);
+       }
+#endif /*_WIN32*/
+       if (_res.defdname[0] == 0) {
+               if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
+                  (cp = index(buf, '.')))
+                       (void)strcpy(_res.defdname, cp + 1);
+       }
+
+       /* find components of local domain that might be searched */
+       if (havesearch == 0) {
+               pp = _res.dnsrch;
+               *pp++ = _res.defdname;
+               for (cp = _res.defdname, n = 0; *cp; cp++)
+                       if (*cp == '.')
+                               n++;
+               cp = _res.defdname;
+               for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH;
+                   n--) {
+                       cp = index(cp, '.');
+                       *pp++ = ++cp;
+               }
+               *pp++ = 0;
+       }
+       /* default search order to bind only */
+       if (norder == 0) {
+               _res.order[0] = RES_SERVICE_BIND;
+               _res.order[1] = RES_SERVICE_NONE;
+       }
+       _res.options |= RES_INIT;
+       return (0);
+}
diff --git a/src/res_mkquery.c b/src/res_mkquery.c
new file mode 100644 (file)
index 0000000..9d9e314
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)res_mkquery.c      6.12 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "sys.h"
+#include "nameser.h"
+#include "resolv.h"
+#include "common.h"
+
+ID_CVS("$Id$");
+
+/*
+ * Form all types of queries.
+ * Returns the size of the result or -1.
+ */
+res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)
+       int op;                 /* opcode of query */
+       char *dname;            /* domain name */
+       int class, type;        /* class and type of query */
+       char *data;             /* resource record data */
+       int datalen;            /* length of data */
+       struct rrec *newrr;     /* new rr for modify or append */
+       char *buf;              /* buffer to put query */
+       int buflen;             /* size of buffer */
+{
+       register HEADER *hp;
+       register char *cp;
+       register int n;
+       char *dnptrs[10], **dpp, **lastdnptr;
+
+#ifdef DEBUG
+       if (_res.options & RES_DEBUG)
+               printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
+#endif /*DEBUG*/
+       /*
+        * Initialize header fields.
+        */
+       if ((buf == NULL) || (buflen < sizeof(HEADER)))
+               return(-1);
+       bzero(buf, sizeof(HEADER));
+       hp = (HEADER *) buf;
+       hp->id = htons(++_res.id);
+       hp->opcode = op;
+       hp->pr = (_res.options & RES_PRIMARY) != 0;
+       hp->rd = (_res.options & RES_RECURSE) != 0;
+       hp->rcode = NOERROR;
+       cp = buf + sizeof(HEADER);
+       buflen -= sizeof(HEADER);
+       dpp = dnptrs;
+       *dpp++ = buf;
+       *dpp++ = NULL;
+       lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
+       /*
+        * perform opcode specific processing
+        */
+       switch (op) {
+       case QUERY:
+               if ((buflen -= QFIXEDSZ) < 0)
+                       return(-1);
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               buflen -= n;
+               putshort(type, cp);
+               cp += sizeof(u_short);
+               putshort(class, cp);
+               cp += sizeof(u_short);
+               hp->qdcount = htons(1);
+               if (op == QUERY || data == NULL)
+                       break;
+               /*
+                * Make an additional record for completion domain.
+                */
+               buflen -= RRFIXEDSZ;
+               if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               buflen -= n;
+               putshort(T_NULL, cp);
+               cp += sizeof(u_short);
+               putshort(class, cp);
+               cp += sizeof(u_short);
+               putlong(0, cp);
+               cp += sizeof(u_long);
+               putshort(0, cp);
+               cp += sizeof(u_short);
+               hp->arcount = htons(1);
+               break;
+
+       case IQUERY:
+               /*
+                * Initialize answer section
+                */
+               if (buflen < 1 + RRFIXEDSZ + datalen)
+                       return (-1);
+               *cp++ = '\0';   /* no domain name */
+               putshort(type, cp);
+               cp += sizeof(u_short);
+               putshort(class, cp);
+               cp += sizeof(u_short);
+               putlong(0, cp);
+               cp += sizeof(u_long);
+               putshort(datalen, cp);
+               cp += sizeof(u_short);
+               if (datalen) {
+                       bcopy(data, cp, datalen);
+                       cp += datalen;
+               }
+               hp->ancount = htons(1);
+               break;
+
+#ifdef ALLOW_UPDATES
+       /*
+        * For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
+        * (Record to be modified is followed by its replacement in msg.)
+        */
+       case UPDATEM:
+       case UPDATEMA:
+
+       case UPDATED:
+               /*
+                * The res code for UPDATED and UPDATEDA is the same; user
+                * calls them differently: specifies data for UPDATED; server
+                * ignores data if specified for UPDATEDA.
+                */
+       case UPDATEDA:
+               buflen -= RRFIXEDSZ + datalen;
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               putshort(type, cp);
+                cp += sizeof(u_short);
+                putshort(class, cp);
+                cp += sizeof(u_short);
+               putlong(0, cp);
+               cp += sizeof(u_long);
+               putshort(datalen, cp);
+                cp += sizeof(u_short);
+               if (datalen) {
+                       bcopy(data, cp, datalen);
+                       cp += datalen;
+               }
+               if ( (op == UPDATED) || (op == UPDATEDA) ) {
+                       hp->ancount = htons(0);
+                       break;
+               }
+               /* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
+
+       case UPDATEA:   /* Add new resource record */
+               buflen -= RRFIXEDSZ + datalen;
+               if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
+                       return (-1);
+               cp += n;
+               putshort(newrr->r_type, cp);
+                cp += sizeof(u_short);
+                putshort(newrr->r_class, cp);
+                cp += sizeof(u_short);
+               putlong(0, cp);
+               cp += sizeof(u_long);
+               putshort(newrr->r_size, cp);
+                cp += sizeof(u_short);
+               if (newrr->r_size) {
+                       bcopy(newrr->r_data, cp, newrr->r_size);
+                       cp += newrr->r_size;
+               }
+               hp->ancount = htons(0);
+               break;
+
+#endif /* ALLOW_UPDATES */
+       }
+       return (cp - buf);
+}
diff --git a/src/res_skipname.c b/src/res_skipname.c
new file mode 100644 (file)
index 0000000..818e7b4
--- /dev/null
@@ -0,0 +1,34 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include "nameser.h"
+#include "common.h"
+
+ID_CVS("$Id$");
+/*
+ * Skip over a compressed domain name. Return the size or -1.
+ */
+dn_skipname(comp_dn, eom)
+       u_char *comp_dn, *eom;
+{
+       register u_char *cp;
+       register int n;
+
+       cp = comp_dn;
+       while (cp < eom && (n = *cp++)) {
+               /*
+                * check for indirection
+                */
+               switch (n & INDIR_MASK) {
+               case 0:         /* normal case, n == len */
+                       cp += n;
+                       continue;
+               default:        /* illegal type */
+                       return (-1);
+               case INDIR_MASK:        /* indirection */
+                       cp++;
+               }
+               break;
+       }
+       return (cp - comp_dn);
+}
+
diff --git a/src/s_auth.c b/src/s_auth.c
new file mode 100644 (file)
index 0000000..74d379f
--- /dev/null
@@ -0,0 +1,308 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/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.
+ *
+ *   You 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 lint
+static  char sccsid[] = "@(#)s_auth.c  1.18 4/18/94 (C) 1992 Darren Reed";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "version.h"
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if defined(__hpux)
+# include "inet.h"
+#endif
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "sock.h"      /* If FD_ZERO isn't define up to this point,  */
+                       /* define it (BSD4.2 needs this) */
+#include "h.h"
+
+ID_CVS("$Id$");
+/*
+ * 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".
+ */
+void   start_auth(cptr)
+Reg1   aClient *cptr;
+{
+       struct  sockaddr_in     sock;
+       int     addrlen = sizeof(struct sockaddr_in);
+
+       Debug((DEBUG_NOTICE,"start_auth(%x) fd %d status %d",
+               cptr, cptr->fd, cptr->status));
+       if ((cptr->authfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+           {
+#ifdef USE_SYSLOG
+               syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
+                       get_client_name(cptr,TRUE));
+#endif
+                Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
+                        get_client_name(cptr, TRUE),
+                        strerror(get_sockerr(cptr))));
+               if (!DoingDNS(cptr))
+                       SetAccess(cptr);
+               ircstp->is_abad++;
+               return;
+           }
+#ifndef _WIN32
+       if (cptr->authfd >= (MAXCONNECTIONS - 3))
+           {
+               sendto_ops("Can't allocate fd for auth on %s",
+                          get_client_name(cptr, TRUE));
+               (void)close(cptr->authfd);
+               return;
+           }
+#endif
+
+        
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+      write(cptr->fd, REPORT_DO_ID, R_do_id);
+#else
+      send(cptr->fd, REPORT_DO_ID, R_do_id,0);
+#endif
+#endif
+
+       set_non_blocking(cptr->authfd, cptr);
+
+       getsockname(cptr->fd, (struct sockaddr *)&sock, &addrlen);
+       sock.sin_port = 0;
+       sock.sin_family = AF_INET; /* redundant? */
+       (void)bind(cptr->authfd, (struct sockaddr *)&sock, sizeof(sock));
+
+       bcopy((char *)&cptr->ip, (char *)&sock.sin_addr,
+               sizeof(struct in_addr));
+
+       sock.sin_port = htons(113);
+       sock.sin_family = AF_INET;
+
+       if (connect(cptr->authfd, (struct sockaddr *)&sock,
+#ifndef _WIN32
+                   sizeof(sock)) == -1 && errno != EINPROGRESS)
+#else
+                   sizeof(sock)) == -1 && (WSAGetLastError() !=
+               WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK))
+#endif
+           {
+               ircstp->is_abad++;
+               /*
+                * No error report from this...
+                */
+#ifndef _WIN32
+               (void)close(cptr->authfd);
+#else
+               (void)closesocket(cptr->authfd);
+#endif
+               cptr->authfd = -1;
+               if (!DoingDNS(cptr))
+                       SetAccess(cptr);
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+               write(cptr->fd, REPORT_FAIL_ID, R_fail_id);
+#else
+               send(cptr->fd, REPORT_FAIL_ID, R_fail_id, 0);
+#endif
+#endif
+               return;
+           }
+       cptr->flags |= (FLAGS_WRAUTH|FLAGS_AUTH);
+       if (cptr->authfd > highest_fd)
+               highest_fd = cptr->authfd;
+       return;
+}
+
+/*
+ * send_authports
+ *
+ * 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(cptr)
+aClient        *cptr;
+{
+       struct  sockaddr_in     us, them;
+       char    authbuf[32];
+       int     ulen, tlen;
+
+       Debug((DEBUG_NOTICE,"write_authports(%x) 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, TRUE));
+#endif
+               goto authsenderr;
+           }
+
+       (void)sprintf(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((char *)&them.sin_addr)));
+#ifndef _WIN32
+       if (write(cptr->authfd, authbuf, strlen(authbuf)) != strlen(authbuf))
+#else
+       if (send(cptr->authfd, authbuf, strlen(authbuf), 0) != (int)strlen(authbuf))
+#endif
+           {
+authsenderr:
+               ircstp->is_abad++;
+#ifndef _WIN32
+               (void)close(cptr->authfd);
+#else
+               (void)closesocket(cptr->authfd);
+#endif
+               if (cptr->authfd == highest_fd)
+                       while (!local[highest_fd])
+                               highest_fd--;
+               cptr->authfd = -1;
+               cptr->flags &= ~FLAGS_AUTH;
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+               write(cptr->fd, REPORT_FAIL_ID, R_fail_id);
+#else
+               send(cptr->fd, REPORT_FAIL_ID, R_fail_id, 0);
+#endif
+#endif
+               if (!DoingDNS(cptr))
+                       SetAccess(cptr);
+           }
+       cptr->flags &= ~FLAGS_WRAUTH;
+       return;
+}
+
+/*
+ * 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.
+ */
+void   read_authports(cptr)
+Reg1   aClient *cptr;
+{
+       Reg1    char    *s, *t;
+       Reg2    int     len;
+       char    ruser[USERLEN+1], system[8];
+       u_short remp = 0, locp = 0;
+
+       *system = *ruser = '\0';
+       Debug((DEBUG_NOTICE,"read_authports(%x) fd %d authfd %d stat %d",
+               cptr, cptr->fd, cptr->authfd, cptr->status));
+       /*
+        * 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
+        */
+#ifndef _WIN32
+       if ((len = read(cptr->authfd, cptr->buffer + cptr->count,
+                       sizeof(cptr->buffer) - 1 - cptr->count)) >= 0)
+#else
+       if ((len = recv(cptr->authfd, cptr->buffer + cptr->count,
+                       sizeof(cptr->buffer) - 1 - cptr->count, 0)) >= 0)
+#endif
+           {
+               cptr->count += len;
+               cptr->buffer[cptr->count] = '\0';
+           }
+
+       cptr->lasttime = TStime();
+       if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) &&
+           (sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %10s",
+                   &remp, &locp, ruser) == 3))
+           {
+               s = rindex(cptr->buffer, ':');
+               *s++ = '\0';
+               for (t = (rindex(cptr->buffer, ':') + 1); *t; t++)
+                       if (!isspace(*t))
+                               break;
+               strncpyzt(system, t, sizeof(system));
+                for (t = ruser; *s && *s != '@' && (t < ruser + sizeof(ruser)); s++)
+                       if (!isspace(*s) && *s != ':')
+                               *t++ = *s;
+               *t = '\0';
+               Debug((DEBUG_INFO,"auth reply ok [%s] [%s]", system, ruser));
+           }
+       else if (len != 0)
+           {
+               if (!index(cptr->buffer, '\n') && !index(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';
+           }
+#ifndef _WIN32
+       (void)close(cptr->authfd);
+#else
+       (void)closesocket(cptr->authfd);
+#endif
+       if (cptr->authfd == highest_fd)
+               while (!local[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));
+
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+       write(cptr->fd, REPORT_FIN_ID, R_fin_id);
+#else
+       send(cptr->fd, REPORT_FIN_ID, R_fin_id, 0);
+#endif
+#endif
+
+       if (!locp || !remp || !*ruser)
+           {
+               ircstp->is_abad++;
+               return;
+           }
+       ircstp->is_asuc++;
+       strncpyzt(cptr->username, ruser, USERLEN+1);
+/*     if (strncmp(system, "OTHER", 5))
+*/             cptr->flags |= FLAGS_GOTID;
+       Debug((DEBUG_INFO, "got username [%s]", ruser));
+       return;
+}
diff --git a/src/s_bsd.c b/src/s_bsd.c
new file mode 100644 (file)
index 0000000..6eb28bc
--- /dev/null
@@ -0,0 +1,2657 @@
+/*
+ *   IRC - Internet Relay Chat, ircd/s_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.
+ */
+
+/* -- Jto -- 07 Jul 1990
+ * Added jlp@hamblin.byu.edu's debugtty fix
+ */
+
+/* -- Armin -- Jun 18 1990
+ * Added setdtablesize() for more socket connections
+ * (sequent OS Dynix only) -- maybe select()-call must be changed ...
+ */
+
+/* -- Jto -- 13 May 1990
+ * Added several fixes from msa:
+ *   Better error messages
+ *   Changes in check_access
+ * Added SO_REUSEADDR fix from zessel@informatik.uni-kl.de
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_bsd.c   2.78 2/7/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "version.h"
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <utmp.h>
+#include <sys/resource.h>
+#else
+#include <io.h>
+#endif
+#if defined(SOL20)
+#include <sys/filio.h>
+#endif
+#include "inet.h"
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#ifdef AIX
+# include <time.h>
+# include <arpa/nameser.h>
+#else
+# include "nameser.h"
+#endif
+#include "resolv.h"
+#include "sock.h"      /* If FD_ZERO isn't define up to this point,  */
+                       /* define it (BSD4.2 needs this) */
+#include "h.h"
+#ifndef NO_FDLIST
+#include  "fdlist.h"
+#endif
+
+ID_CVS("$Id$");
+
+#ifndef IN_LOOPBACKNET
+#define IN_LOOPBACKNET 0x7f
+#endif
+
+#ifdef _WIN32
+extern HWND    hwIRCDWnd;
+#endif
+aClient        *local[MAXCONNECTIONS];
+int    highest_fd = 0, readcalls = 0, udpfd = -1, resfd = -1;
+static struct  sockaddr_in     mysk;
+static void    polludp();
+
+static struct  sockaddr *connect_inet PROTO((aConfItem *, aClient *, int *));
+static int     completed_connection PROTO((aClient *));
+static int     check_init PROTO((aClient *, char *));
+#ifndef _WIN32
+static void    do_dns_async PROTO(()), set_sock_opts PROTO((int, aClient *));
+#else
+static void    set_sock_opts PROTO((int, aClient *));
+#endif
+static char    readbuf[8192];
+char zlinebuf[BUFSIZE];
+extern char *version;
+
+#ifndef NO_FDLIST
+extern  fdlist default_fdlist;
+extern  fdlist busycli_fdlist;
+extern  fdlist serv_fdlist;
+extern  fdlist oper_fdlist;
+extern  fdlist socks_fdlist;
+#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
+
+/*
+** add_local_domain()
+** Add the domain to hostname, if it is missing
+** (as suggested by eps@TOASTER.SFSU.EDU)
+*/
+
+void   add_local_domain(hname, size)
+char   *hname;
+int    size;
+{
+#ifdef RES_INIT
+       /* try to fix up unqualified names */
+       if (!index(hname, '.'))
+           {
+               if (!(_res.options & RES_INIT))
+                   {
+                       Debug((DEBUG_DNS,"res_init()"));
+                       res_init();
+                   }
+               if (_res.defdname[0])
+                   {
+                       (void)strncat(hname, ".", size-1);
+                       (void)strncat(hname, _res.defdname, size-2);
+                   }
+           }
+#endif
+       return;
+}
+
+/*
+** Cannot use perror() within daemon. stderr is closed in
+** ircd and cannot be used. And, worse yet, it might have
+** been reassigned to a normal connection...
+*/
+
+/*
+** report_error
+**     This a replacement for perror(). Record error to log and
+**     also send a copy to all *LOCAL* opers online.
+**
+**     text    is a *format* string for outputting error. It must
+**             contain only two '%s', the first will be replaced
+**             by the sockhost from the cptr, and the latter will
+**             be taken from sys_errlist[errno].
+**
+**     cptr    if not NULL, is the *LOCAL* client associated with
+**             the error.
+*/
+void   report_error(text, cptr)
+char   *text;
+aClient *cptr;
+{
+#ifndef _WIN32
+       Reg1    int     errtmp = errno; /* debug may change 'errno' */
+#else
+       Reg1    int     errtmp = WSAGetLastError(); /* debug may change 'errno' */
+#endif
+       Reg2    char    *host;
+       int     err, len = sizeof(err);
+
+       host = (cptr) ? get_client_name(cptr, FALSE) : "";
+
+       fprintf(stderr, text, host, strerror(errtmp));
+       fputc('\n',stderr);
+       Debug((DEBUG_ERROR, text, host, strerror(errtmp)));
+
+       /*
+        * 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.
+        */
+#ifdef SO_ERROR
+       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
+       return;
+}
+
+/*
+ * 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.
+ */
+int    inetport(cptr, name, port)
+aClient        *cptr;
+char   *name;
+int    port;
+{
+       static  struct sockaddr_in server;
+       int     ad[4], len = sizeof(server);
+       char    ipname[20];
+
+       if (BadPtr(name))
+               name = "*";
+       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 :-)
+        */
+       (void)sscanf(name, "%d.%d.%d.%d", &ad[0], &ad[1], &ad[2], &ad[3]);
+       (void)sprintf(ipname, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]);
+
+       if (cptr != &me)
+           {
+               (void)sprintf(cptr->sockhost, "%-.42s.%.u",
+                       name, (unsigned int)port);
+               (void)strcpy(cptr->name, me.name);
+           }
+       /*
+        * At first, open a new socket
+        */
+       if (cptr->fd == -1)
+               cptr->fd = socket(AF_INET, SOCK_STREAM, 0);
+
+       if (cptr->fd < 0)
+           {
+//             fprintf(
+#if !defined(DEBUGMODE) && !defined(_WIN32)
+#endif
+               report_error("opening stream socket %s:%s", cptr);
+               return -1;
+           }
+       else if (cptr->fd >= MAXCLIENTS)
+           {
+               sendto_ops("No more connections allowed (%s)", cptr->name);
+#ifndef _WIN32
+               (void)close(cptr->fd);
+#else
+               (void)closesocket(cptr->fd);
+#endif
+               return -1;
+           }
+       set_sock_opts(cptr->fd, cptr);
+       /*
+        * 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.
+        */
+       if (port)
+           {
+               server.sin_family = AF_INET;
+               /* per-port bindings, fixes /stats l */
+               server.sin_addr.s_addr = inet_addr(ipname);
+#ifdef TESTNET
+               server.sin_port = htons(port + 10000);
+#else
+               server.sin_port = htons(port);
+#endif
+               /*
+                * Try 10 times to bind the socket with an interval of 20
+                * seconds. Do this so we dont have to keepp trying manually
+                * to bind. Why ? Because a port that has closed often lingers
+                * around for a short time.
+                * This used to be the case.  Now it no longer is.
+                * Could cause the server to hang for too long - avalon
+                */
+               if (bind(cptr->fd, (struct sockaddr *)&server,
+                       sizeof(server)) == -1)
+                   {
+                       report_error("binding stream socket %s:%s", cptr);
+#ifndef _WIN32
+                       (void)close(cptr->fd);
+#else
+                       (void)closesocket(cptr->fd);
+#endif
+                       return -1;
+                   }
+           }
+       if (getsockname(cptr->fd, (struct sockaddr *)&server, &len))
+           {
+               report_error("getsockname failed for %s:%s",cptr);
+#ifndef _WIN32
+               (void)close(cptr->fd);
+#else
+               (void)closesocket(cptr->fd);
+#endif
+               return -1;
+           }
+
+       if (cptr == &me) /* KLUDGE to get it work... */
+           {
+               char    buf[1024];
+
+#ifdef TESTNET
+               (void)sprintf(buf, rpl_str(RPL_MYPORTIS), me.name, "*",
+                   ntohs(server.sin_port) - 10000);
+#else
+               (void)sprintf(buf, rpl_str(RPL_MYPORTIS), me.name, "*",
+                   ntohs(server.sin_port));
+#endif
+               (void)write(0, buf, strlen(buf));
+           }
+       if (cptr->fd > highest_fd)
+               highest_fd = cptr->fd;
+       cptr->ip.s_addr = name ? inet_addr(ipname) : me.ip.s_addr;
+#ifdef TESTNET
+       cptr->port = (int)ntohs(server.sin_port) - 10000;
+#else
+       cptr->port = (int)ntohs(server.sin_port);
+#endif
+       (void)listen(cptr->fd, LISTEN_SIZE);
+       local[cptr->fd] = cptr;
+
+       return 0;
+}
+
+/*
+ * 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(aconf)
+aConfItem *aconf;
+{
+       aClient *cptr;
+
+       cptr = make_client(NULL, NULL);
+       cptr->flags = FLAGS_LISTEN;
+       cptr->acpt = cptr;
+       cptr->from = cptr;
+       SetMe(cptr);
+       strncpyzt(cptr->name, aconf->host, sizeof(cptr->name));
+               if (inetport(cptr, aconf->host, aconf->port))
+                       cptr->fd = -2;
+
+       if (cptr->fd >= 0)
+           {
+               cptr->confs = make_link();
+               cptr->confs->next = NULL;
+               cptr->confs->value.aconf = aconf;
+               set_non_blocking(cptr->fd, cptr);
+           }
+       else
+               free_client(cptr);
+       return 0;
+}
+
+/*
+ * close_listeners
+ *
+ * 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.
+ */
+void   close_listeners()
+{
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       Reg3    aConfItem *aconf;
+
+       /*
+        * close all 'extra' listening ports we have and unlink the file
+        * name if it was a unix socket.
+        */
+       for (i = highest_fd; i >= 0; i--)
+           {
+               if (!(cptr = local[i]))
+                       continue;
+               if (!IsMe(cptr) || cptr == &me || !IsListening(cptr))
+                       continue;
+               aconf = cptr->confs->value.aconf;
+
+               if (IsIllegal(aconf) && aconf->clients == 0)
+                   {
+                       close_connection(cptr);
+                   }
+           }
+}
+
+/*
+ * init_sys
+ */
+void   init_sys()
+{
+       Reg1    int     fd;
+#ifdef RLIMIT_FD_MAX
+       struct rlimit limit;
+       int     pid;
+
+       if (!getrlimit(RLIMIT_FD_MAX, &limit))
+           {
+# ifdef        pyr
+               if (limit.rlim_cur < MAXCONNECTIONS)
+#else
+               if (limit.rlim_max < MAXCONNECTIONS)
+# endif
+                   {
+                       (void)fprintf(stderr,"ircd fd table too big\n");
+                       (void)fprintf(stderr,"Hard Limit: %d IRC max: %d\n",
+                               limit.rlim_max, MAXCONNECTIONS);
+                       (void)fprintf(stderr,"Fix MAXCONNECTIONS\n");
+                       exit(-1);
+                   }
+# ifndef       pyr
+               limit.rlim_cur = limit.rlim_max; /* make soft limit the max */
+               if (setrlimit(RLIMIT_FD_MAX, &limit) == -1)
+                   {
+                       (void)fprintf(stderr,"error setting max fd's to %d\n",
+                                       limit.rlim_cur);
+                       exit(-1);
+                   }
+# endif
+           }
+#endif
+
+        /* Startup message 
+        pid = getpid();
+        pid++;
+        fprintf(stderr, "|---------------------------------------------\n");
+        fprintf(stderr, "| UnrealIRCD has successfully loaded.\n");
+        fprintf(stderr, "| Config Directory: %s\n", DPATH);
+        fprintf(stderr, "| MAXCONNECTIONS set at %d\n", MAXCONNECTIONS);
+        fprintf(stderr, "| Process ID: %d\n", pid);
+        fprintf(stderr, "|---------------------------------------------\n");*/
+
+#ifdef sequent
+# ifndef       DYNIXPTX
+       int     fd_limit;
+
+       fd_limit = setdtablesize(MAXCONNECTIONS + 1);
+       if (fd_limit < MAXCONNECTIONS)
+           {
+               (void)fprintf(stderr,"ircd fd table too big\n");
+               (void)fprintf(stderr,"Hard Limit: %d IRC max: %d\n",
+                       fd_limit, MAXCONNECTIONS);
+               (void)fprintf(stderr,"Fix MAXCONNECTIONS\n");
+               exit(-1);
+           }
+# endif
+#endif
+#if defined(PCS) || defined(DYNIXPTX) || defined(SVR3)
+       char    logbuf[BUFSIZ];
+
+       (void)setvbuf(stderr,logbuf,_IOLBF,sizeof(logbuf));
+#else
+# if defined(HPUX)
+       (void)setvbuf(stderr, NULL, _IOLBF, 0);
+# else
+#  if !defined(SOL20) && !defined(_WIN32)
+       (void)setlinebuf(stderr);
+#  endif
+# endif
+#endif
+#ifndef _WIN32
+       for (fd = 3; fd < MAXCONNECTIONS; fd++)
+           {
+               (void)close(fd);
+               local[fd] = NULL;
+           }
+       local[1] = NULL;
+       (void)close(1);
+
+       if (bootopt & BOOT_TTY) /* debugging is going to a tty */
+               goto init_dgram;
+       if (!(bootopt & BOOT_DEBUG))
+               (void)close(2);
+
+       if (((bootopt & BOOT_CONSOLE) || isatty(0)) &&
+           !(bootopt & (BOOT_INETD|BOOT_OPER)))
+           {
+#ifndef _AMIGA
+/*             if (fork())
+                       exit(0);
+*/
+#endif
+#ifdef TIOCNOTTY
+               if ((fd = open("/dev/tty", O_RDWR)) >= 0)
+                   {
+                       (void)ioctl(fd, TIOCNOTTY, (char *)NULL);
+                       (void)close(fd);
+                   }
+#endif
+
+#if defined(HPUX) || defined(SOL20) || defined(DYNIXPTX) || \
+    defined(_POSIX_SOURCE) || defined(SVR4) || defined(SGI)
+               (void)setsid();
+#else
+               (void)setpgrp(0, (int)getpid());
+#endif
+               (void)close(0); /* fd 0 opened by inetd */
+               local[0] = NULL;
+           }
+init_dgram:
+#endif /*_WIN32*/
+       resfd = init_resolver(0x1f);
+
+       return;
+}
+
+void   write_pidfile()
+{
+#ifdef IRCD_PIDFILE
+       int fd;
+       char buff[20];
+       if ((fd = open(IRCD_PIDFILE, O_CREAT|O_WRONLY, 0600))>=0)
+           {
+               bzero(buff, sizeof(buff));
+               (void)sprintf(buff,"%5d\n", (int)getpid());
+               if (write(fd, buff, strlen(buff)) == -1)
+                       Debug((DEBUG_NOTICE,"Error writing to pid file %s",
+                             IRCD_PIDFILE));
+               (void)close(fd);
+               return;
+           }
+#ifdef DEBUGMODE
+       else
+               Debug((DEBUG_NOTICE,"Error opening pid file %s",
+                       IRCD_PIDFILE));
+#endif
+#endif
+}
+               
+/*
+ * 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(cptr, sockn)
+Reg1   aClient *cptr;
+Reg2   char    *sockn;
+{
+       struct  sockaddr_in sk;
+       int     len = sizeof(struct sockaddr_in);
+
+
+       /* If descriptor is a tty, special checking... */
+#ifndef _WIN32
+       if (isatty(cptr->fd))
+#else
+       if (0)
+#endif
+           {
+               strncpyzt(sockn, me.sockhost, HOSTLEN);
+               bzero((char *)&sk, sizeof(struct sockaddr_in));
+           }
+       else if (getpeername(cptr->fd, (struct sockaddr *)&sk, &len) == -1)
+           {
+               report_error("connect failure: %s %s", cptr);
+               return -1;
+           }
+       (void)strcpy(sockn, (char *)inetntoa((char *)&sk.sin_addr));
+       if (inet_netof(sk.sin_addr) == IN_LOOPBACKNET)
+           {
+               cptr->hostp = NULL;
+               strncpyzt(sockn, me.sockhost, HOSTLEN);
+           }
+       bcopy((char *)&sk.sin_addr, (char *)&cptr->ip,
+               sizeof(struct in_addr));
+
+#ifdef TESTNET
+       cptr->port = (int)ntohs(sk.sin_port) - 10000;
+#else
+       cptr->port = (int)ntohs(sk.sin_port);
+#endif
+
+       return 0;
+}
+
+/*
+ * Ordinary client access check. Look for conf lines which have the same
+ * status as the flags passed.
+ *  0 = Success
+ * -1 = Access denied
+ * -2 = Bad socket.
+ */
+int    check_client(cptr)
+Reg1   aClient *cptr;
+{
+       static  char    sockname[HOSTLEN+1];
+       Reg2    struct  hostent *hp = NULL;
+       Reg3    int     i;
+       ClearAccess(cptr);
+       Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]",
+               cptr->name, inetntoa((char *)&cptr->ip)));
+
+       if (check_init(cptr, sockname))
+               return -2;
+
+       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 (!bcmp(hp->h_addr_list[i], (char *)&cptr->ip,
+                                 sizeof(struct in_addr)))
+                               break;
+               if (!hp->h_addr_list[i])
+                   {
+                       sendto_ops("IP# Mismatch: %s != %s[%08x]",
+                                  inetntoa((char *)&cptr->ip), hp->h_name,
+                                  *((unsigned long *)hp->h_addr));
+                       hp = NULL;
+                   }
+           }
+
+       if ((i = attach_Iline(cptr, hp, sockname)))
+           {
+               Debug((DEBUG_DNS,"ch_cl: access denied: %s[%s]",
+                       cptr->name, sockname));
+               return i;
+           }
+
+       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 0;
+}
+
+#define        CFLAG   CONF_CONNECT_SERVER
+#define        NFLAG   CONF_NOCONNECT_SERVER
+/*
+ * check_server_init(), 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.
+ *  0 = Success
+ * -1 = Access denied
+ * -2 = Bad socket.
+ */
+int    check_server_init(cptr)
+aClient        *cptr;
+{
+       Reg1    char    *name;
+       Reg2    aConfItem *c_conf = NULL, *n_conf = NULL;
+       struct  hostent *hp = NULL;
+       Link    *lp;
+
+       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;
+       /*
+        * We initiated this connection so the client should have a C and N
+        * line already attached after passing through the connec_server()
+        * function earlier.
+        */
+       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[%s]", name,
+                                  cptr->sockhost);
+                       det_confs_butmask(cptr, 0);
+                       return -1;
+                   }
+           }
+
+       /*
+       ** 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.
+       */
+       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 = index(aconf->host, '@')))
+                               s++;
+                       else
+                               s = aconf->host;
+                       Debug((DEBUG_DNS,"sv_ci:cache lookup (%s)",s));
+                       hp = gethost_byname(s, &lin);
+                   }
+           }
+       return check_server(cptr, hp, c_conf, n_conf, 0);
+
+}
+
+int    check_server(cptr, hp, c_conf, n_conf, estab)
+aClient        *cptr;
+Reg1   aConfItem       *n_conf, *c_conf;
+Reg2   struct  hostent *hp;
+int    estab;
+{
+       Reg3    char    *name;
+       char    abuff[HOSTLEN+USERLEN+2];
+       char    sockname[HOSTLEN+1], fullname[HOSTLEN+1];
+       Link    *lp = cptr->confs;
+       int     i;
+
+       ClearAccess(cptr);
+       if (check_init(cptr, sockname))
+               return -2;
+
+check_serverback:
+       if (hp)
+           {
+               for (i = 0; hp->h_addr_list[i]; i++)
+                       if (!bcmp(hp->h_addr_list[i], (char *)&cptr->ip,
+                                 sizeof(struct in_addr)))
+                               break;
+               if (!hp->h_addr_list[i])
+                   {
+                       sendto_ops("IP# Mismatch: %s != %s[%08x]",
+                                  inetntoa((char *)&cptr->ip), hp->h_name,
+                                  *((unsigned long *)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++])
+                   {
+                       strncpyzt(fullname, name, sizeof(fullname));
+                       add_local_domain(fullname, HOSTLEN-strlen(fullname));
+                       Debug((DEBUG_DNS, "sv_cl: gethostbyaddr: %s->%s",
+                               sockname, fullname));
+                       (void)sprintf(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;
+
+       /*
+        * 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))
+           {
+               (void)sprintf(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
+        */
+       if (!c_conf || !n_conf)
+           {
+               get_sockhost(cptr, sockname);
+               Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s] c %x n %x",
+                       name, cptr->username, cptr->sockhost,
+                       c_conf, n_conf));
+               return -1;
+           }
+       /*
+        * attach the C and N lines to the client structure for later use.
+        */
+       (void)attach_conf(cptr, n_conf);
+       (void)attach_conf(cptr, c_conf);
+       (void)attach_confs(cptr, name, CONF_HUB|CONF_LEAF|CONF_UWORLD);
+
+       if ((c_conf->ipnum.s_addr == -1) && !IsUnixSocket(cptr))
+               bcopy((char *)&cptr->ip, (char *)&c_conf->ipnum,
+                       sizeof(struct in_addr));
+       if (!IsUnixSocket(cptr))
+               get_sockhost(cptr, c_conf->host);
+
+       Debug((DEBUG_DNS,"sv_cl: access ok: %s[%s]",
+               name, cptr->sockhost));
+       if (estab)
+               return m_server_estab(cptr);
+       return 0;
+}
+#undef CFLAG
+#undef NFLAG
+
+/*
+** 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(cptr)
+aClient        *cptr;
+{
+       aConfItem *aconf;
+
+       SetHandshake(cptr);
+       
+       aconf = find_conf(cptr->confs, cptr->name, CONF_CONNECT_SERVER);
+       if (!aconf)
+           {
+               sendto_ops("Lost C-Line for %s", get_client_name(cptr,FALSE));
+               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", get_client_name(cptr,FALSE));
+               return -1;
+           }
+       sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
+       sendto_one(cptr, "SERVER %s 1 :%s",
+                  my_name_for_link(me.name, aconf), me.info);
+       if (!IsDead(cptr))
+               start_auth(cptr);
+
+       return (IsDead(cptr)) ? -1 : 0;
+}
+
+/*
+** close_connection
+**     Close the physical connection. This function must make
+**     MyConnect(cptr) == FALSE, and set cptr->from == NULL.
+*/
+void   close_connection(cptr)
+aClient *cptr;
+{
+        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 += TStime() - 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 (IsClient(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 += TStime() - 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;
+                   }
+           }
+       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.
+        *
+        * Now just hold on a minute.  We're currently doing this when a
+        * CLIENT exits too?  I don't think so!  If its not a server, or
+        * the SQUIT flag has been set, then we don't schedule a fast
+        * reconnect.  Pisses off too many opers. :-)  -Cabal95
+        */
+       if (IsServer(cptr) && !(cptr->flags & FLAGS_SQUIT) &&
+           (aconf = find_conf_exact(cptr->name, cptr->username,
+                                   cptr->sockhost, CONF_CONNECT_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 = TStime();
+               aconf->hold += (aconf->hold - cptr->since > HANGONGOODLINK) ?
+                               HANGONRETRYDELAY : ConfConFreq(aconf);
+               if (nextconnect > aconf->hold)
+                       nextconnect = aconf->hold;
+           }
+
+       if (cptr->authfd >= 0)
+#ifndef _WIN32
+               (void)close(cptr->authfd);
+#else
+               (void)closesocket(cptr->authfd);
+#endif
+
+#ifdef SOCKSPORT
+       if (cptr->socksfd >= 0)
+#ifndef _WIN32
+               (void)close(cptr->socksfd);
+#else
+               (void)closesocket(cptr->socksfd);
+#endif /* _WIN32 */
+#endif /* SOCKSPORT */
+
+
+
+       if (cptr->fd >= 0)
+           {
+               flush_connections(cptr->fd);
+               local[cptr->fd] = NULL;
+#ifndef _WIN32
+               (void)close(cptr->fd);
+#else
+               (void)closesocket(cptr->fd);
+#endif
+               cptr->fd = -2;
+               DBufClear(&cptr->sendQ);
+               DBufClear(&cptr->recvQ);
+               bzero(cptr->passwd, sizeof(cptr->passwd));
+               /*
+                * 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 (local[highest_fd])
+                       break;
+
+       det_confs_butmask(cptr, 0);
+       cptr->from = NULL; /* ...this should catch them! >:) --msa */
+
+       /*
+        * fd remap to keep local[i] filled at the bottom.
+        */
+       if (empty > 0)
+               if ((j = highest_fd) > (i = empty) &&
+                   (local[j]->status != STAT_LOG))
+                   {
+                       if (dup2(j,i) == -1)
+                               return;
+                       local[i] = local[j];
+                       local[i]->fd = i;
+                       local[j] = NULL;
+#ifndef NO_FDLIST
+                       /* update server list */
+                       if (IsServer(local[i]))
+                       {
+                               delfrom_fdlist(j,&busycli_fdlist);
+                               delfrom_fdlist(j,&serv_fdlist);
+                               addto_fdlist(i,&busycli_fdlist);
+                               addto_fdlist(i,&serv_fdlist);
+                      }
+                     if (IsAnOper(local[i])) {
+                           delfrom_fdlist(j, &busycli_fdlist);
+                           delfrom_fdlist(j, &oper_fdlist);
+                           addto_fdlist(i, &busycli_fdlist);
+                             addto_fdlist(i, &oper_fdlist);
+                     }
+#endif
+#ifndef _WIN32
+                       (void)close(j);
+#else
+                       (void)closesocket(j);
+#endif
+                       while (!local[highest_fd])
+                               highest_fd--;
+                   }
+       return;
+}
+
+/*
+** set_sock_opts
+*/
+static void    set_sock_opts(fd, cptr)
+int    fd;
+aClient        *cptr;
+{
+       int     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
+#if  defined(SO_DEBUG) && defined(DEBUGMODE) && 0
+/* Solaris with SO_DEBUG writes to syslog by default */
+#if !defined(SOL20) || defined(USE_SYSLOG)
+       opt = 1;
+       if (setsockopt(fd, SOL_SOCKET, SO_DEBUG, (OPT_TYPE *)&opt, sizeof(opt)) < 0)
+               report_error("setsockopt(SO_DEBUG) %s:%s", cptr);
+#endif /* SOL20 */
+#endif
+#if defined(SO_USELOOPBACK) && !defined(_WIN32)
+       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;
+# else
+       opt = 8192;
+# 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) && !defined(_WIN32)
+       {
+       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)
+                       (void)sprintf(s, "%02.2x:", *t++);
+               *s = '\0';
+               sendto_ops("Connection %s using IP opts: (%s)",
+                          get_client_name(cptr, TRUE), readbuf);
+           }
+       if (setsockopt(fd, IPPROTO_IP, IP_OPTIONS, (OPT_TYPE *)NULL, 0) < 0)
+               report_error("setsockopt(IP_OPTIONS) %s:%s", cptr);
+       }
+#endif
+}
+
+
+int    get_sockerr(cptr)
+aClient        *cptr;
+{
+#ifndef _WIN32
+       int errtmp = errno, err = 0, len = sizeof(err);
+#else
+       int errtmp = WSAGetLastError(), err = 0, len = sizeof(err);
+#endif
+#ifdef SO_ERROR
+       if (cptr->fd >= 0)
+               if (!getsockopt(cptr->fd, SOL_SOCKET, SO_ERROR, (OPT_TYPE *)&err, &len))
+                       if (err)
+                               errtmp = err;
+#endif
+       return errtmp;
+}
+
+/*
+** 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(fd, cptr)
+int    fd;
+aClient *cptr;
+{
+       int     res, nonb = 0;
+
+       /*
+       ** 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) < 0)
+               report_error("ioctl(fd,FIONBIO) failed for %s:%s", cptr);
+#else
+# if !defined(_WIN32)
+       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);
+# else
+       nonb=1;
+       if (ioctlsocket(fd, FIONBIO, &nonb) < 0)
+               report_error("ioctlsocket(fd,FIONBIO) failed for %s:%s", cptr);
+# endif
+#endif
+       return;
+}
+
+/*
+ * 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 yuet since it doesnt have a name.
+ */
+aClient        *add_connection(cptr, fd)
+aClient        *cptr;
+int    fd;
+{
+       Link    lin;
+       aClient *acptr;
+       aConfItem *aconf = NULL;
+       char    *message[20];
+       acptr = make_client(NULL, &me);
+
+       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.
+        */
+#ifndef _WIN32
+       if (isatty(fd)) /* If descriptor is a tty, special checking... */
+#else
+       if (0)
+#endif
+               get_sockhost(acptr, cptr->sockhost);
+       else
+           {
+               Reg1    char    *s, *t;
+               struct  sockaddr_in addr;
+               int     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);
+#ifndef _WIN32
+                       (void)close(fd);
+#else
+                       (void)closesocket(fd);
+#endif
+                       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, (char *)inetntoa((char *)&addr.sin_addr));
+               bcopy ((char *)&addr.sin_addr, (char *)&acptr->ip,
+                       sizeof(struct in_addr));
+               /* Check for zaps -- Barubary */
+               if (find_zap(acptr, 0))
+               {
+                       set_non_blocking(fd, acptr);
+                       set_sock_opts(fd, acptr);
+                       send(fd, zlinebuf, strlen(zlinebuf), 0);
+                       goto add_con_refuse;
+               }
+                else
+               if (find_tkline_match(acptr, 2) != -1)
+               {
+                       set_non_blocking(fd, acptr);
+                       set_sock_opts(fd, acptr);
+                       send(fd, zlinebuf, strlen(zlinebuf), 0);
+                       goto add_con_refuse;
+               }
+#ifdef TESTNET
+               acptr->port = ntohs(addr.sin_port) - 10000;
+#else
+               acptr->port = ntohs(addr.sin_port);
+#endif
+#if 0
+               /*
+                * Some genious along the lines of ircd took out the code
+                * where ircd loads the IP mask from the P:Lines, so this
+                * is useless untill that's added back. :)
+                */
+               /*
+                * 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;
+#endif
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+               write(fd, REPORT_DO_DNS, R_do_dns);
+#else
+               send(fd, REPORT_DO_DNS, R_do_dns, 0);
+#endif
+#endif
+               lin.flags = ASYNC_CLIENT;
+               lin.value.cptr = acptr;
+               Debug((DEBUG_DNS, "lookup %s",
+                       inetntoa((char *)&addr.sin_addr)));
+               acptr->hostp = gethost_byaddr((char *)&acptr->ip, &lin);
+               if (!acptr->hostp)
+                       SetDNS(acptr);
+#ifdef SHOWCONNECTINFO
+               else
+#ifndef _WIN32
+                       write(fd, REPORT_FIN_DNSC, R_fin_dnsc);
+#else
+                       send(fd, REPORT_FIN_DNSC, R_fin_dnsc, 0);
+#endif
+
+#endif
+               nextdnscheck = 1;
+           }
+
+       if (aconf)
+               aconf->clients++;
+       acptr->fd = fd;
+       if (fd > highest_fd)
+               highest_fd = fd;
+       local[fd] = acptr;
+       acptr->acpt = cptr;
+       add_client_to_list(acptr);
+       set_non_blocking(acptr->fd, acptr);
+       set_sock_opts(acptr->fd, acptr);
+       start_auth(acptr);
+#ifdef SOCKSPORT
+       start_socks(acptr);
+#endif
+       return acptr;
+}
+
+/*
+** read_packet
+**
+** 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
+*/
+static int     read_packet(cptr, rfd)
+Reg1   aClient *cptr;
+fd_set *rfd;
+{
+       Reg1    int     dolen = 0, length = 0, done;
+       time_t  now = TStime();
+
+       if (FD_ISSET(cptr->fd, rfd) &&
+           !(IsPerson(cptr) && DBufLength(&cptr->recvQ) > 6090))
+           {
+#ifndef _WIN32
+               errno = 0;
+#else
+               WSASetLastError(0);
+#endif
+               length = recv(cptr->fd, readbuf, sizeof(readbuf), 0);
+
+               cptr->lasttime = now;
+               if (cptr->lasttime > cptr->since)
+                       cptr->since = cptr->lasttime;
+               cptr->flags &= ~(FLAGS_PINGSENT|FLAGS_NONL);
+               /*
+                * If not ready, fake it so it isnt closed
+                */
+               if (length == -1 &&
+#ifndef _WIN32
+                       ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
+#else
+                       (WSAGetLastError() == WSAEWOULDBLOCK))
+#endif
+                       return 1;
+               if (length <= 0)
+                       return length;
+           }
+
+       /*
+       ** For server connections, we process as many as we can without
+       ** worrying about the time of day or anything :)
+       */
+       if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr) ||
+           IsService(cptr))
+           {
+               if (length > 0)
+                       if ((done = dopacket(cptr, readbuf, length)))
+                               return done;
+           }
+       else
+           {
+               /*
+               ** 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.
+               */
+               if (dbuf_put(&cptr->recvQ, readbuf, length) < 0)
+                       return exit_client(cptr, cptr, cptr, "dbuf_put fail");
+
+               if (IsPerson(cptr) &&
+                   DBufLength(&cptr->recvQ) > CLIENT_FLOOD)
+                   {
+                       sendto_umode(UMODE_FLOOD|UMODE_OPER,
+                               "*** Flood -- %s!%s@%s (%d) exceeds %d recvQ",
+                               cptr->name[0] ? cptr->name : "*",
+                               cptr->user ? cptr->user->username : "*",
+                               cptr->user ? cptr->user->realhost : "*",
+                               DBufLength(&cptr->recvQ), CLIENT_FLOOD);
+                       return exit_client(cptr, cptr, cptr, "Excess Flood");
+                   }
+
+               while (DBufLength(&cptr->recvQ) && !NoNewLine(cptr) &&
+                      ((cptr->status < STAT_UNKNOWN) ||
+                       (cptr->since - now < 10)))
+                   {
+                       /*
+                       ** If it has become registered as a Service or Server
+                       ** then skip the per-message parsing below.
+                       */
+                       if (IsService(cptr) || IsServer(cptr))
+                           {
+                               dolen = dbuf_get(&cptr->recvQ, readbuf,
+                                                sizeof(readbuf));
+                               if (dolen <= 0)
+                                       break;
+                               if ((done = dopacket(cptr, readbuf, dolen)))
+                                       return done;
+                               break;
+                           }
+                       dolen = dbuf_getmsg(&cptr->recvQ, readbuf,
+                                           sizeof(readbuf));
+                       /*
+                       ** 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
+                       */
+                       while (dolen <= 0)
+                           {
+                               if (dolen < 0)
+                                       return exit_client(cptr, cptr, cptr,
+                                                          "dbuf_getmsg fail");
+                               if (DBufLength(&cptr->recvQ) < 510)
+                                   {
+                                       cptr->flags |= FLAGS_NONL;
+                                       break;
+                                   }
+                               dolen = dbuf_get(&cptr->recvQ, readbuf, 511);
+                               if (dolen > 0 && DBufLength(&cptr->recvQ))
+                                       DBufClear(&cptr->recvQ);
+                           }
+
+                       if (dolen > 0 &&
+                           (dopacket(cptr, readbuf, dolen) == FLUSH_BUFFER))
+                               return FLUSH_BUFFER;
+                   }
+           }
+       return 1;
+}
+
+
+/*
+ * 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.
+ */
+#ifdef NO_FDLIST
+int    read_message(delay)
+#else
+int    read_message(delay, listp)
+#endif
+time_t delay; /* Don't ever use ZERO here, unless you mean to poll and then
+               * you have to have sleep/wait somewhere else in the code.--msa
+               */
+#ifndef NO_FDLIST
+fdlist *listp;
+#endif
+{
+       Reg1    aClient *cptr;
+       Reg2    int     nfds;
+       struct  timeval wait;
+#ifdef pyr
+       struct  timeval nowt;
+       u_long  us;
+#endif
+#ifndef _WIN32
+       fd_set  read_set, write_set;
+#else
+       fd_set  read_set, write_set, excpt_set;
+#endif
+        register int j;
+       time_t  delay2 = delay, now;
+       u_long  usec = 0;
+       int     res, length, fd, i;
+       int     auth = 0;
+#ifdef SOCKSPORT
+       int     socks = 0;
+#endif
+       int     sockerr;
+       static time_t last_tune = 0;
+
+#ifndef NO_FDLIST
+       /* if it is called with NULL we check all active fd's */
+              if (!listp)
+              {
+                      listp = &default_fdlist;
+                      listp->last_entry = highest_fd+1; /* remember the 0th entry isnt used */
+              }             
+#endif
+
+         if ((time(NULL) - last_tune) >        300)
+         {
+               last_tune = time(NULL);
+               save_tunefile();
+         }
+#ifdef pyr
+       (void) gettimeofday(&nowt, NULL);
+       now = nowt.tv_sec;
+#else
+       now = TStime();
+#endif
+
+       for (res = 0;;)
+           {
+               FD_ZERO(&read_set);
+               FD_ZERO(&write_set);
+#ifdef _WIN32
+               FD_ZERO(&excpt_set);
+#endif
+
+#ifdef NO_FDLIST
+               for (i = highest_fd; i >= 0; i--)
+#else
+                    for (i=listp->entry[j=1];j<=listp->last_entry;
+                                           i=listp->entry[++j])
+#endif
+                   {
+                       if (!(cptr = local[i]))
+                               continue;
+                       if (IsLog(cptr))
+                               continue;
+#ifdef SOCKSPORT
+                       if (DoingSocks(cptr))
+                       {
+                               socks++;
+                               FD_SET(cptr->socksfd, &read_set);
+#ifdef _WIN32
+                               FD_SET(cptr->socksfd, &excpt_set);
+#endif
+                               if (cptr->flags & FLAGS_WRSOCKS)
+                                       FD_SET(cptr->socksfd, &write_set);
+                       }
+#endif /* SOCKSPORT */
+
+                       if (DoingAuth(cptr))
+                           {
+                               auth++;
+                               Debug((DEBUG_NOTICE,"auth on %x %d", cptr, i));
+                               FD_SET(cptr->authfd, &read_set);
+#ifdef _WIN32
+                               FD_SET(cptr->authfd, &excpt_set);
+#endif
+                               if (cptr->flags & FLAGS_WRAUTH)
+                                       FD_SET(cptr->authfd, &write_set);
+                           }
+                       if (DoingDNS(cptr) || DoingAuth(cptr)
+#ifdef SOCKSPORT                       
+  || DoingSocks(cptr)
+#endif
+                               )
+                               continue;
+                       if (IsMe(cptr) && IsListening(cptr))
+                           {
+                               FD_SET(i, &read_set);
+                           }
+                       else if (!IsMe(cptr))
+                           {
+                               if (DBufLength(&cptr->recvQ) && delay2 > 2)
+                                       delay2 = 1;
+                               if (DBufLength(&cptr->recvQ) < 4088)
+                                       FD_SET(i, &read_set);
+                           }
+
+                       if (DBufLength(&cptr->sendQ) || IsConnecting(cptr) ||
+                           (DoList(cptr) && IsSendable(cptr)))
+#ifndef        pyr
+                               FD_SET(i, &write_set);
+#else
+                           {
+                               if (!IsBlocked(cptr))
+                                       FD_SET(i, &write_set);
+                               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)
+                               ClearBlocked(cptr);
+#endif
+                   }
+
+#ifdef SOCKSPORT
+               if (me.socksfd >= 0)
+                       FD_SET(me.socksfd, &read_set);
+#endif
+               if (udpfd >= 0)
+                       FD_SET(udpfd, &read_set);
+#ifndef _WIN32
+               if (resfd >= 0)
+                       FD_SET(resfd, &read_set);
+#endif
+
+               wait.tv_sec = MIN(delay2, delay);
+               wait.tv_usec = usec;
+#ifdef HPUX
+               nfds = select(FD_SETSIZE, (int *)&read_set, (int *)&write_set,
+                               0, &wait);
+#else
+# ifndef _WIN32
+               nfds = select(FD_SETSIZE, &read_set, &write_set, 0, &wait);
+# else
+               nfds = select(FD_SETSIZE, &read_set, &write_set, &excpt_set, &wait);
+# endif
+#endif
+#ifndef _WIN32
+               if (nfds == -1 && errno == EINTR)
+#else
+               if (nfds == -1 && WSAGetLastError() == WSAEINTR)
+#endif
+                       return -1;
+               else if (nfds >= 0)
+                       break;
+               report_error("select %s:%s", &me);
+               res++;
+               if (res > 5)
+                       restart("too many select errors");
+#ifndef _WIN32
+               sleep(10);
+#else
+               Sleep(10);
+#endif
+           }
+#ifdef SOCKSPORT
+       if (me.socksfd >= 0 && FD_ISSET(me.socksfd, &read_set))
+       {
+               int tmpsock;
+
+               tmpsock = accept(me.socksfd, NULL, NULL);
+               if(tmpsock >= 0)
+#ifdef _WIN32
+                       closesocket(tmpsock);
+#else
+                       close(tmpsock);
+#endif /* _WIN32 */
+               FD_CLR(me.socksfd, &read_set);
+       }
+#endif /* SOCKSPORT */
+  
+       if (udpfd >= 0 && FD_ISSET(udpfd, &read_set))
+           {
+                       polludp();
+                       nfds--;
+                       FD_CLR(udpfd, &read_set);
+           }
+#ifndef _WIN32
+       if (resfd >= 0 && FD_ISSET(resfd, &read_set))
+           {
+                       do_dns_async();
+                       nfds--;
+                       FD_CLR(resfd, &read_set);
+           }
+#endif
+       /*
+        * 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
+        */
+#ifdef NO_FDLIST
+       for (i = highest_fd; (auth > 0) && (i >= 0); i--)
+#else
+        for (i=listp->entry[j=1];j <= listp->last_entry;
+                                         i=listp->entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]))
+                       continue;
+               if (cptr->authfd < 0)
+                       continue;
+               auth--;
+#ifdef _WIN32
+               /*
+                * Because of the way windows uses select(), we have to use
+                * the exception FD set to find out when a connection is
+                * refused.  ie Auth ports and /connect's.  -Cabal95
+                */
+               if (FD_ISSET(cptr->authfd, &excpt_set))
+                   {
+                       int     err, len = sizeof(err);
+
+                       if (getsockopt(cptr->authfd, SOL_SOCKET, SO_ERROR,
+                                  (OPT_TYPE *)&err, &len) || err)
+                           {
+                               ircstp->is_abad++;
+                               closesocket(cptr->authfd);
+                               if (cptr->authfd == highest_fd)
+                                       while (!local[highest_fd])
+                                               highest_fd--;
+                               cptr->authfd = -1;
+                               cptr->flags &= ~(FLAGS_AUTH|FLAGS_WRAUTH);
+                               if (!DoingDNS(cptr))
+                                       SetAccess(cptr);
+                               if (nfds > 0)
+                                       nfds--;
+                               continue;
+                           }
+                   }
+#endif
+               if ((nfds > 0) && FD_ISSET(cptr->authfd, &write_set))
+                   {
+                       nfds--;
+                       send_authports(cptr);
+                   }
+               else if ((nfds > 0) && FD_ISSET(cptr->authfd, &read_set))
+                   {
+                       nfds--;
+                       read_authports(cptr);
+                   }
+           }
+#ifdef SOCKSPORT
+       /*
+        * I really hate to do this.. but another loop
+        * to check to see if we have any socks fd's.. - darkrot
+        */
+       for (i = highest_fd; (socks > 0) && (i >= 0); i--)
+           {
+               if (!(cptr = local[i]))
+                       continue;
+               if (cptr->socksfd < 0 || IsMe(cptr))
+                       continue;
+               socks--;
+#ifdef _WIN32
+               /*
+                * Because of the way windows uses select(), we have to use
+                * the exception FD set to find out when a connection is
+                * refused.  ie Auth ports and /connect's.  -Cabal95
+                */
+               if (FD_ISSET(cptr->socksfd, &excpt_set))
+                   {
+                       int     err, len = sizeof(err);
+
+                       if (getsockopt(cptr->socksfd, SOL_SOCKET, SO_ERROR,
+                                  (OPT_TYPE *)&err, &len) || err)
+                           {
+                               ircstp->is_abad++;
+                               closesocket(cptr->socksfd);
+                               if (cptr->socksfd == highest_fd)
+                                       while (!local[highest_fd])
+                                               highest_fd--;
+                               cptr->socksfd = -1;
+                               cptr->flags &= ~(FLAGS_SOCKS|FLAGS_WRSOCKS);
+                               if (nfds > 0)
+                                       nfds--;
+                               continue;
+                           }
+                   }
+#endif /* _WIN32 */
+               if ((nfds > 0) && FD_ISSET(cptr->socksfd, &write_set))
+                   {
+                       nfds--;
+                       send_socksquery(cptr);
+                   }
+               else if ((nfds > 0) && FD_ISSET(cptr->socksfd, &read_set))
+                   {
+                       nfds--;
+                       read_socks(cptr);
+                   }
+           }
+#endif /* SOCKSPORT */
+
+       for (i = highest_fd; i >= 0; i--)
+               if ((cptr = local[i]) && FD_ISSET(i, &read_set) &&
+                   IsListening(cptr))
+                   {
+                       FD_CLR(i, &read_set);
+                       nfds--;
+                       cptr->lasttime = TStime();
+                       /*
+                       ** 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(i, NULL, NULL)) < 0)
+                           {
+                               report_error("Cannot accept connections %s:%s",
+                                               cptr);
+                               break;
+                           }
+                       ircstp->is_ac++;
+                       if (fd >= MAXCLIENTS)
+                           {
+                               ircstp->is_ref++;
+                               sendto_ops("All connections in use. (%s)",
+                                          get_client_name(cptr, TRUE));
+                               (void)send(fd,
+                                       "ERROR :All connections in use\r\n",
+                                       32, 0);
+#ifndef _WIN32
+                               (void)close(fd);
+#else
+                               (void)closesocket(fd);
+#endif
+                               break;
+                           }
+                       /*
+                        * Use of add_connection (which never fails :) meLazy
+                        */
+                               (void)add_connection(cptr, fd);
+                       nextping = TStime();
+                       if (!cptr->acpt)
+                               cptr->acpt = &me;
+                   }
+
+       for (i = highest_fd; i >= 0; i--)
+           {
+               if (!(cptr = local[i]) || IsMe(cptr))
+                       continue;
+               if (FD_ISSET(i, &write_set))
+                   {
+                       int     write_err = 0;
+                       nfds--;
+                       /*
+                       ** ...room for writing, empty some queue then...
+                       */
+                       ClearBlocked(cptr);
+                       if (IsConnecting(cptr))
+                                 write_err = completed_connection(cptr);
+                       if (!write_err) {
+                               if (DoList(cptr) && IsSendable(cptr))
+                                       send_list(cptr, 32);
+                               (void)send_queued(cptr);
+                       }
+
+                       if (IsDead(cptr) || write_err)
+                           {
+deadsocket:
+                               if (FD_ISSET(i, &read_set))
+                                   {
+                                       nfds--;
+                                       FD_CLR(i, &read_set);
+                                   }
+                               (void)exit_client(cptr, cptr, &me,
+                                                 ((sockerr = get_sockerr(cptr))
+                                                  ? strerror(sockerr)
+                                                  : "Client exited"));
+                               continue;
+                           }
+                   }
+               length = 1;     /* for fall through case */
+               if (!NoNewLine(cptr) || FD_ISSET(i, &read_set))
+                       length = read_packet(cptr, &read_set);
+               if (length > 0)
+                       flush_connections(i);
+               if ((length != FLUSH_BUFFER) && IsDead(cptr))
+                       goto deadsocket;
+               if (!FD_ISSET(i, &read_set) && length > 0)
+                       continue;
+               nfds--;
+               readcalls++;
+               if (length > 0)
+                       continue;
+
+               /*
+               ** ...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
+               */
+#ifndef _WIN32
+               Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d",
+                       i, errno, length));
+#else
+               Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d",
+                       i, WSAGetLastError(), length));
+#endif
+
+               /*
+               ** NOTE: if length == -2 then cptr has already been freed!
+               */
+               if (length != -2 && (IsServer(cptr) || IsHandshake(cptr)))
+                   {
+                       if (length == 0) {
+                                sendto_locfailops("Server %s closed the connection",
+                                           get_client_name(cptr,FALSE));
+                                sendto_serv_butone(&me,
+                                       ":%s GLOBOPS :Server %s closed the connection",
+                                       me.name, get_client_name(cptr,FALSE));
+                       }
+                       else
+                                report_error("Lost connection to %s:%s",
+                                             cptr);
+                   }
+               if (length != FLUSH_BUFFER)
+                       (void)exit_client(cptr, cptr, &me,
+                                         ((sockerr = get_sockerr(cptr))
+                                          ? strerror(sockerr)
+                                          : "Client exited"));
+           }
+       return 0;
+}
+
+/*
+ * connect_server
+ */
+int    connect_server(aconf, by, hp)
+aConfItem *aconf;
+aClient        *by;
+struct hostent *hp;
+{
+       Reg1    struct  sockaddr *svp;
+       Reg2    aClient *cptr, *c2ptr;
+       Reg3    char    *s;
+       int     errtmp, len;
+
+       Debug((DEBUG_NOTICE,"Connect to %s[%s] @%s",
+               aconf->name, aconf->host, inetntoa((char *)&aconf->ipnum)));
+
+       if ((c2ptr = find_server(aconf->name, NULL)))
+           {
+               sendto_ops("Server %s already present from %s",
+                          aconf->name, get_client_name(c2ptr, TRUE));
+               if (by && IsPerson(by) && !MyClient(by))
+                 sendto_one(by,
+                             ":%s NOTICE %s :Server %s already present from %s",
+                             me.name, by->name, aconf->name,
+                            get_client_name(c2ptr, TRUE));
+               return -1;
+           }
+
+       /*
+        * 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 )
+            )
+           {
+               Link    lin;
+
+               lin.flags = ASYNC_CONNECT;
+               lin.value.aconf = aconf;
+               nextdnscheck = 1;
+               s = (char *)index(aconf->host, '@');
+               s++; /* should NEVER be NULL */
+               if ((aconf->ipnum.s_addr = inet_addr(s)) == -1)
+                   {
+                       aconf->ipnum.s_addr = 0;
+                       hp = gethost_byname(s, &lin);
+                       Debug((DEBUG_NOTICE, "co_sv: hp %x ac %x na %s ho %s",
+                               hp, aconf, aconf->name, s));
+                       if (!hp)
+                               return 0;
+                       bcopy(hp->h_addr, (char *)&aconf->ipnum,
+                               sizeof(struct in_addr));
+                   }
+           }
+       cptr = make_client(NULL, NULL);
+       cptr->hostp = hp;
+       /*
+        * Copy these in so we have something for error detection.
+        */
+       strncpyzt(cptr->name, aconf->name, sizeof(cptr->name));
+       strncpyzt(cptr->sockhost, aconf->host, HOSTLEN+1);
+
+       svp = connect_inet(aconf, cptr, &len);
+
+       if (!svp)
+           {
+               if (cptr->fd != -1)
+#ifndef _WIN32
+                       (void)close(cptr->fd);
+#else
+                       (void)closesocket(cptr->fd);
+#endif
+               cptr->fd = -2;
+               free_client(cptr);
+               return -1;
+           }
+
+       set_non_blocking(cptr->fd, cptr);
+       set_sock_opts(cptr->fd, cptr);
+#ifndef _WIN32
+       (void)signal(SIGALRM, dummy);
+       if (connect(cptr->fd, svp, len) < 0 && errno != EINPROGRESS)
+           {
+               errtmp = errno; /* other system calls may eat errno */
+#else
+       if (connect(cptr->fd, svp, len) < 0 &&
+               WSAGetLastError() != WSAEINPROGRESS &&
+               WSAGetLastError() != WSAEWOULDBLOCK)
+           {
+               errtmp = WSAGetLastError(); /* other system calls may eat errno */
+#endif
+               report_error("Connect to host %s failed: %s",cptr);
+                if (by && IsPerson(by) && !MyClient(by))
+                  sendto_one(by,
+                             ":%s NOTICE %s :Connect to host %s failed.",
+                            me.name, by->name, cptr);
+#ifndef _WIN32
+               (void)close(cptr->fd);
+#else
+               (void)closesocket(cptr->fd);
+#endif
+               cptr->fd = -2;
+               free_client(cptr);
+#ifndef _WIN32
+               errno = errtmp;
+               if (errno == EINTR)
+                       errno = ETIMEDOUT;
+#else
+               WSASetLastError(errtmp);
+               if (errtmp == WSAEINTR)
+                       WSASetLastError(WSAETIMEDOUT);
+#endif
+               return -1;
+           }
+
+        /* 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
+         */
+        (void)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->host);
+                if (by && IsPerson(by) && !MyClient(by))
+                  sendto_one(by,
+                             ":%s NOTICE %s :Connect to host %s failed.",
+                            me.name, by->name, cptr);
+               det_confs_butmask(cptr, 0);
+#ifndef _WIN32
+               (void)close(cptr->fd);
+#else
+               (void)closesocket(cptr->fd);
+#endif
+               cptr->fd = -2;
+               free_client(cptr);
+                return(-1);
+           }
+       /*
+       ** The socket has been connected or connect is in progress.
+       */
+       (void)make_server(cptr);
+       if (by && IsPerson(by))
+           {
+               (void)strcpy(cptr->serv->by, by->name);
+               if (cptr->serv->user) free_user(cptr->serv->user, NULL);
+               cptr->serv->user = by->user;
+               by->user->refcnt++;
+           }
+           else
+           {
+               (void)strcpy(cptr->serv->by, "AutoConn.");
+               if (cptr->serv->user) free_user(cptr->serv->user, NULL);
+               cptr->serv->user = NULL;
+           }
+       (void)strcpy(cptr->serv->up, me.name);
+       if (cptr->fd > highest_fd)
+               highest_fd = cptr->fd;
+       local[cptr->fd] = cptr;
+       cptr->acpt = &me;
+       SetConnecting(cptr);
+
+       get_sockhost(cptr, aconf->host);
+       add_client_to_list(cptr);
+       nextping = TStime();
+
+       return 0;
+}
+
+static struct  sockaddr *connect_inet(aconf, cptr, lenp)
+Reg1   aConfItem       *aconf;
+Reg2   aClient *cptr;
+int    *lenp;
+{
+       static  struct  sockaddr_in     server;
+       Reg3    struct  hostent *hp;
+
+       /*
+        * Might as well get sockhost from here, the connection is attempted
+        * with it so if it fails its useless.
+        */
+       cptr->fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (cptr->fd >= MAXCLIENTS)
+           {
+               sendto_ops("No more connections allowed (%s)", cptr->name);
+               return NULL;
+           }
+       mysk.sin_port = 0;
+       bzero((char *)&server, sizeof(server));
+       server.sin_family = AF_INET;
+       get_sockhost(cptr, aconf->host);
+
+       if (cptr->fd == -1)
+           {
+               report_error("opening stream socket to server %s:%s", cptr);
+               return NULL;
+           }
+       get_sockhost(cptr, aconf->host);
+       server.sin_port = 0;
+       server.sin_addr = me.ip;
+       server.sin_family = AF_INET;
+       /*
+       ** 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
+       */
+       /* We do now.  Virtual interface stuff --ns */
+       if (me.ip.s_addr != INADDR_ANY)
+       if (bind(cptr->fd, (struct sockaddr *)&server, sizeof(server)) == -1)
+           {
+               report_error("error binding to local port for %s:%s", cptr);
+               return NULL;
+           }
+       bzero((char *)&server, sizeof(server));
+       server.sin_family = AF_INET;
+       /*
+        * 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 == -1))
+               aconf->ipnum.s_addr = inet_addr(aconf->host);
+       if (aconf->ipnum.s_addr == -1)
+           {
+               hp = cptr->hostp;
+               if (!hp)
+                   {
+                       Debug((DEBUG_FATAL, "%s: unknown host", aconf->host));
+                       return NULL;
+                   }
+               bcopy(hp->h_addr, (char *)&aconf->ipnum,
+                     sizeof(struct in_addr));
+           }
+       bcopy((char *)&aconf->ipnum, (char *)&server.sin_addr,
+               sizeof(struct in_addr));
+       bcopy((char *)&aconf->ipnum, (char *)&cptr->ip,
+               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;
+}
+
+/*
+ * The following section of code performs summoning of users to irc.
+ */
+#if defined(ENABLE_SUMMON) || defined(ENABLE_USERS)
+int    utmp_open()
+{
+#ifdef O_NOCTTY
+       return (open(UTMP, O_RDONLY|O_NOCTTY));
+#else
+       return (open(UTMP, O_RDONLY));
+#endif
+}
+
+int    utmp_read(fd, name, line, host, hlen)
+int    fd, hlen;
+char   *name, *line, *host;
+{
+       struct  utmp    ut;
+       while (read(fd, (char *)&ut, sizeof (struct utmp))
+               == sizeof (struct utmp))
+           {
+               strncpyzt(name, ut.ut_name, 9);
+               strncpyzt(line, ut.ut_line, 10);
+#ifdef USER_PROCESS
+#  if defined(HPUX) || defined(AIX)
+               strncpyzt(host,(ut.ut_host[0]) ? (ut.ut_host) : me.name, 16);
+#  else
+               strncpyzt(host, me.name, 9);
+#  endif
+               if (ut.ut_type == USER_PROCESS)
+                       return 0;
+#else
+               strncpyzt(host, (ut.ut_host[0]) ? (ut.ut_host) : me.name,
+                       hlen);
+               if (ut.ut_name[0])
+                       return 0;
+#endif
+           }
+       return -1;
+}
+
+int    utmp_close(fd)
+int    fd;
+{
+       return(close(fd));
+}
+
+#ifdef ENABLE_SUMMON
+void   summon(who, namebuf, linebuf, chname)
+aClient *who;
+char   *namebuf, *linebuf, *chname;
+{
+       static  char    wrerr[] = "NOTICE %s :Write error. Couldn't summon.";
+       int     fd;
+       char    line[120];
+       time_t  now;
+       struct  tm      *tp;
+
+       now = TStime();
+       tp = localtime(&now);
+       if (strlen(linebuf) > (size_t) 9)
+           {
+               sendto_one(who,"NOTICE %s :Serious fault in SUMMON.",
+                          who->name);
+               sendto_one(who,
+                          "NOTICE %s :linebuf too long. Inform Administrator",
+                          who->name);
+               return;
+           }
+       /*
+        * Following line added to prevent cracking to e.g. /dev/kmem if
+        * UTMP is for some silly reason writable to everyone...
+        */
+       if ((linebuf[0] != 't' || linebuf[1] != 't' || linebuf[2] != 'y')
+           && (linebuf[0] != 'c' || linebuf[1] != 'o' || linebuf[2] != 'n')
+#ifdef HPUX
+           && (linebuf[0] != 'p' || linebuf[1] != 't' || linebuf[2] != 'y' ||
+               linebuf[3] != '/')
+#endif
+           )
+           {
+               sendto_one(who,
+                     "NOTICE %s :Looks like mere mortal souls are trying to",
+                          who->name);
+               sendto_one(who,"NOTICE %s :enter the twilight zone... ",
+                          who->name);
+               Debug((0, "%s (%s@%s, nick %s, %s)",
+                     "FATAL: major security hack. Notify Administrator !",
+                     who->username, who->user->host,
+                     who->name, who->info));
+               return;
+           }
+
+       (void)sprintf(line,"/dev/%s", linebuf);
+#ifdef O_NOCTTY
+       if ((fd = open(line, O_WRONLY | O_NDELAY | O_NOCTTY)) == -1)
+#else
+       if ((fd = open(line, O_WRONLY | O_NDELAY)) == -1)
+#endif
+           {
+               sendto_one(who,
+                          "NOTICE %s :%s seems to have disabled summoning...",
+                          who->name, namebuf);
+               return;
+           }
+#if !defined(O_NOCTTY) && defined(TIOCNOTTY)
+       (void) ioctl(fd, TIOCNOTTY, NULL);
+#endif
+       (void)sprintf(line,"\n\r\007Message from IRC_Daemon@%s at %d:%02d\n\r",
+                       me.name, tp->tm_hour, tp->tm_min);
+       if (write(fd, line, strlen(line)) != strlen(line))
+           {
+               (void)close(fd);
+               sendto_one(who, wrerr, who->name);
+               return;
+           }
+       (void)strcpy(line, "ircd: You are being summoned to Internet Relay \
+Chat on\n\r");
+       if (write(fd, line, strlen(line)) != strlen(line))
+           {
+               (void)close(fd);
+               sendto_one(who, wrerr, who->name);
+               return;
+           }
+       (void)sprintf(line, "ircd: Channel %s, by %s@%s (%s) %s\n\r",
+               chname, who->user->username, who->user->host, who->name, who->info);
+       if (write(fd, line, strlen(line)) != strlen(line))
+           {
+               (void)close(fd);
+               sendto_one(who, wrerr, who->name);
+               return;
+           }
+       (void)strcpy(line,"ircd: Respond with irc\n\r");
+       if (write(fd, line, strlen(line)) != strlen(line))
+           {
+               (void)close(fd);
+               sendto_one(who, wrerr, who->name);
+               return;
+           }
+       (void)close(fd);
+       sendto_one(who, rpl_str(RPL_SUMMONING), me.name, who->name, namebuf);
+       return;
+}
+#  endif
+#endif /* ENABLE_SUMMON */
+
+/*
+** 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(cptr, name, len)
+aClient        *cptr;
+char   *name;
+int    len;
+{
+       static  char tmp[HOSTLEN+1];
+       struct  hostent *hp;
+       char    *cname = cptr->name;
+
+       /*
+       ** Setup local socket structure to use for binding to.
+       */
+       bzero((char *)&mysk, sizeof(mysk));
+       mysk.sin_family = AF_INET;
+
+       if (gethostname(name,len) == -1)
+               return;
+       name[len] = '\0';
+
+       /* assume that a name containing '.' is a FQDN */
+       if (!index(name,'.'))
+               add_local_domain(name, len - strlen(name));
+
+       /*
+       ** If hostname gives another name than cname, then check if there is
+       ** a CNAME record for cname pointing to hostname. If so accept
+       ** cname as our name.   meLazy
+       */
+       if (BadPtr(cname))
+               return;
+       if ((hp = gethostbyname(cname)) || (hp = gethostbyname(name)))
+           {
+               char    *hname;
+               int     i = 0;
+
+               for (hname = hp->h_name; hname; hname = hp->h_aliases[i++])
+                   {
+                       strncpyzt(tmp, hname, sizeof(tmp));
+                       add_local_domain(tmp, sizeof(tmp) - strlen(tmp));
+
+                       /*
+                       ** Copy the matching name over and store the
+                       ** 'primary' IP# as 'myip' which is used
+                       ** later for making the right one is used
+                       ** for connecting to other hosts.
+                       */
+                       if (!mycmp(me.name, tmp))
+                               break;
+                   }
+               if (mycmp(me.name, tmp))
+                       strncpyzt(name, hp->h_name, len);
+               else
+                       strncpyzt(name, tmp, len);
+               bcopy(hp->h_addr, (char *)&mysk.sin_addr,
+                       sizeof(struct in_addr));
+               Debug((DEBUG_DEBUG,"local name is %s",
+                               get_client_name(&me,TRUE)));
+           }
+       return;
+}
+
+/*
+** setup a UDP socket and listen for incoming packets
+*/
+int    setup_ping()
+{
+       struct  sockaddr_in     from;
+       int     on = 1;
+
+       bzero((char *)&from, sizeof(from));
+       from.sin_addr = me.ip;
+#ifdef TESTNET
+       from.sin_port = htons(17007);
+#else
+       from.sin_port = htons(7007);
+#endif
+       from.sin_family = AF_INET;
+
+       if ((udpfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+           {
+#ifndef _WIN32
+               Debug((DEBUG_ERROR, "socket udp : %s", strerror(errno)));
+#else
+               Debug((DEBUG_ERROR, "socket udp : %s",
+                       strerror(WSAGetLastError())));
+#endif
+               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
+#ifndef _WIN32
+               Debug((DEBUG_ERROR, "setsockopt so_reuseaddr : %s",
+                       strerror(errno)));
+               (void)close(udpfd);
+#else
+               Debug((DEBUG_ERROR, "setsockopt so_reuseaddr : %s",
+                       strerror(WSAGetLastError())));
+               (void)closesocket(udpfd);
+#endif
+               udpfd = -1;
+               return -1;
+           }
+       on = 0;
+       (void) 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
+#ifndef _WIN32
+               Debug((DEBUG_ERROR, "bind : %s", strerror(errno)));
+               (void)close(udpfd);
+#else
+               Debug((DEBUG_ERROR, "bind : %s", strerror(WSAGetLastError())));
+               (void)closesocket(udpfd);
+#endif
+               udpfd = -1;
+               return -1;
+           }
+#ifndef _WIN32
+       if (fcntl(udpfd, F_SETFL, FNDELAY)==-1)
+           {
+               Debug((DEBUG_ERROR, "fcntl fndelay : %s", strerror(errno)));
+               (void)close(udpfd);
+               udpfd = -1;
+               return -1;
+           }
+#endif
+       return udpfd;
+}
+
+/*
+ * max # of pings set to 15/sec.
+ */
+static void    polludp()
+{
+       Reg1    char    *s;
+       struct  sockaddr_in     from;
+       int     n, fromlen = sizeof(from);
+       static  time_t  last = 0, now;
+       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"));
+
+       n = recvfrom(udpfd, readbuf, mlen, 0,
+               (struct sockaddr *)&from, &fromlen);
+       now = TStime();
+       if (now == last)
+               if (++cnt > 14)
+                       return;
+       cnt = 0;
+       last = now;
+
+       if (n == -1)
+           {
+#ifndef _WIN32
+               if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
+#else
+               if ((WSAGetLastError() == WSAEWOULDBLOCK))
+#endif
+                       return;
+               else
+                   {
+                       report_error("udp port recvfrom (%s): %s", &me);
+                       return;
+                   }
+           }
+       ircstp->is_udp++;
+       if (n  < 19)
+               return;
+
+       s = readbuf + n;
+       /*
+        * attach my name and version for the reply
+        */
+       *readbuf |= 1;
+       (void)strcpy(s, me.name);
+       s += strlen(s)+1;
+       (void)strcpy(s, version);
+       s += strlen(s);
+       (void)sendto(udpfd, readbuf, s-readbuf, 0,
+               (struct sockaddr *)&from ,sizeof(from));
+       return;
+}
+
+/*
+ * do_dns_async
+ *
+ * Called when the fd returned from init_resolver() has been selected for
+ * reading.
+ */
+#ifndef _WIN32
+static void    do_dns_async()
+#else
+void   do_dns_async(id)
+int    id;
+#endif
+{
+       static  Link    ln;
+       aClient *cptr;
+       aConfItem       *aconf;
+       struct  hostent *hp;
+
+       ln.flags = -1;
+#ifndef _WIN32
+       hp = get_res((char *)&ln);
+#else
+       hp = get_res((char *)&ln, id);
+#endif
+       while (hp != NULL)
+       {
+       Debug((DEBUG_DNS,"%#x = get_res(%d,%#x)",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);
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+                       write(cptr->fd, REPORT_FIN_DNS, R_fin_dns);
+#else
+                       send(cptr->fd, REPORT_FIN_DNS, R_fin_dns, 0);
+#endif
+#endif
+                       ClearDNS(cptr);
+                       if (!DoingAuth(cptr))
+                               SetAccess(cptr);
+                       cptr->hostp = hp;
+                   }
+               break;
+       case ASYNC_CONNECT :
+               aconf = ln.value.aconf;
+               if (hp && aconf)
+                   {
+                       bcopy(hp->h_addr, (char *)&aconf->ipnum,
+                             sizeof(struct in_addr));
+                       (void)connect_server(aconf, NULL, hp);
+                   }
+               else
+                       sendto_ops("Connect to %s failed: host lookup",
+                                  (aconf) ? aconf->host : "unknown");
+               break;
+       case ASYNC_CONF :
+               aconf = ln.value.aconf;
+               if (hp && aconf)
+                       bcopy(hp->h_addr, (char *)&aconf->ipnum,
+                             sizeof(struct in_addr));
+               break;
+       case ASYNC_SERVER :
+               cptr = ln.value.cptr;
+               del_queries((char *)cptr);
+               ClearDNS(cptr);
+               if (check_server(cptr, hp, NULL, NULL, 1))
+                       (void)exit_client(cptr, cptr, &me,
+                               "No Authorization");
+               break;
+       default :
+               break;
+       }
+
+       ln.flags = -1;
+#ifndef _WIN32
+       hp = get_res((char *)&ln);
+#else
+       hp = get_res((char *)&ln, id);
+#endif
+       } /* while (hp != NULL) */
+}
diff --git a/src/s_conf.c b/src/s_conf.c
new file mode 100644 (file)
index 0000000..14baab5
--- /dev/null
@@ -0,0 +1,2630 @@
+/*
+ *   IRC - Internet Relay Chat, ircd/s_conf.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.
+ */
+
+/* Changed all calls of check_pings so that only when a kline-related command
+   is used will a kline check occur -- Barubary */
+
+#define KLINE_RET_AKILL 3
+#define KLINE_RET_PERM 2
+#define KLINE_RET_DELOK 1
+#define KLINE_DEL_ERR 0
+
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_conf.c  2.56 02 Apr 1994 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "channel.h"
+#include <fcntl.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/wait.h>
+#else
+#include <io.h>
+#endif
+#include <sys/stat.h>
+#ifdef __hpux
+#include "inet.h"
+#endif
+#if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
+#include <time.h>
+#endif
+
+ID_CVS("$Id$");
+ID_Notes("O:line flags in here");
+#include "h.h"
+
+static int     check_time_interval PROTO((char *, char *));
+static int     lookup_confhost PROTO((aConfItem *));
+static int     is_comment PROTO((char *));
+static  int     advanced_check(char *, int);
+
+aSqlineItem    *sqline = NULL;
+aConfItem      *conf = NULL;
+extern char    zlinebuf[];
+
+/*
+ * remove all conf entries from the client except those which match
+ * the status field mask.
+ */
+void   det_confs_butmask(cptr, mask)
+aClient        *cptr;
+int    mask;
+{
+       Reg1 Link *tmp, *tmp2;
+
+       for (tmp = cptr->confs; tmp; tmp = tmp2)
+           {
+               tmp2 = tmp->next;
+               if ((tmp->value.aconf->status & mask) == 0)
+                       (void)detach_conf(cptr, tmp->value.aconf);
+           }
+}
+
+/*
+ * Add a temporary line to the configuration
+ */
+void   add_temp_conf(status, host, passwd, name, port, class, temp)
+unsigned int   status;
+char   *host;
+char   *passwd;
+char   *name;
+int    port, class, temp;      /* temp: 0 = perm 1 = temp 2 = akill */
+{
+       Reg1 aConfItem *aconf;
+
+       aconf = make_conf();
+
+       aconf->tmpconf = temp;
+       aconf->status = status;
+       if (host)
+         DupString(aconf->host, host);
+       if (passwd)
+         DupString(aconf->passwd, passwd);
+       if (name)
+         DupString(aconf->name, name);
+       aconf->port = port;
+       if (class)
+               Class(aconf) = find_class(class);
+       if (!find_temp_conf_entry(aconf, status)) {
+               aconf->next = conf;
+               conf = aconf;
+               aconf = NULL;
+       }
+
+       if (aconf)
+         free_conf(aconf);
+}
+
+/*
+ * delete a temporary conf line.  *only* temporary conf lines may be deleted.
+ */
+int    del_temp_conf(status, host, passwd, name, port, class, akill)
+unsigned int    status, akill;
+char    *host;
+char    *passwd;
+char    *name;
+int     port, class;
+{
+       Reg1    aConfItem       *aconf;
+       Reg3    aConfItem       *bconf;
+       u_int   mask;
+       u_int   result=KLINE_DEL_ERR;
+
+       aconf = make_conf();
+       
+       aconf->status=status;
+       if(host)
+               DupString(aconf->host, host);
+       if(passwd)
+               DupString(aconf->passwd, passwd);
+       if(name)
+               DupString(aconf->name, name);
+       aconf->port = port;
+       if(class)
+               Class(aconf) = find_class(class);
+       mask = status;
+       if (bconf=find_temp_conf_entry(aconf,mask)) /* only if non-null ptr */
+       {
+/* Completely skirt the akill error messages if akill is set to 1
+ * this allows RAKILL to do its thing without having to go through the
+ * error checkers.  If it had to it would go kaplooey. --Russell
+ */
+               if (bconf->tmpconf == KLINE_PERM && (akill != 3))
+                       result = KLINE_RET_PERM;/* Kline permanent */
+               else if (!akill && (bconf->tmpconf == KLINE_AKILL))
+                       result = KLINE_RET_AKILL;  /* Akill */
+               else if (akill && (bconf->tmpconf != KLINE_AKILL))
+                       result = KLINE_RET_PERM;
+               else
+               {
+                       bconf->status |= CONF_ILLEGAL; /* just mark illegal */
+                       result = KLINE_RET_DELOK;      /* same as deletion */
+               }       
+
+       }
+       if (aconf)
+               free_conf(aconf);
+       return result; /* if it gets to here, it doesn't exist */
+}
+
+/*
+ * find the first (best) I line to attach.
+ */
+int    attach_Iline(cptr, hp, sockhost)
+aClient *cptr;
+Reg2   struct  hostent *hp;
+char   *sockhost;
+{
+       Reg1    aConfItem       *aconf;
+       Reg3    char    *hname;
+       Reg4    int     i;
+       static  char    uhost[HOSTLEN+USERLEN+3];
+       static  char    fullname[HOSTLEN+1];
+
+       for (aconf = conf; aconf; aconf = aconf->next)
+           {
+               if (aconf->status != CONF_CLIENT)
+                       continue;
+               if (aconf->port && aconf->port != cptr->acpt->port)
+                       continue;
+               if (!aconf->host || !aconf->name)
+                       goto attach_iline;
+               if (hp)
+                       for (i = 0, hname = hp->h_name; hname;
+                            hname = hp->h_aliases[i++])
+                           {
+                               (void)strncpy(fullname, hname,
+                                       sizeof(fullname)-1);
+                               add_local_domain(fullname,
+                                                HOSTLEN - strlen(fullname));
+                               Debug((DEBUG_DNS, "a_il: %s->%s",
+                                     sockhost, fullname));
+                               if (index(aconf->name, '@'))
+                                   {
+                                       (void)strcpy(uhost, cptr->username);
+                                       (void)strcat(uhost, "@");
+                                   }
+                               else
+                                       *uhost = '\0';
+                               (void)strncat(uhost, fullname,
+                                       sizeof(uhost) - strlen(uhost));
+                               if (!match(aconf->name, uhost))
+                                       goto attach_iline;
+                           }
+
+               if (index(aconf->host, '@'))
+                   {
+                       strncpyzt(uhost, cptr->username, sizeof(uhost));
+                       (void)strcat(uhost, "@");
+                   }
+               else
+                       *uhost = '\0';
+               (void)strncat(uhost, sockhost, sizeof(uhost) - strlen(uhost));
+               if (!match(aconf->host, uhost))
+                       goto attach_iline;
+               continue;
+attach_iline:
+               if (index(uhost, '@'))
+                       cptr->flags |= FLAGS_DOID;
+               get_sockhost(cptr, uhost);
+
+              if (aconf->passwd && !strcmp(aconf->passwd, "ONE"))
+              {
+               for (i = highest_fd; i >= 0; i--)
+                                if (local[i] && MyClient(local[i]) &&
+                                     local[i]->ip.s_addr == cptr->ip.s_addr)
+                                   return -1; /* Already got one with that ip# */
+              }
+              
+               return attach_conf(cptr, aconf);
+           }
+       return -1;
+}
+
+/*
+ * Find the single N line and return pointer to it (from list).
+ * If more than one then return NULL pointer.
+ */
+aConfItem      *count_cnlines(lp)
+Reg1   Link    *lp;
+{
+       Reg1    aConfItem       *aconf, *cline = NULL, *nline = NULL;
+
+       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.
+**      Also removes a class from the list if marked for deleting.
+*/
+int    detach_conf(cptr, aconf)
+aClient *cptr;
+aConfItem *aconf;
+{
+       Reg1    Link    **lp, *tmp;
+
+       lp = &(cptr->confs);
+
+       while (*lp)
+           {
+               if ((*lp)->value.aconf == aconf)
+                   {
+                       if ((aconf) && (Class(aconf)))
+                           {
+                               if (aconf->status & CONF_CLIENT_MASK)
+                                       if (ConfLinks(aconf) > 0)
+                                               --ConfLinks(aconf);
+                                       if (ConfMaxLinks(aconf) == -1 &&
+                                   ConfLinks(aconf) == 0)
+                                   {
+                                       free_class(Class(aconf));
+                                       Class(aconf) = NULL;
+                                   }
+                            }
+                       if (aconf && !--aconf->clients && IsIllegal(aconf))
+                               free_conf(aconf);
+                       tmp = *lp;
+                       *lp = tmp->next;
+                       free_link(tmp);
+                       return 0;
+                   }
+               else
+                       lp = &((*lp)->next);
+           }
+       return -1;
+}
+
+static int     is_attached(aconf, cptr)
+aConfItem *aconf;
+aClient *cptr;
+{
+       Reg1    Link    *lp;
+
+       for (lp = cptr->confs; lp; lp = lp->next)
+               if (lp->value.aconf == aconf)
+                       break;
+
+       return (lp) ? 1 : 0;
+}
+
+/*
+** attach_conf
+**     Associate a specific configuration entry to a *local*
+**     client (this is the one which used in accepting the
+**     connection). Note, that this automaticly changes the
+**     attachment if there was an old one...
+*/
+int    attach_conf(cptr, aconf)
+aConfItem *aconf;
+aClient *cptr;
+{
+       Reg1 Link *lp;
+
+       if (is_attached(aconf, cptr))
+               return 1;
+       if (IsIllegal(aconf))
+               return -1;
+       if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) &&
+           aconf->clients >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
+               return -3;      /* Use this for printing error message */
+       lp = make_link();
+       lp->next = cptr->confs;
+       lp->value.aconf = aconf;
+       cptr->confs = lp;
+       aconf->clients++;
+       if (aconf->status & CONF_CLIENT_MASK)
+               ConfLinks(aconf)++;
+       return 0;
+}
+
+
+aConfItem *find_tline(char *host)
+    {
+       Reg1 aConfItem *aconf;
+
+       for (aconf = conf; aconf; aconf = aconf->next)
+               if (aconf->status & CONF_TLINE)
+                       if (!match(aconf->host, host)) {
+                               return(aconf);
+                       }       
+       return(NULL);
+    }
+
+aConfItem *find_socksexcept(char *host)
+    {
+       Reg1 aConfItem *aconf;
+
+       for (aconf = conf; aconf; aconf = aconf->next)
+               if (aconf->status & CONF_SOCKSEXCEPT)
+                       if (!match(aconf->host, host)) {
+                               return(aconf);
+                       }       
+       return(NULL);
+    }
+
+aConfItem *find_admin()
+    {
+       Reg1 aConfItem *aconf;
+
+       for (aconf = conf; aconf; aconf = aconf->next)
+               if (aconf->status & CONF_ADMIN)
+                               break;
+       return(aconf);
+    }
+
+/* Find a DR_PASS line for the /DIE or /RESTART command
+ * Instead of returning the whole structure we return a
+ * char* which is the pass. 
+ * Added December 28 1997 -- NikB 
+ */
+char *find_diepass() 
+    {
+       Reg1 aConfItem *aconf;
+       
+       for (aconf = conf; aconf; aconf = aconf->next)
+           if (aconf->status & CONF_DRPASS)
+                       return (aconf->host);
+                       
+       return NULL;    /* Return NULL (We did not find any) */
+    }
+
+char *find_restartpass() 
+    {
+       Reg1 aConfItem *aconf;
+       
+       for (aconf = conf; aconf; aconf = aconf->next)
+           if (aconf->status & CONF_DRPASS)
+                       return (aconf->passwd);
+                               
+       return NULL;    /* Return NULL (We did not find any) */
+    }
+   
+aConfItem *find_me()
+    {
+       Reg1 aConfItem *aconf;
+       for (aconf = conf; aconf; aconf = aconf->next)
+               if (aconf->status & CONF_ME)
+                       break;
+       
+       return (aconf);
+    }
+
+/*
+ * attach_confs
+ *  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(cptr, name, statmask)
+aClient        *cptr;
+char   *name;
+int    statmask;
+{
+       Reg1 aConfItem *tmp;
+       aConfItem *first = NULL;
+       int len = strlen(name);
+  
+       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) && !first)
+                               first = tmp;
+                   }
+               else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
+                        (tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
+                       tmp->name && !match(tmp->name, name))
+                   {
+                       if (!attach_conf(cptr, tmp) && !first)
+                               first = tmp;
+                   }
+           }
+       return (first);
+}
+
+/*
+ * Added for new access check    meLazy
+ */
+aConfItem *attach_confs_host(cptr, host, statmask)
+aClient *cptr;
+char   *host;
+int    statmask;
+{
+       Reg1    aConfItem *tmp;
+       aConfItem *first = NULL;
+       int     len = strlen(host);
+  
+       if (!host || len > HOSTLEN)
+               return NULL;
+
+       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) && !first)
+                               first = tmp;
+                   }
+               else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
+                   (tmp->status & CONF_SERVER_MASK) &&
+                   (tmp->host && mycmp(tmp->host, host) == 0))
+                   {
+                       if (!attach_conf(cptr, tmp) && !first)
+                               first = tmp;
+                   }
+           }
+       return (first);
+}
+
+/*
+ * find a conf entry which matches the hostname and has the same name.
+ */
+aConfItem *find_conf_exact(name, user, host, statmask)
+char   *name, *host, *user;
+int    statmask;
+{
+       Reg1    aConfItem *tmp;
+       char    userhost[USERLEN+HOSTLEN+3];
+
+       (void)sprintf(userhost, "%s@%s", user, host);
+
+       for (tmp = conf; tmp; tmp = tmp->next)
+           {
+               if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
+                   mycmp(tmp->name, name))
+                       continue;
+               if (tmp->status & CONF_ILLEGAL)
+                       continue;
+               /*
+               ** Accept if the *real* hostname (usually sockecthost)
+               ** socket host) matches *either* host or name field
+               ** of the configuration.
+               */
+               if (match(tmp->host, userhost))
+                       continue;
+               if (tmp->status & (CONF_OPERATOR|CONF_LOCOP))
+                   {
+                       if (tmp->clients < MaxLinks(Class(tmp)))
+                               return tmp;
+                       else
+                               continue;
+                   }
+               else
+                       return tmp;
+           }
+       return NULL;
+}
+
+aConfItem *find_conf_name(name, statmask)
+char   *name;
+int    statmask;
+{
+       Reg1    aConfItem *tmp;
+       for (tmp = conf; tmp; tmp = tmp->next)
+           {
+               /*
+               ** Accept if the *real* hostname (usually sockecthost)
+               ** matches *either* host or name field of the configuration.
+               */
+               if ((tmp->status & statmask) &&
+                   (!tmp->name || match(tmp->name, name) == 0))
+                       return tmp;
+           }
+       return NULL;
+}
+
+aConfItem *find_conf_servern(name)
+char   *name;
+{
+       Reg1    aConfItem *tmp;
+       for (tmp = conf; tmp; tmp = tmp->next)
+           {
+               /*
+               ** Accept if the *real* hostname (usually sockecthost)
+               ** matches *either* host or name field of the configuration.
+               */
+               if ((tmp->status & CONF_NOCONNECT_SERVER) &&
+                   (!tmp->name || match(tmp->name, name) == 0))
+                       return tmp;
+           }
+       return NULL;
+}
+
+aConfItem *find_conf(lp, name, statmask)
+char   *name;
+Link   *lp;
+int    statmask;
+{
+       Reg1    aConfItem *tmp;
+       int     namelen = name ? strlen(name) : 0;
+  
+       if (namelen > HOSTLEN)
+               return (aConfItem *) 0;
+
+       for (; lp; lp = lp->next)
+           {
+               tmp = lp->value.aconf;
+               if ((tmp->status & statmask) &&
+                   (((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
+                    tmp->name && !match(tmp->name, name)) ||
+                    ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0 &&
+                    tmp->name && !match(tmp->name, name))))
+                       return tmp;
+           }
+       return NULL;
+}
+
+/*
+ * Added for new access check    meLazy
+ */
+aConfItem *find_conf_host(lp, host, statmask)
+Reg2   Link    *lp;
+char   *host;
+Reg3   int     statmask;
+{
+       Reg1    aConfItem *tmp;
+       int     hostlen = host ? strlen(host) : 0;
+  
+       if (hostlen > HOSTLEN || BadPtr(host))
+               return (aConfItem *)NULL;
+       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;
+           }
+       return NULL;
+}
+
+/* find_exception        
+** find a virtual exception
+*/
+int find_exception(char *abba)
+{
+    aConfItem *tmp;
+
+    for (tmp=conf; tmp; tmp=tmp->next)
+    {}
+
+    return 0;
+}
+
+/*
+ * find_conf_ip
+ *
+ * Find a conf line using the IP# stored in it to search upon.
+ * Added 1/8/92 by Avalon.
+ */
+aConfItem *find_conf_ip(lp, ip, user, statmask)
+char   *ip, *user;
+Link   *lp;
+int    statmask;
+{
+       Reg1    aConfItem *tmp;
+       Reg2    char    *s;
+  
+       for (; lp; lp = lp->next)
+           {
+               tmp = lp->value.aconf;
+               if (!(tmp->status & statmask))
+                       continue;
+               s = index(tmp->host, '@');
+               *s = '\0';
+               if (match(tmp->host, user))
+                   {
+                       *s = '@';
+                       continue;
+                   }
+               *s = '@';
+               if (!bcmp((char *)&tmp->ipnum, ip, sizeof(struct in_addr)))
+                       return tmp;
+           }
+       return NULL;
+}
+
+/*
+ * find_conf_entry
+ *
+ * - looks for a match on all given fields.
+ */
+aConfItem *find_conf_entry(aconf, mask)
+aConfItem *aconf;
+u_int  mask;
+{
+       Reg1    aConfItem *bconf;
+
+       for (bconf = conf, mask &= ~CONF_ILLEGAL; 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)))
+                       continue;
+               if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
+                       continue;
+
+               if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
+                   (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
+                       continue;
+               if (!BadPtr(bconf->passwd) && mycmp(bconf->passwd, "ONE") && 
+                   mycmp(bconf->passwd, aconf->passwd))
+                       continue;
+
+               if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
+                   (BadPtr(aconf->name) && !BadPtr(bconf->name)))
+                       continue;
+               if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
+                       continue;
+               break;
+           }
+       return bconf;
+}
+
+/*
+ * find_temp_conf_entry
+ *
+ * - looks for a match on all given fields for a TEMP conf line.
+ *  Right now the passwd,port, and class fields are ignored, because it's
+ *  only useful for k:lines anyway.  -Russell   11/22/95
+ *  1/21/95 Now looks for any conf line.  I'm leaving this routine and its
+ *  call in because this routine has potential in future upgrades. -Russell
+ */
+aConfItem *find_temp_conf_entry(aconf, mask)
+aConfItem *aconf;
+u_int   mask;
+{
+        Reg1    aConfItem *bconf;
+
+        for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
+            {
+               /* kline/unkline/kline fix -- Barubary */
+               if (bconf->status & CONF_ILLEGAL) continue;
+                if (!(bconf->status & mask) || (bconf->port != aconf->port))
+                        continue;
+/*                if (!bconf->tempconf) continue;*/
+                if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
+                    (BadPtr(aconf->host) && !BadPtr(bconf->host)))
+                       continue;
+                if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
+                        continue;
+
+/*                if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
+                    (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
+                        continue;
+                if (!BadPtr(bconf->passwd) &&
+                    mycmp(bconf->passwd, aconf->passwd))
+                        continue;*/
+
+                if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
+                    (BadPtr(aconf->name) && !BadPtr(bconf->name)))
+                       continue;
+                if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
+                        continue;
+                break;
+            }
+        return bconf;
+}
+
+aSqlineItem *find_sqline_nick(nickmask)
+char *nickmask;
+{
+       Reg1    aSqlineItem *asqline;
+
+       for(asqline = sqline; asqline; asqline = asqline->next) {
+               if(!BadPtr(asqline->sqline) && (asqline->status !=
+                       CONF_ILLEGAL) && !mycmp(asqline->sqline, nickmask))
+               return asqline;
+       }
+       return NULL;
+}
+
+aSqlineItem *find_sqline_match(nickname)
+char *nickname;
+{
+        Reg1    aSqlineItem *asqline;
+
+       for(asqline = sqline; asqline; asqline = asqline->next) {
+               if(!BadPtr(asqline->sqline) && (asqline->status != 
+                       CONF_ILLEGAL) && !match(asqline->sqline,nickname))
+               return asqline;
+       }
+       return NULL;
+}
+
+/*
+**      parv[0] = sender prefix
+**      parv[1] = server
+**      parv[2] = +/-
+**
+*/
+int     m_svsnoop(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+       Reg1    aConfItem *aconf;
+
+        if (!(check_registered(sptr) && IsULine(cptr, sptr) && parc > 2))
+                return 0;
+/* svsnoop bugfix --binary */
+       if (hunt_server(cptr, sptr, ":%s SVSNOOP %s :%s", 1, parc, parv) == HUNTED_ISME) {
+               if (parv[2][0] == '+')
+                       for(aconf=conf;aconf;aconf=aconf->next) {
+                          if (aconf->status & CONF_OPERATOR || aconf->status & CONF_LOCOP)
+                                       aconf->status = CONF_ILLEGAL;
+                       }
+               else
+                       (void)rehash(&me, &me, 2);
+       }       
+}
+#define doDebug debugNotice( __FILE__, __LINE__)
+
+void   debugNotice(char *file, long line) {
+       /* a little handy debug tool --sts */
+#ifdef STSDEBUG
+       sendto_ops("# !Debug! # %s:%i", file, line);
+       flush_connections(me.fd);
+#endif 
+}
+#define DoFlush flush_connections(me.fd)
+/*
+ * rehash
+ *
+ * Actual REHASH service routine. Called with sig == 0 if it has been called
+ * as a result of an operator issuing this command, else assume it has been
+ * called as a result of the server receiving a HUP signal.
+ */
+int    rehash(cptr, sptr, sig)
+aClient        *cptr, *sptr;
+int    sig;
+{
+       Reg1    aConfItem **tmp = &conf, *tmp2;
+       Reg2    aClass  *cltmp;
+       Reg1    aClient *acptr;
+       Reg2    int     i;
+       int     ret = 0;
+ /* One of the REHASH bugs -- sts*/
+       flush_connections(me.fd);
+       if (sig == 1)
+           {
+               sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
+#ifdef ULTRIX
+               if (fork() > 0)
+                       exit(0);
+               write_pidfile();
+#endif
+           }
+       for (i = 0; i <= highest_fd; i++)
+               if ((acptr = local[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)
+                   {
+                       /*
+                       ** 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;
+                           }
+                       else
+                               tmp = &tmp2->next;
+                       tmp2->status |= CONF_ILLEGAL;
+                   }
+               else
+                   {
+                       *tmp = tmp2->next;
+                       /* free expression trees of connect rules */
+                       if ((tmp2->status & (CONF_CRULEALL|CONF_CRULEAUTO))
+                           && (tmp2->passwd != NULL))
+                         crule_free (&(tmp2->passwd));
+                       free_conf(tmp2);
+                   }
+       /*
+        * We don't delete the class table, rather mark all entries
+        * for deletion. The table is cleaned up by check_class. - avalon
+        */
+       for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp))
+               MaxLinks(cltmp) = -1;
+       if (sig != 2)
+               flush_cache();
+
+       (void) initconf(0);
+       DoFlush;
+       close_listeners();
+       /*
+        * flush out deleted I and P lines although still in use.
+        */
+       for (tmp = &conf; (tmp2 = *tmp); )
+               if (!(tmp2->status & CONF_ILLEGAL))
+                       tmp = &tmp2->next;
+               else
+                   {
+                       *tmp = tmp2->next;
+                       tmp2->next = NULL;
+                       if (!tmp2->clients)
+                               free_conf(tmp2);
+                   }
+       /* Added to make sure K-lines are checked -- Barubary */
+       check_pings(TStime(), 1);
+       /* Recheck all U-lines -- Barubary */
+       for (i = 0; i < highest_fd; i++)
+               if ((acptr = local[i]) && !IsMe(acptr))
+               {
+                       if (find_conf_host(acptr->from->confs, acptr->name,
+                               CONF_UWORLD) || (acptr->user && find_conf_host(
+                               acptr->from->confs, acptr->user->server,
+                               CONF_UWORLD)))
+                               acptr->flags |= FLAGS_ULINE;
+                       else
+                               acptr->flags &= ~FLAGS_ULINE;
+               }
+       reset_help(); /* Reinitialize help-system. -Donwulff */
+       return ret;
+}
+
+/*
+ * openconf
+ *
+ * returns -1 on any error or else the fd opened from which to read the
+ * configuration file from.  This may either be th4 file direct or one end
+ * of a pipe from m4.
+ */
+int    openconf()
+{
+#ifdef M4_PREPROC
+       int     pi[2], i;
+
+       if (pipe(pi) == -1)
+               return -1;
+       switch(fork())
+       {
+       case -1 :
+               return -1;
+       case 0 :
+               (void)close(pi[0]);
+               if (pi[1] != 1)
+                   {
+                       (void)dup2(pi[1], 1);
+                       (void)close(pi[1]);
+                   }
+               (void)dup2(1,2);
+               for (i = 3; i < MAXCONNECTIONS; i++)
+                       if (local[i])
+                               (void) close(i);
+               /*
+                * m4 maybe anywhere, use execvp to find it.  Any error
+                * goes out with report_error.  Could be dangerous,
+                * two servers running with the same fd's >:-) -avalon
+                */
+               (void)execlp("m4", "m4", "ircd.m4", configfile, 0);
+               report_error("Error executing m4 %s:%s", &me);
+               exit(-1);
+       default :
+               (void)close(pi[1]);
+               return pi[0];
+       }
+#else
+       return open(configfile, O_RDONLY);
+#endif
+}
+extern char *getfield();
+
+#define STAR1 OFLAG_SADMIN|OFLAG_ADMIN|OFLAG_NETADMIN|OFLAG_COADMIN
+#define STAR2 OFLAG_TECHADMIN|OFLAG_ZLINE|OFLAG_AGENT|OFLAG_HIDE|OFLAG_WHOIS
+#define STAR3 OFLAG_INVISIBLE
+static int oper_access[] = {
+    ~(STAR1|STAR2|STAR3), '*',
+       OFLAG_LOCAL,    'o',
+       OFLAG_GLOBAL,   'O',
+       OFLAG_REHASH,   'r',
+       OFLAG_EYES,     'e',
+       OFLAG_DIE,      'D',
+       OFLAG_RESTART,  'R',
+       OFLAG_HELPOP,   'h',
+       OFLAG_GLOBOP,   'g',
+       OFLAG_WALLOP,   'w',
+       OFLAG_LOCOP,    'l',
+       OFLAG_LROUTE,   'c',
+       OFLAG_GROUTE,   'L',
+       OFLAG_LKILL,    'k',
+       OFLAG_GKILL,    'K',
+       OFLAG_KLINE,    'b',
+       OFLAG_UNKLINE,  'B',
+       OFLAG_LNOTICE,  'n',
+       OFLAG_GNOTICE,  'G',
+       OFLAG_ADMIN,    'A',
+       OFLAG_SADMIN,   'a',
+       OFLAG_NETADMIN, 'N',
+       OFLAG_COADMIN,  'C',
+       OFLAG_TECHADMIN, 'T',
+       OFLAG_UMODEC,   'u',
+       OFLAG_UMODEF,   'f',
+       OFLAG_ZLINE,    'z',
+       OFLAG_WHOIS,    'W',
+        OFLAG_HIDE,     'H',
+        OFLAG_AGENT,   'S',
+       OFLAG_INVISIBLE, '^',
+       0, 0 };
+
+char   oflagbuf[128];
+
+char   *oflagstr(long oflag)
+{
+       int   *i, flag;
+       char  m;
+       char  *p = oflagbuf;
+               
+       for (i = &oper_access[6], m = *(i + 1); (flag = *i); i += 2, m = *(i + 1))
+       {
+                         if (oflag & flag)
+                         {
+                               *p = m;
+                               p++;
+                         }   
+       }
+       *p = '\0';
+       return oflagbuf;
+}
+
+/*
+** initconf() 
+**    Read configuration file.
+**
+**    returns -1, if file cannot be opened
+**             0, if file opened
+*/
+
+#define MAXCONFLINKS 150
+
+int    initconf(opt)
+int    opt;
+{
+       static  char    quotes[9][2] = {{'b', '\b'}, {'f', '\f'}, {'n', '\n'},
+                                       {'r', '\r'}, {'t', '\t'}, {'v', '\v'},
+                                       {'\\', '\\'}, { 0, 0}};
+       Reg1    char    *tmp, *s;
+       int     fd, i;
+       char    line[512], c[80];
+       int     ccount = 0, ncount = 0;
+       aConfItem *aconf = NULL;
+
+       Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
+       if ((fd = openconf()) == -1)
+           {
+#ifdef M4_PREPROC
+               (void)wait(0);
+#endif
+               return -1;
+           }
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
+           {
+               line[i] = '\0';
+               if ((tmp = (char *)index(line, '\n')))
+                       *tmp = 0;
+               else while(dgets(fd, c, sizeof(c) - 1) > 0)
+                       if ((tmp = (char *)index(c, '\n')))
+                           {
+                               *tmp = 0;
+                               break;
+                           }
+               /*
+                * 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++)
+                                               ;
+                           }
+                       else if (*tmp == '#')
+                               *tmp = '\0';
+                   }
+               if (!*line || line[0] == '#' || line[0] == '\n' ||
+                   line[0] == ' ' || line[0] == '\t')
+                       continue;
+               
+               /* Could we test if it's conf line at all?      -Vesa */
+               if (line[1] != ':')
+                   {
+                        Debug((DEBUG_ERROR, "Bad config line: %s", line));
+                        continue;
+                    }
+               if (aconf)
+                       free_conf(aconf);
+               aconf = make_conf();
+
+               tmp = getfield(line);
+               if (!tmp)
+                       continue;
+               switch (*tmp)
+               {
+                       case 'A': /* Name, e-mail address of administrator */
+                               aconf->status = CONF_ADMIN;
+                               break;
+                       case 'a': /* of this server. */
+                               aconf->status = CONF_SADMIN;
+                               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 'e':
+                               aconf->status = CONF_SOCKSEXCEPT;
+                               break;
+                       case 'E':
+                               aconf->status = CONF_EXCEPT;
+                               break;
+                       case 'G':
+                       case 'g':
+                         /* General config options */
+                         aconf->status = CONF_CONFIG;
+                         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 ircd.conf */
+                       case 'k':
+                               aconf->status = CONF_KILL;
+                               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)
+                        * Not anymore, OperFlag access levels. -Cabal95 */
+                       case 'o':
+                               aconf->status = CONF_OPERATOR;
+                               break;
+                       case 'P': /* listen port line */
+                       case 'p':
+                               aconf->status = CONF_LISTEN_PORT;
+                               break;
+                       case 'Q': /* reserved nicks */
+                               aconf->status = CONF_QUARANTINED_NICK;
+                               break;
+                       case 'q': /* a server that you don't want in your */
+                                 /* network. USE WITH CAUTION! */
+                               aconf->status = CONF_QUARANTINED_SERVER;
+
+                               break;
+                       case 'S': /* Service. Same semantics as   */
+                       case 's': /* CONF_OPERATOR                */
+                               aconf->status = CONF_SERVICE;
+                               break;
+                       case 'T':
+                               aconf->status = CONF_TLINE;
+                               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;
+                       case 'Z':
+                       case 'z':
+                               aconf->status = CONF_ZAP;
+                               break;
+                       case 'X':
+                       case 'x':
+                               aconf->status = CONF_DRPASS;
+                               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 */
+                   {
+                       /* Yes I know this could be much cleaner, but I did not
+                        * want to put it into its own separate function, but  
+                        * I believe the X:should be like this:
+                        * X:restartpass:diepass
+                        * which leaves this code untouched. This is already indented
+                        * enough to justify that...
+                        */
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       DupString(aconf->host, tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       DupString(aconf->passwd, tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       DupString(aconf->name, tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       if (aconf->status & CONF_OPS) {
+                         int   *i, flag;
+                         char  *m = "*";
+                         /*
+                          * Now we use access flags to define
+                          * what an operator can do with their O.
+                          */
+                         for (m = (*tmp) ? tmp : m; *m; m++) {
+                           for (i = oper_access; (flag = *i); i += 2)
+                             if (*m == (char)(*(i+1))) {
+                               aconf->port |= flag;
+                               break;
+                             }
+                         }
+                         if (!(aconf->port&OFLAG_ISGLOBAL))
+                               aconf->status = CONF_LOCOP;
+                       }
+                       else
+                               aconf->port = atoi(tmp);
+                       if ((tmp = getfield(NULL)) == NULL)
+                               break;
+                       Class(aconf) = find_class(atoi(tmp));
+                       break;
+                   }
+               /*
+               ** If conf line is a general config, just
+               ** see if we recognize the keyword, and set
+               ** the appropriate global.  We don't use a "standard"
+               ** config link here, because these are things which need
+               ** to be tested SO often that a simple global test
+               ** is much better!  -Aeto
+               */
+               if ((aconf->status & CONF_CONFIG) == CONF_CONFIG) {
+                 continue;
+               }
+
+               /* Check for bad Z-lines masks as they are *very* dangerous
+                  if not correct!!! */
+               if (aconf->status == CONF_ZAP)
+               {
+                       char *tempc = aconf->host;
+                       if (!tempc)
+                       {
+                               free_conf(aconf);
+                               aconf = NULL;
+                               continue;
+                       }
+                       for (; *tempc; tempc++)
+                               if ((*tempc >= '0') && (*tempc <= '9'))
+                                       goto zap_safe;
+                       free_conf(aconf);
+                       aconf = NULL;
+                       continue;
+                       zap_safe:;
+               }
+               /*
+               ** T:Line protection stuff..
+               **
+               **
+               */
+               if (aconf->status & CONF_TLINE)
+               {
+                       if (*aconf->passwd == '/')
+                               goto badtline;
+                       if (strstr(aconf->passwd, ".."))
+                               goto badtline;
+                       if (strchr(aconf->passwd, '~'))
+                               goto badtline;
+                       if (!strcmp(aconf->passwd, configfile) || !strcmp(aconf->name, configfile))
+                               goto badtline;
+                       if (!strcmp(aconf->passwd, CPATH) || !strcmp(aconf->name, CPATH))
+                               goto badtline;
+                       if (!strcmp(aconf->passwd, ZCONF) || !strcmp(aconf->name, ZCONF))
+                               goto badtline;
+                       if (!strcmp(aconf->passwd, OPATH) || !strcmp(aconf->name, OPATH))
+                               goto badtline;
+                       if (!strcmp(aconf->passwd, lPATH) || !strcmp(aconf->name, lPATH))
+                               goto badtline;
+                       
+                       goto tline_safe;
+               badtline:
+                       free_conf(aconf);
+                       aconf = NULL;
+                       continue;
+               tline_safe:;
+               }
+               /*
+                ** 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)
+                   {
+                       add_class(atoi(aconf->host), atoi(aconf->passwd),
+                                 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 (Class(aconf) == 0)
+                               Class(aconf) = find_class(0);
+                       if (MaxLinks(Class(aconf)) < 0)
+                               Class(aconf) = 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)
+                                   {
+                                       bconf->class->links -= bconf->clients;
+                                       bconf->class = aconf->class;
+                                        if (bconf->class)
+                                        bconf->class->links += bconf->clients;
+                                   }
+                               free_conf(aconf);
+                               aconf = bconf;
+                           }
+                       else if (aconf->host &&
+                                aconf->status == CONF_LISTEN_PORT)
+                               (void)add_listener(aconf);
+                   }
+               if (aconf->status & CONF_SERVER_MASK)
+                       if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS ||
+                           !aconf->host || !aconf->name)
+                               continue;
+
+               if (aconf->status &
+                   (CONF_SERVER_MASK|CONF_LOCOP|CONF_OPERATOR))
+                       if (!index(aconf->host, '@') && *aconf->host != '/')
+                           {
+                               char    *newhost;
+                               int     len = 3;        /* *@\0 = 3 */
+
+                               len += strlen(aconf->host);
+                               newhost = (char *)MyMalloc(len);
+                               (void)sprintf(newhost, "*@%s", aconf->host);
+                               MyFree(aconf->host);
+                               aconf->host = newhost;
+                           }
+               if (aconf->status & CONF_SERVER_MASK)
+                   {
+                       if (BadPtr(aconf->passwd))
+                               continue;
+                       else
+                       if (!(opt & BOOT_QUICK))
+                               (void)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))
+                 {
+                   MyFree (aconf->passwd);
+                   if ((aconf->passwd =
+                        (char *) crule_parse (aconf->name)) == NULL)
+                     {
+                       free_conf (aconf);
+                       aconf = NULL;
+                       continue;
+                     }
+                 }
+
+               /*
+               ** Own port and name cannot be changed after the startup.
+               ** (or could be allowed, but only if all links are closed
+               ** first).
+               ** Configuration info does not override the name and port
+               ** if previously defined. Note, that "info"-field can be
+               ** changed by "/rehash".
+               */
+               if (aconf->status == CONF_ME)
+                   {
+                       strncpyzt(me.info, aconf->name, sizeof(me.info));
+                       if (me.name[0] == '\0' && aconf->host[0])
+                               strncpyzt(me.name, aconf->host,
+                                         sizeof(me.name));
+                       if (aconf->passwd[0] && (aconf->passwd[0] != '*'))
+                               me.ip.s_addr = inet_addr(aconf->passwd);
+                       else
+                               me.ip.s_addr = INADDR_ANY;
+                       if (portnum < 0 && aconf->port >= 0)
+                               portnum = aconf->port;
+                   }
+               if (aconf->status == CONF_EXCEPT)
+                       aconf->tmpconf = KLINE_EXCEPT;
+               if (aconf->status == CONF_KILL)
+                       aconf->tmpconf = KLINE_PERM;
+               (void)collapse(aconf->host);
+               (void)collapse(aconf->name);
+               Debug((DEBUG_NOTICE,
+                     "Read Init: (%d) (%s) (%s) (%s) (%d) (%d)",
+                     aconf->status, aconf->host, aconf->passwd,
+                     aconf->name, aconf->port, Class(aconf)));
+               aconf->next = conf;
+               conf = aconf;
+               aconf = NULL;
+           }
+       if (aconf)
+               free_conf(aconf);
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       (void)close(fd);
+#ifdef M4_PREPROC
+       (void)wait(0);
+#endif
+       check_class();
+       nextping = nextconnect = TStime();
+       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(aconf)
+Reg1   aConfItem       *aconf;
+{
+       Reg2    char    *s;
+       Reg3    struct  hostent *hp;
+       Link    ln;
+
+       if (BadPtr(aconf->host) || BadPtr(aconf->name))
+               goto badlookup;
+       if ((s = index(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)))
+               bcopy(hp->h_addr, (char *)&(aconf->ipnum),
+                       sizeof(struct in_addr));
+
+       if (aconf->ipnum.s_addr == -1)
+               goto badlookup;
+       return 0;
+badlookup:
+       if (aconf->ipnum.s_addr == -1)
+               bzero((char *)&aconf->ipnum, sizeof(struct in_addr));
+       Debug((DEBUG_ERROR,"Host/server name error: (%s) (%s)",
+               aconf->host, aconf->name));
+       return -1;
+}
+
+int    find_kill(cptr)
+aClient        *cptr;
+{
+       char    reply[256], *host, *name;
+       aConfItem *tmp;
+
+       if (!cptr->user)
+               return 0;
+
+       host = cptr->sockhost;
+       name = cptr->user->username;
+
+       if (strlen(host)  > (size_t) HOSTLEN ||
+            (name ? strlen(name) : 0) > (size_t) HOSTLEN)
+               return (0);
+
+       reply[0] = '\0';
+
+       for (tmp = conf; tmp; tmp = tmp->next)
+               if ((tmp->status == CONF_EXCEPT) && tmp->host && tmp->name &&
+                   (match(tmp->host, host) == 0) &&
+                   (!name || match(tmp->name, name) == 0) &&
+                   (!tmp->port || (tmp->port == cptr->acpt->port)))
+                       /* can short-circuit evaluation - not taking chances
+                           cos check_time_interval destroys tmp->passwd
+                                                                - Mmmm
+                         */
+                        if (BadPtr(tmp->passwd))
+                                break;
+                        else if (is_comment(tmp->passwd))
+                                break;
+                        else if (check_time_interval(tmp->passwd, reply))
+                                break;
+
+
+       if (tmp) {
+               /* This is an E:Line */
+               return 0;
+       }
+       
+       for (tmp = conf; tmp; tmp = tmp->next)
+               if ((tmp->status == CONF_KILL) && tmp->host && tmp->name &&
+                   (match(tmp->host, host) == 0) &&
+                   (!name || match(tmp->name, name) == 0) &&
+                   (!tmp->port || (tmp->port == cptr->acpt->port)))
+                       /* can short-circuit evaluation - not taking chances
+                           cos check_time_interval destroys tmp->passwd
+                                                                - Mmmm
+                         */
+                        if (BadPtr(tmp->passwd))
+                                break;
+                        else if (is_comment(tmp->passwd))
+                                break;
+                        else if (check_time_interval(tmp->passwd, reply))
+                                break;
+
+
+       if (reply[0])
+               sendto_one(cptr,reply,
+                          me.name, ERR_YOUREBANNEDCREEP, cptr->name, KLINE_ADDRESS);
+       else if (tmp)
+            if (BadPtr(tmp->passwd))
+               sendto_one(cptr,
+                          ":%s %d %s :*** You are not welcome on this server."
+                          "  Email %s for more information.",
+                          me.name, ERR_YOUREBANNEDCREEP, cptr->name, KLINE_ADDRESS);
+             else
+#ifdef COMMENT_IS_FILE
+                   m_killcomment(cptr,cptr->name, tmp->passwd);
+#else
+            {
+             if (*tmp->passwd == '|' && !strchr(tmp->passwd, '/') && match("|kc.*", tmp->passwd))
+             {
+                       m_killcomment(cptr, cptr->name, (tmp->passwd) + 1);
+             } 
+              else
+             if (tmp->tmpconf == KLINE_AKILL)
+              sendto_one(cptr,
+                         ":%s %d %s :*** %s",
+                         me.name, ERR_YOUREBANNEDCREEP, cptr->name,
+                         tmp->passwd);
+             else
+              sendto_one(cptr,
+                         ":%s %d %s :*** You are not welcome on this server: "
+                        "%s.  Email %s for more information.",
+                         me.name, ERR_YOUREBANNEDCREEP, cptr->name,
+                         tmp->passwd, KLINE_ADDRESS);
+            }
+#endif  /* COMMENT_IS_FILE */
+
+       return (tmp ? -1 : 0);
+}
+
+char *find_zap(aClient *cptr, int dokillmsg)  
+{
+       aConfItem *tmp;
+       char *retval = NULL;
+       for (tmp = conf; tmp; tmp = tmp->next)
+               if ((tmp->status == CONF_ZAP) && tmp->host &&
+                       !match(tmp->host, inetntoa((char *) &cptr->ip)))
+                       {
+                               retval = (tmp->passwd) ? tmp->passwd :
+                                       "Reason unspecified";
+                               break;
+                       }
+       if (dokillmsg && retval)
+               sendto_one(cptr,
+                       ":%s %d %s :*** You are not welcome on this server: "
+                       "%s.  Email %s for more information.",
+                       me.name, ERR_YOUREBANNEDCREEP, cptr->name,
+                       retval, KLINE_ADDRESS);
+       if (!dokillmsg && retval)
+       {
+               sprintf(zlinebuf,
+                       "ERROR :Closing Link: [%s] (You are not welcome on "
+                       "this server: %s.  Email %s for more"
+                       " information.)\r\n", inetntoa((char *) &cptr->ip),
+                       retval, KLINE_ADDRESS);
+               retval = zlinebuf;
+       }
+       return retval;
+}
+
+int    find_kill_byname(host, name)
+char *host, *name;
+{
+       aConfItem *tmp;
+
+       for (tmp = conf; tmp; tmp = tmp->next) {
+               if ((tmp->status == CONF_KILL) && tmp->host && tmp->name &&
+                   (match(tmp->host, host) == 0) &&
+                   (!name || match(tmp->name, name) == 0))
+               return 1;
+       }
+
+       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
+*/
+int     m_killcomment(sptr, parv, filename)
+aClient *sptr;
+char    *parv, *filename;
+{
+      int     fd;
+      char    line[80];
+      Reg1    char     *tmp;
+      struct  stat    sb;
+      struct  tm      *tm;
+
+      /*
+       * stop NFS hangs...most systems should be able to open a file in
+       * 3 seconds. -avalon (curtesy of wumpus)
+       */
+      fd = open(filename, O_RDONLY);
+      if (fd == -1)
+          {
+              sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
+              sendto_one(sptr,
+                         ":%s %d %s :*** You are not welcome to this server.",
+                         me.name, ERR_YOUREBANNEDCREEP, parv);
+              return 0;
+          }
+      (void)fstat(fd, &sb);
+      tm = localtime(&sb.st_mtime);
+      (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+      while (dgets(fd, line, sizeof(line)-1) > 0)
+          {
+              if ((tmp = (char *)index(line,'\n')))
+                      *tmp = '\0';
+              if ((tmp = (char *)index(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 :*** You are not welcome to this server.",
+                   me.name, ERR_YOUREBANNEDCREEP, parv);
+      (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+      (void)close(fd);
+      return 0;
+  }
+
+
+/*
+** is the K line field an interval or a comment? - Mmmm
+*/
+
+static int is_comment(comment)
+char   *comment;
+{
+       int i;
+        for (i=0; i<strlen(comment); i++)
+          if ( (comment[i] != ' ') && (comment[i] != '-')
+                                     && (comment[i] != ',') 
+                  &&  ( (comment[i] < '0') || (comment[i] > '9') ) )
+                       return(1);
+
+       return(0);
+}
+
+
+/*
+** check against a set of time intervals
+*/
+
+static int     check_time_interval(interval, reply)
+char   *interval, *reply;
+{
+       struct tm *tptr;
+       time_t  tick;
+       char    *p;
+       int     perm_min_hours, perm_min_minutes,
+               perm_max_hours, perm_max_minutes;
+       int     now, perm_min, perm_max;
+
+       tick = TStime();
+       tptr = localtime(&tick);
+       now = tptr->tm_hour * 60 + tptr->tm_min;
+
+       while (interval)
+           {
+               p = (char *)index(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 <= now && now <= perm_max)
+                   : (perm_min <= now || now <= perm_max))
+                   {
+                       (void)sprintf(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 <= now + 5 && now + 5 <= perm_max)
+                   : (perm_min <= now + 5 || now + 5 <= perm_max))
+                   {
+                       (void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
+                               perm_min-now,(perm_min-now)>1?"s ":" ",
+                               "and you will be denied for further access");
+                       return(ERR_YOUWILLBEBANNED);
+                   }
+               interval = p;
+           }
+       return(0);
+}
+
+/*
+** m_rakill;
+**      parv[0] = sender prefix
+**      parv[1] = hostmask
+**      parv[2] = username
+**      parv[3] = comment
+*/
+int     m_rakill(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *hostmask, *usermask;
+        int     result;
+
+        if (check_registered(sptr))
+                return 0;
+
+        if (parc < 2 && IsPerson(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "AKILL");
+                return 0;
+            }
+
+        if (IsServer(sptr) && parc < 3)
+                return 0;
+
+        if (!IsServer(cptr))
+          {
+                if (!IsOper(sptr))
+                    {
+                        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
+                                sptr->name);
+                        return 0;
+                    }
+                else
+                    {
+                        if ((hostmask = (char *)index(parv[1], '@')))
+                          {
+                            *hostmask = 0;
+                            hostmask++;
+                            usermask = parv[1];
+                          }
+                        else
+                          {
+                            sendto_one(sptr, ":%s NOTICE %s :%s", me.name,
+                              sptr->name, "Please use a user@host mask.");
+                            return 0;
+                          }
+                    }
+          }
+        else
+          {
+            hostmask = parv[1];
+            usermask = parv[2];
+          }
+
+        if (!usermask || !hostmask)
+          {
+           /*
+            * This is very bad, it should never happen.
+            */
+            sendto_ops("Error adding akill from %s!", sptr->name);
+            return 0;
+          }
+
+        result = del_temp_conf(CONF_KILL, hostmask, NULL, usermask, 0, 0, 2);
+        if (result == KLINE_DEL_ERR)
+          {
+            if (!MyClient(sptr))
+              {
+                sendto_serv_butone(cptr, ":%s RAKILL %s %s",
+                  IsServer(cptr) ? parv[0] : me.name, hostmask, usermask);
+                return 0;
+              }
+            sendto_one(sptr, ":%s NOTICE %s :Akill %s@%s does not exist.",
+              me.name, sptr->name, usermask, hostmask);
+            return 0;
+          }
+
+        if (MyClient(sptr))
+          {
+            sendto_ops("%s removed akill for %s@%s",
+              sptr->name, usermask, hostmask);
+            sendto_serv_butone(&me,
+              ":%s GLOBOPS :%s removed akill for %s@%s",
+              me.name, sptr->name, usermask, hostmask);
+          }
+
+        sendto_serv_butone(cptr, ":%s RAKILL %s %s",
+                IsServer (cptr) ? parv[0] : me.name,
+                hostmask, usermask);
+
+        check_pings(TStime(), 1);
+    }
+
+/* ** m_akill;
+**     parv[0] = sender prefix
+**     parv[1] = hostmask
+**     parv[2] = username
+**     parv[3] = comment
+*/
+int    m_akill(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+        char    *hostmask, *usermask, *comment;
+
+        if (check_registered(sptr))
+                return 0;
+
+        if (parc < 2 && IsPerson(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "AKILL");
+                return 0;
+            }
+
+        if (IsServer(sptr) && parc < 3)
+                return 0;
+
+        if (!IsServer(cptr))
+          {
+                if (!IsOper(sptr))
+                    {
+                        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
+                                sptr->name);
+                        return 0;
+                    }
+                else
+                    {
+                        comment = parc < 3 ? NULL : parv[2];
+                        if ((hostmask = (char *)index(parv[1], '@')))
+                          {
+                            *hostmask = 0;
+                            hostmask++;
+                            usermask = parv[1];
+                          }
+                        else
+                          {
+                            sendto_one(sptr, ":%s NOTICE %s :%s", me.name,
+                              sptr->name, "Please use a nick!user@host mask.");
+                            return 0;
+                          }
+                        if (!strcmp(usermask, "*") || !strchr(hostmask, '.'))
+                {
+                        sendto_one (sptr, "NOTICE %s :*** What a sweeping AKILL.  If only your admin knew you tried that..", parv[0]);
+                       sendto_realops("%s attempted to /akill *@*", parv[0]);
+                        return 0;
+                }
+                        if (MyClient(sptr))
+                          {
+                            sendto_ops("%s added akill for %s@%s (%s)",
+                              sptr->name, usermask, hostmask,
+                              !BadPtr(comment) ? comment : "no reason");
+                            sendto_serv_butone(&me,
+                              ":%s GLOBOPS :%s added akill for %s@%s (%s)",
+                              me.name, sptr->name, usermask, hostmask,
+                              !BadPtr(comment) ? comment : "no reason");
+                          }
+                    }
+          }
+        else
+          {
+            hostmask = parv[1];
+            usermask = parv[2];
+            comment = parc < 4 ? NULL : parv[3];
+          }
+
+        if (!usermask || !hostmask)
+          {
+           /*
+            * This is very bad, it should never happen.
+            */
+            sendto_ops("Error adding akill from %s!", sptr->name);
+            return 0;
+          }
+
+        if (!find_kill_byname(hostmask, usermask))
+        {
+
+#ifndef COMMENT_IS_FILE
+                add_temp_conf(CONF_KILL, hostmask, comment, usermask, 0, 0, 2);
+#else
+                add_temp_conf(CONF_KILL, hostmask, NULL, usermask, 0, 0, 2);
+#endif
+        }
+
+        if (comment)
+                sendto_serv_butone(cptr, ":%s AKILL %s %s :%s",
+                        IsServer(cptr) ? parv[0] : me.name, hostmask,
+                        usermask, comment);
+        else
+                sendto_serv_butone(cptr, ":%s AKILL %s %s",
+                        IsServer (cptr) ? parv[0] : me.name,
+                        hostmask, usermask);
+
+
+        check_pings(TStime(), 1);
+
+    }
+
+/*    m_sqline
+**     parv[0] = sender
+**     parv[1] = nickmask
+**     parv[2] = reason
+*/
+int    m_sqline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1 aSqlineItem *asqline;
+
+       if (!IsServer(sptr) || parc < 2)
+               return 0;
+
+       if(parv[2])
+               sendto_serv_butone(cptr, ":%s SQLINE %s :%s", parv[0],
+                            parv[1], parv[2]);
+       else
+               sendto_serv_butone(cptr, ":%s SQLINE %s", parv[0],
+                            parv[1]);
+
+       asqline = make_sqline();
+
+       if (parv[2])
+         DupString(asqline->reason, parv[2]);
+       if (parv[1])
+         DupString(asqline->sqline, parv[1]);
+
+       if (!find_sqline_nick(parv[1])) {
+               asqline->next = sqline;
+               sqline = asqline;
+               asqline = NULL;
+       }
+
+       if (asqline)
+         free_sqline(asqline);
+}
+
+/*    m_unsqline
+**     parv[0] = sender
+**     parv[1] = nickmask
+*/
+int    m_unsqline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1 aSqlineItem *asqline;
+
+       if (!IsServer(sptr) || parc < 1)
+               return 0;
+
+       sendto_serv_butone(cptr, ":%s UNSQLINE %s", parv[0],
+                    parv[1]);
+
+       if(!(asqline = find_sqline_nick(parv[1])))
+               return;
+
+       asqline->status = CONF_ILLEGAL;
+
+}
+
+/*
+** m_kline;
+**     parv[0] = sender prefix
+**     parv[1] = nickname
+**     parv[2] = comment or filename
+*/
+int    m_kline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       char *host, *tmp, *hosttemp;
+       char uhost[80], name[80];
+       int ip1, ip2, ip3, temp;
+       aClient *acptr;
+       FILE *aLog;
+
+        if (!MyClient(sptr) || !OPCanKline(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (parc < 2)
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "KLINE");
+               return 0;
+           }
+
+
+/* This patch allows opers to quote kline by address as well as nick
+ * --Russell
+ */
+       if (hosttemp = (char *) strchr((char *) parv[1], '@'))
+       {
+               temp = 0;
+               while (temp <= 20)
+                       name[temp++] = 0;
+               strcpy(uhost, ++hosttemp);
+               strncpy(name, parv[1], hosttemp-1-parv[1]);
+               if (name[0] == '\0' || uhost[0] == '\0')
+               {
+                       Debug((DEBUG_INFO, "KLINE: Bad field!"));
+                       sendto_one (sptr, "NOTICE %s :If you're going to add a userhost, at LEAST specify both fields", parv[0]);       
+                       return 0;
+               }
+               if (!strcmp(uhost, "*") || !strchr(uhost, '.'))
+               {
+                       sendto_one (sptr, "NOTICE %s :*** What a sweeping K:Line.  If only your admin knew you tried that..", parv[0]);
+                       sendto_realops("%s attempted to /kline *@*", parv[0]);
+                       return 0;
+               }
+       }       
+
+/* by nick */
+       else
+       {
+               if (!(acptr = find_client(parv[1], NULL))) {
+                       if (!(acptr = get_history(parv[1], (long)KILLCHASETIMELIMIT))) {
+                               sendto_one(sptr, "NOTICE %s :Can't find user %s to add KLINE",
+                                          parv[0], parv[1]);
+                               return 0;
+                       }
+               }
+
+               if (!acptr->user)
+                       return 0;
+
+               strcpy(name, acptr->user->username);
+               if (MyClient(acptr))
+                       host = acptr->sockhost;
+               else
+                       host = acptr->user->realhost;
+
+               /* Sanity checks */
+
+               if (name == '\0' || host == '\0')
+               {
+                       Debug((DEBUG_INFO, "KLINE: Bad field"));
+                       sendto_one(sptr, "NOTICE %s :Bad field!", parv[0]);
+                       return 0;
+               }
+
+               /* Add some wildcards */
+
+
+               strcpy(uhost, host);
+               if (isdigit(host[strlen(host)-1])) {
+                       if (sscanf(host, "%d.%d.%d.%*d", &ip1, &ip2, &ip3))
+                               sprintf(uhost, "%d.%d.%d.*", ip1, ip2, ip3);
+               }
+               else if (sscanf(host, "%*[^.].%*[^.].%s", uhost)) { /* Not really... */
+                       tmp = (char*)strchr(host, '.');
+                       sprintf(uhost, "*%s", tmp);
+               }
+       }
+
+       sendto_ops("%s added a temp k:line for %s@%s %s", parv[0], name, uhost, parv[2] ? parv[2] : "");
+       aLog = fopen(lPATH, "a");
+       if (aLog)
+       {
+               fprintf(aLog, "(%s) %s added a temp k:line for %s@%s %s", myctime(TStime()), parv[0], name, uhost, parv[2] ? parv[2] : "");
+               fclose(aLog);
+       }
+       
+       add_temp_conf(CONF_KILL, uhost, parv[2], name, 0, 0, 1);
+       check_pings(TStime(), 1);
+    }
+       
+
+/*
+ *  m_unkline
+ *    parv[0] = sender prefix
+ *    parv[1] = userhost
+ */
+
+int m_unkline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+
+       int     result, temp;
+       char    *hosttemp=parv[1], host[80], name[80];
+       FILE    *aLog;
+
+       if (!MyClient(sptr) || !OPCanUnKline(sptr))
+       {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+       }
+       if (parc<2)
+       {
+               sendto_one(sptr,"NOTICE %s :Not enough parameters", parv[0]);
+               return 0;
+       }
+        if (hosttemp = (char *) strchr((char *)parv[1], '@'))
+        {
+                temp = 0;
+                while (temp <= 20)
+                        name[temp++] = 0;
+                strcpy(host, ++hosttemp);
+                strncpy(name, parv[1], hosttemp-1-parv[1]);
+                if (name[0] == '\0' || host[0] == '\0')
+                {
+                        Debug((DEBUG_INFO, "UNKLINE: Bad field"));
+                       sendto_one(sptr, "NOTICE %s : Both user and host fields must be non-null", parv[0]);
+                       return 0;
+               }
+               result = del_temp_conf(CONF_KILL, host, NULL, name, 
+                       NULL, NULL, 0);
+               if (result == KLINE_RET_AKILL) {        /* akill - result = 3 */
+                       sendto_one(sptr, "NOTICE %s :You may not remove autokills.  Only U:lined clients may.", parv[0]);
+                       return 0;
+               }
+               if (result ==  KLINE_RET_PERM) {        /* Not a temporary line - result =2 */
+                       sendto_one(sptr,"NOTICE %s :You may not remove permanent K:Lines - talk to the admin", parv[0]);
+                       return 0;
+               }
+               if (result ==  KLINE_RET_DELOK)  {      /* Successful result = 1*/
+                       sendto_one(sptr,"NOTICE %s :Temp K:Line %s@%s is now removed.", parv[0],name,host);
+                       sendto_ops("%s removed temp k:line %s@%s", parv[0], name, host);
+                       aLog = fopen(lPATH, "a");
+                       if (aLog)
+                       {
+                               fprintf(aLog, "(%s) %s removed temp k:line %s@%s", myctime(TStime()), parv[0], name, host);                             
+                               fclose(aLog);
+                       }                       
+                       return 0;
+               }
+               if (result == KLINE_DEL_ERR) {  /* Unsuccessful result = 0*/
+                       sendto_one(sptr,"NOTICE %s :Temporary K:Line %s@%s not found", parv[0],name,host);
+                       return 0;
+               }
+       }
+       /* This wasn't here before -- Barubary */
+       check_pings(TStime(), 1);
+}
+
+/*
+ *  m_zline                       add a temporary zap line
+ *    parv[0] = sender prefix
+ *    parv[1] = host
+ *    parv[2] = reason
+ */
+
+int m_zline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+       char userhost[512+2]="", *in;
+       int result=0, uline=0, i=0, propo=0;
+       char *reason, *mask, *server, *person;
+       aClient *acptr;
+       
+       reason=mask=server=person=NULL;
+       
+       reason = ((parc>=3) ? parv[parc-1] : "Reason unspecified");
+       mask   = ((parc>=2) ? parv[parc-2] : NULL);
+       server   = ((parc>=4) ? parv[parc-1] : NULL);
+
+       if (parc == 4)
+       {
+             mask = parv[parc-3];
+             server = parv[parc-2];
+             reason = parv[parc-1];
+       }
+
+       uline = IsULine(cptr, sptr) ? 1 : 0;
+
+       if (!uline && (!MyConnect(sptr) || !OPCanZline(sptr) || !IsOper(sptr)))
+       {
+         sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+         return -1;
+       }
+
+       if (uline)
+       {
+         if (parc>=4 && server)
+         {
+           if (hunt_server(cptr, sptr, ":%s ZLINE %s %s :%s", 2, parc, parv)
+                != HUNTED_ISME)
+             return 0;
+           else    ;
+         }
+         else propo=1;
+       }
+
+       if (parc < 2)
+       {
+         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                    me.name, parv[0], "ZLINE");
+         return -1;
+       }
+
+       if (acptr = find_client(parv[1], NULL))
+       {
+         strcpy(userhost, inetntoa((char *) &acptr->ip));
+         person = &acptr->name[0];
+         acptr = NULL;
+       }
+     /* z-lines don't support user@host format, they only 
+        work with ip addresses and nicks */
+       else
+       if ((in = index(parv[1], '@')) && (*(in+1)!='\0'))
+       {
+         strcpy(userhost, in+1);
+         in = &userhost[0];
+         while(*in) 
+         { 
+           if (!isdigit(*in) && !ispunct(*in)) 
+           {
+             sendto_one(sptr, ":%s NOTICE %s :z:lines work only with ip addresses (you cannot specify ident either)", me.name, sptr->name);
+             return;
+           }
+           in++;
+           }
+         } else if (in && !(*(in+1))) /* sheesh not only specifying a ident@, but
+                                   omitting the ip...?*/
+         {
+           sendto_one(sptr, ":%s NOTICE %s :Hey! z:lines need an ip address...",
+                       me.name, sptr->name);
+           return -1;
+         }
+       else
+       {
+         strcpy(userhost, parv[1]);
+         in = &userhost[0];
+         while(*in) 
+         { 
+           if (!isdigit(*in) && !ispunct(*in)) 
+           {
+              sendto_one(sptr, ":%s NOTICE %s :z:lines work only with ip addresses (you cannot specify ident either)", me.name, sptr->name);
+              return;
+           }
+           in++;
+         }
+       }
+    
+          /* this'll protect against z-lining *.* or something */
+       if (advanced_check(userhost, TRUE) == FALSE)
+       { 
+         sendto_ops("Bad z:line mask from %s *@%s [%s]", parv[0], userhost, reason?reason:"");
+         if (MyClient(sptr))
+         sendto_one(sptr, ":%s NOTICE %s :*@%s is a bad z:line mask...", me.name, sptr->name, userhost);
+         return;
+        }
+
+       if (uline == 0)
+       {
+         if (person)
+           sendto_ops("%s added a temp z:line for %s (*@%s) [%s]", parv[0], person, userhost, reason?reason:"");
+         else
+           sendto_ops("%s added a temp z:line *@%s [%s]", parv[0], userhost, reason?reason:"");
+         (void) add_temp_conf(CONF_ZAP, userhost,  reason, NULL, 0, 0, KLINE_TEMP); 
+        }
+       else
+        {
+        if (person)
+          sendto_ops("%s z:lined %s (*@%s) on %s [%s]", parv[0], person, userhost, server?server:ircnetwork , reason?reason:"");
+        else
+          sendto_ops("%s z:lined *@%s on %s [%s]", parv[0], userhost, server?server:ircnetwork , reason?reason:"");
+         (void) add_temp_conf(CONF_ZAP, userhost,  reason, NULL, 0, 0, KLINE_AKILL); 
+        }
+
+                                           /* something's wrong if i'm
+                                              zapping the command source... */
+       if (find_zap(cptr, 0)||find_zap(sptr, 0))
+       {
+             sendto_failops_whoare_opers("z:line error: mask=%s parsed=%s I tried to zap cptr", mask, userhost);
+             sendto_serv_butone(NULL,":%s GLOBOPS :z:line error: mask=%s parsed=%s I tried to zap cptr", me.name, mask, userhost);
+             flush_connections(me.fd);
+             (void)rehash(&me, &me, 0);
+             return;
+       }
+#ifdef PRECISE_CHECK
+       for (i=highest_fd;i>0;i--)
+       {
+         if (!(acptr = local[i]) || IsLog(acptr) || IsMe(acptr));
+            continue;
+#else
+       for (acptr = &me; acptr; acptr = acptr->prev)
+       {
+               if (IsMe(cptr) || !MyClient(cptr) || IsLog(cptr))
+                       continue;
+#endif
+
+         if (  find_zap(acptr, 1) )
+          {
+           if (!IsServer(acptr))
+           {
+               sendto_one(sptr,":%s NOTICE %s :*** %s %s",
+                          me.name, sptr->name, 
+                         acptr->name[0]?acptr->name:"<unknown>");
+               exit_client(acptr, acptr, acptr, "z-lined");
+           }
+           else
+           {
+             sendto_one(sptr, ":%s NOTICE %s :*** exiting %s",
+                        me.name, sptr->name, acptr->name);
+             sendto_ops("dropping server %s (z-lined)", acptr->name);
+             sendto_serv_butone(cptr, "GNOTICE :dropping server %s (z-lined)",
+                                acptr->name);
+             exit_client(acptr, acptr, acptr, "z-lined");
+
+           }
+         }
+       }
+
+       if (propo==1)      /* propo is if a ulined server is propagating a z-line
+                             this should go after the above check */
+            sendto_serv_butone(cptr, ":%s ZLINE %s :%s", parv[0], parv[1], reason?reason:"");
+
+        check_pings(TStime(), 1);
+
+}
+
+
+/*
+ *  m_unzline                        remove a temporary zap line
+ *    parv[0] = sender prefix
+ *    parv[1] = host
+ */
+
+int m_unzline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+char userhost[512+2]="", *in;
+int result=0, uline=0, akill=0;
+aConfItem *aconf, *tmp;
+aConfItem dummy;
+char *mask, *server;
+
+uline = IsULine(cptr, sptr)? 1 : 0;
+
+   if (parc < 2)
+   {
+   sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+              me.name, parv[0], "UNZLINE");
+      return -1;
+   }
+
+
+ if (parc < 3 || !uline)
+ {
+     mask   = parv[parc-1];
+     server = NULL;
+ }
+ else if (parc == 3)
+ {
+     mask   = parv[parc-2];
+     server = parv[parc-1];
+ }
+
+   if (!uline && (!MyConnect(sptr) || !OPCanZline(sptr) || !IsOper(sptr)))
+   {
+       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+       return -1;
+   }
+
+   /* before we even check ourselves we need to do the uline checks
+      because we aren't supposed to add a z:line if the message is
+      destined to be passed on...*/
+
+   if (uline)
+   {
+     if (parc == 3 && server)
+     {
+        if (hunt_server(cptr, sptr, ":%s UNZLINE %s %s", 2, parc, parv) != HUNTED_ISME)
+                   return 0;
+        else    ;
+     }
+      else
+            sendto_serv_butone(cptr, ":%s UNZLINE %s", parv[0], parv[1]);
+
+   }
+
+
+   /* parse the removal mask the same way so an oper can just use
+      the same thing to remove it if they specified *@ or something... */
+   if ((in = index(parv[1], '@')))
+   {
+       strcpy(userhost, in+1);
+       in = &userhost[0];
+       while(*in) 
+       { 
+           if (!isdigit(*in) && !ispunct(*in)) 
+           {
+              sendto_one(sptr, ":%s NOTICE %s :it's not possible to have a z:line that's not an ip addresss...", me.name, sptr->name);
+              return;
+           }
+            in++;
+       }
+   }
+   else
+   {
+       strcpy(userhost, parv[1]);
+       in = &userhost[0];
+       while(*in) 
+       { 
+           if (!isdigit(*in) && !ispunct(*in)) 
+           {
+              sendto_one(sptr, ":%s NOTICE %s :it's not possible to have a z:line that's not an ip addresss...", me.name, sptr->name);
+              return;
+           }
+            in++;
+       }
+   }
+
+       akill = 0;
+retry_unzline:
+
+        if (uline == 0)
+        {
+           result = del_temp_conf(CONF_ZAP, userhost,  NULL, NULL, 0, 0, akill);
+         if ((result) == KLINE_RET_DELOK)
+          {
+             sendto_one(sptr,":%s NOTICE %s :temp z:line *@%s removed", me.name, parv[0], userhost);
+             sendto_ops("%s removed temp z:line *@%s", parv[0], userhost);
+          }
+          else if (result == KLINE_RET_PERM)
+              sendto_one(sptr, ":%s NOTICE %s :You may not remove permanent z:lines talk to your admin...", me.name, sptr->name);
+
+          else if (result == KLINE_RET_AKILL && !(sptr->umodes & UMODE_SADMIN))
+          {
+              sendto_one(sptr, ":%s NOTICE %s :You may not remove z:lines placed by services...", me.name, sptr->name);
+          }
+          else if (result == KLINE_RET_AKILL && !akill)
+          {
+             akill=1;
+             goto retry_unzline;
+          }
+          else
+              sendto_one(sptr, ":%s NOTICE %s :Couldn't find/remove zline for *@%s", me.name, sptr->name, userhost);
+
+        }
+        else    
+        {      /* services did it, services should be able to remove
+                  both types...;> */
+         if (del_temp_conf(CONF_ZAP, userhost,  NULL, NULL, 0, 0, 1) == KLINE_RET_DELOK||
+              del_temp_conf(CONF_ZAP, userhost,  NULL, NULL, 0, 0, 0) == KLINE_RET_DELOK)
+          {
+              if (MyClient(sptr))
+             sendto_one(sptr,"NOTICE %s :temp z:line *@%s removed", parv[0], userhost);
+             sendto_ops("%s removed temp z:line *@%s", parv[0], userhost);
+          }
+          else
+              sendto_one(sptr, ":%s NOTICE %s :ERROR Removing z:line", me.name, sptr->name);
+       }
+
+}
+
+
+/* ok, given a mask, our job is to determine
+ * wether or not it's a safe mask to banish...
+ *
+ * userhost= mask to verify
+ * ipstat= TRUE  == it's an ip
+ *         FALSE == it's a hostname
+ *         UNSURE == we need to find out
+ * return value
+ *         TRUE  == mask is ok
+ *         FALSE == mask is not ok
+ *        UNSURE == [unused] something went wrong
+ */
+
+advanced_check(char *userhost, int ipstat)
+{
+  register int retval = TRUE;
+  char *up, *p, *thisseg;
+  int  numdots=0, segno=0, numseg, i=0;
+  char *ipseg[10+2];
+  char safebuffer[512]=""; /* buffer strtoken() can mess up to its heart's content...;>*/
+
+  strcpy(safebuffer, userhost);
+
+#define userhost safebuffer
+#define IP_WILDS_OK(x) ((x)<2? 0 : 1)
+
+   if (ipstat == UNSURE)
+   {
+        ipstat=TRUE;
+        for (;*up;up++) 
+        {
+           if (*up=='.') numdots++;
+           if (!isdigit(*up) && !ispunct(*up)) {ipstat=FALSE; continue;}
+        }
+        if (numdots != 3) ipstat=FALSE;
+        if (numdots < 1 || numdots > 9)  return(0);
+   }
+
+     /* fill in the segment set */
+  {
+     int l = 0;
+        for (segno = 0, i = 0, thisseg = strtoken(&p, userhost, "."); thisseg;
+             thisseg = strtoken(&p, NULL, "."), i++)
+        {
+            
+            l = strlen(thisseg)+2;
+            ipseg[segno] = calloc(1, l);
+            strncpy(ipseg[segno++], thisseg, l);
+        }
+  }
+     if (segno < 2 && ipstat==TRUE) retval = FALSE;  
+     numseg = segno;
+     if (ipstat==TRUE)
+      for(i=0;i<numseg;i++)
+      {
+            if (!IP_WILDS_OK(i) && index(ipseg[i], '*')||index(ipseg[i], '?'))
+               retval=FALSE;            
+            MyFree(ipseg[i]);
+      }
+     else
+     {
+      int wildsok=0;
+
+      for(i=0;i<numseg;i++)
+      {
+             /* for hosts, let the mask extent all the way to 
+                the second-level domain... */
+           wildsok=1;
+           if (i==numseg||(i+1)==numseg) wildsok=0;
+           if (wildsok == 0 && (index(ipseg[i], '*')||index(ipseg[i], '?')))
+           {
+             retval=FALSE;
+           }
+            MyFree(ipseg[i]);
+      }
+
+
+     }
+
+           return(retval);
+#undef userhost
+#undef IP_WILDS_OK
+
+}
diff --git a/src/s_debug.c b/src/s_debug.c
new file mode 100644 (file)
index 0000000..3b4084a
--- /dev/null
@@ -0,0 +1,539 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/s_debug.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.
+ */
+
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_debug.c 2.30 1/3/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+/*
+ * Option string.  Must be before #ifdef DEBUGMODE.
+ */
+char   serveropts[] = {
+#ifdef SENDQ_ALWAYS
+'A',
+#endif
+#ifdef CHROOTDIR
+'c',
+#endif
+#ifdef CMDLINE_CONFIG
+'C',
+#endif
+#ifdef DO_ID
+'d',
+#endif
+#ifdef DEBUGMODE
+'D',
+#endif
+#ifdef NOTE_FORWARDER
+'f',
+#endif
+#ifndef        NO_FDLIST
+'F',
+#endif
+#ifdef HUB
+'h',
+#endif
+#ifdef SHOW_INVISIBLE_LUSERS
+'i',
+#endif
+#ifndef        NO_DEFAULT_INVISIBLE
+'I',
+#endif
+#ifdef LEAST_IDLE
+'L',
+#endif
+#ifdef M4_PREPROC
+'m',
+#endif
+#ifdef IDLE_FROM_MSG
+'M',
+#endif
+#ifdef CRYPT_OPER_PASSWORD
+'p',
+#endif
+#ifdef CRYPT_LINK_PASSWORD
+'P',
+#endif
+#ifdef NOSPOOF
+'n',
+#endif
+#ifdef NPATH
+'N',
+#endif
+#ifdef SCRIPTINIFIX
+'s',
+#endif
+#ifdef ENABLE_SUMMON
+'S',
+#endif
+#ifdef IRCII_KLUDGE
+'u',
+#endif
+#ifdef ENABLE_USERS
+'U',
+#endif
+#ifdef VALLOC
+'V',
+#endif
+#ifdef REMOVE_ADVERTISING
+'R',
+#endif
+#ifdef _WIN32
+'W',
+#endif
+#ifdef USE_SYSLOG
+'Y',
+#endif
+#ifdef V28PlusOnly
+'8',
+#endif
+#ifdef SCRIPTINIFIX
+'S',
+#endif
+#ifdef OPER_NO_HIDING
+'H',
+#endif
+'\0'};
+
+#include "numeric.h"
+#include "common.h"
+#include "sys.h"
+#include "whowas.h"
+#include "hash.h"
+#ifndef _WIN32
+#include <sys/file.h>
+#endif
+#ifdef HPUX
+#include <fcntl.h>
+#endif
+#if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
+    !defined(__convex__) && !defined(_WIN32)
+# include <sys/param.h>
+#endif
+#ifdef HPUX
+# include <sys/syscall.h>
+# define getrusage(a,b) syscall(SYS_GETRUSAGE, a, b)
+#endif
+#ifdef GETRUSAGE_2
+# ifdef SOL20
+#  include <sys/time.h>
+#  ifdef RUSAGEH
+#   include <sys/rusage.h>
+#  endif
+# endif
+# include <sys/resource.h>
+#else
+#  ifdef TIMES_2
+#   include <sys/times.h>
+#  endif
+#endif
+#ifdef PCS
+# include <time.h>
+#endif
+#ifdef HPUX
+#include <unistd.h>
+#ifdef DYNIXPTX
+#include <sys/types.h>
+#include <time.h>
+#endif
+#endif
+#include "h.h"
+
+#ifndef ssize_t
+#define ssize_t unsigned int
+#endif
+
+ID_CVS("$Id$");
+
+#ifdef DEBUGMODE
+static char    debugbuf[1024];
+
+#ifndef        USE_VARARGS
+/*VARARGS2*/
+void   debug(level, form, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+int    level;
+char   *form, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10;
+{
+# ifndef _WIN32
+       int     err = errno;
+# else
+       int     err = WSAGetLastError();
+# endif
+#else
+void   debug(level, form, va_alist)
+int    level;
+char   *form;
+va_dcl
+{
+       va_list vl;
+# ifndef _WIN32
+       int     err = errno;
+# else
+       int     err = WSAGetLastError();
+# endif
+
+       va_start(vl);
+#endif
+
+       if ((debuglevel >= 0) && (level <= debuglevel))
+           {
+#ifndef        USE_VARARGS
+               (void)sprintf(debugbuf, form,
+                               p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
+#else
+               (void)vsprintf(debugbuf, form, vl);
+#endif
+
+#ifndef _WIN32
+               if (local[2])
+                   {
+                       local[2]->sendM++;
+                       local[2]->sendB += strlen(debugbuf);
+                   }
+               (void)fprintf(stderr, "%s", debugbuf);
+               (void)fputc('\n', stderr);
+           }
+       errno = err;
+#else
+               strcat(debugbuf, "\r");
+#ifndef _WIN32GUI
+               Cio_Puts(hCio, debugbuf, strlen(debugbuf));
+#endif
+           }
+       WSASetLastError(err);
+#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
+ */
+void   send_usage(cptr, nick)
+aClient *cptr;
+char   *nick;
+{
+
+#ifdef GETRUSAGE_2
+       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 !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__APPLE__)
+/*             extern char *sys_errlist[]; */
+#endif
+               sendto_one(cptr,":%s NOTICE %s :Getruseage error: %s.",
+                          me.name, nick, sys_errlist[errno]);
+               return;
+           }
+       secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
+       rup = time(NULL) - me.since;
+       if (secs == 0)
+               secs = 1;
+
+       sendto_one(cptr,
+                  ":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
+                  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 %d ShMem %d Data %d Stack %d",
+                  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 %d Reclaims %d Faults %d",
+                  me.name, RPL_STATSDEBUG, nick, rus.ru_nswap,
+                  rus.ru_minflt, rus.ru_majflt);
+       sendto_one(cptr, ":%s %d %s :Block in %d out %d",
+                  me.name, RPL_STATSDEBUG, nick, rus.ru_inblock,
+                  rus.ru_oublock);
+       sendto_one(cptr, ":%s %d %s :Msg Rcv %d Send %d",
+                  me.name, RPL_STATSDEBUG, nick, rus.ru_msgrcv, rus.ru_msgsnd);
+       sendto_one(cptr, ":%s %d %s :Signals %d Context Vol. %d Invol %d",
+                  me.name, RPL_STATSDEBUG, nick, rus.ru_nsignals,
+                  rus.ru_nvcsw, rus.ru_nivcsw);
+#else
+# ifdef TIMES_2
+       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.",
+#  ifndef _WIN32
+                          me.name, RPL_STATSDEBUG, nick, strerror(errno));
+#  else
+                          me.name, RPL_STATSDEBUG, nick,
+                                  strerror(WSAGetLastError()));
+#  endif
+               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
+#endif
+       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 blocks %d",
+                  me.name, RPL_STATSDEBUG, nick, dbufalloc, dbufblocks);
+       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
+
+void   count_memory(cptr, nick)
+aClient        *cptr;
+char   *nick;
+{
+       extern  aChannel        *channel;
+       extern  aClass  *classes;
+       extern  aConfItem       *conf;
+       extern  int     flinks;
+       extern  Link    *freelink;
+
+       aClient *acptr;
+       Ban *ban;
+       Link *link;
+       aChannel *chptr;
+       aConfItem *aconf;
+       aClass *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 */
+               fl = 0,         /* free links */
+               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 */
+               wlh = 0,        /* watchlist headers */
+               wle = 0;        /* watchlist entries */
+
+       u_long  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 */
+               wlhm = 0,       /* watchlist memory used */
+               db = 0,         /* memory used by dbufs */
+               rm = 0,         /* res memory used */
+               totcl = 0,
+               totch = 0,
+               totww = 0,
+               tot = 0;
+
+       count_whowas_memory(&wwu, &wwa, &wwam);
+       count_watch_memory(&wlh, &wlhm);
+       wwm = sizeof(aName) * NICKNAMEHISTORYLENGTH;
+
+       for (acptr = client; acptr; acptr = acptr->next)
+           {
+               if (MyConnect(acptr))
+                   {
+                       lc++;
+                       for (link = acptr->confs; link; link = link->next)
+                               lcc++;
+                       wle += acptr->notifies;
+                   }
+               else
+                       rc++;
+               if (acptr->user)
+                  {
+                       us++;
+                       for (link = acptr->user->invited; link;
+                            link = link->next)
+                               usi++;
+                       for (link = acptr->user->channel; link;
+                            link = link->next)
+                               usc++;
+                       if (acptr->user->away)
+                           {
+                               aw++;
+                               awm += (strlen(acptr->user->away)+1);
+                           }
+                  }
+           }
+       lcm = lc * CLIENT_LOCAL_SIZE;
+       rcm = rc * CLIENT_REMOTE_SIZE;
+
+       for (chptr = channel; chptr; chptr = chptr->nextch)
+           {
+               ch++;
+               chm += (strlen(chptr->chname) + sizeof(aChannel));
+               for (link = chptr->members; link; link = link->next)
+                       chu++;
+               for (link = chptr->invites; link; link = link->next)
+                       chi++;
+               for (ban = chptr->banlist; ban; ban = ban->next)
+                   {
+                       chb++;
+                       chbm += (strlen(ban->banstr)+1+
+                                strlen(ban->who)+1+sizeof(Ban));
+                   }
+           }
+
+       for (aconf = conf; 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);
+           }
+
+       for (cltmp = classes; cltmp; cltmp = cltmp->next)
+               cl++;
+
+       sendto_one(cptr, ":%s %d %s :Client Local %d(%d) Remote %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm);
+       sendto_one(cptr, ":%s %d %s :Users %d(%d) Invites %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, us, us*sizeof(anUser), usi,
+                  usi * sizeof(Link));
+       sendto_one(cptr, ":%s %d %s :User channels %d(%d) Aways %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, usc, usc*sizeof(Link),
+                  aw, awm);
+       sendto_one(cptr, ":%s %d %s :WATCH headers %d(%d) entries %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, wlh, wlhm,
+                  wle, wle*sizeof(Link));
+       sendto_one(cptr, ":%s %d %s :Attached confs %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, lcc, lcc*sizeof(Link));
+
+       totcl = lcm + rcm + us*sizeof(anUser) + usc*sizeof(Link) + awm;
+       totcl += lcc*sizeof(Link) + usi*sizeof(Link) + wlhm;
+       totcl += wle*sizeof(Link);
+
+       sendto_one(cptr, ":%s %d %s :Conflines %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, co, com);
+
+       sendto_one(cptr, ":%s %d %s :Classes %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, cl, cl*sizeof(aClass));
+
+       sendto_one(cptr, ":%s %d %s :Channels %d(%d) Bans %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm);
+       sendto_one(cptr, ":%s %d %s :Channel membrs %d(%d) invite %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, chu, chu*sizeof(Link),
+                  chi, chi*sizeof(Link));
+
+       totch = chm + chbm + chu*sizeof(Link) + chi*sizeof(Link);
+
+       sendto_one(cptr, ":%s %d %s :Whowas users %d(%d) away %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, wwu, wwu*sizeof(anUser),
+                  wwa, wwam);
+       sendto_one(cptr, ":%s %d %s :Whowas array %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, NICKNAMEHISTORYLENGTH, wwm);
+
+       totww = wwu*sizeof(anUser) + wwam + wwm;
+
+       sendto_one(cptr, ":%s %d %s :Hash: client %d(%d) chan %d(%d) watch %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, HASHSIZE,
+                  sizeof(aHashEntry) * HASHSIZE,
+                  CHANNELHASHSIZE, sizeof(aHashEntry) * CHANNELHASHSIZE,
+                  NOTIFYHASHSIZE, sizeof(aNotify *) * NOTIFYHASHSIZE);
+       db = dbufblocks * sizeof(dbufbuf);
+       sendto_one(cptr, ":%s %d %s :Dbuf blocks %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, dbufblocks, db);
+
+       link=freelink; while(link=link->next) fl++; fl++;
+       sendto_one(cptr, ":%s %d %s :Link blocks free %d(%d) total %d(%d)",
+                  me.name, RPL_STATSDEBUG, nick, fl, fl*sizeof(Link), 
+                  flinks, flinks*sizeof(Link));
+
+       rm = cres_mem(cptr);
+
+       tot = totww + totch + totcl + com + cl*sizeof(aClass) + db + rm;
+       tot += fl*sizeof(Link);
+       tot += sizeof(aHashEntry) * HASHSIZE;
+       tot += sizeof(aHashEntry) * CHANNELHASHSIZE;
+       tot += sizeof(aNotify *) * NOTIFYHASHSIZE;
+
+       sendto_one(cptr, ":%s %d %s :Total: ww %d ch %d cl %d co %d db %d",
+                  me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, com, db);
+#if !defined(_WIN32) && !defined(_AMIGA)
+#ifdef LINUX_ALPHA
+       sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u",
+                  me.name, RPL_STATSDEBUG, nick, tot,
+                  (u_int)sbrk((size_t)0)-(u_int)sbrk0);
+#else
+       sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %ul",
+                         me.name, RPL_STATSDEBUG, nick, tot,
+                        (u_long)sbrk((size_t)0)-(u_long)sbrk0);
+                                           
+#endif
+#else
+       sendto_one(cptr, ":%s %d %s :TOTAL: %d",
+                  me.name, RPL_STATSDEBUG, nick, tot);
+#endif
+       return;
+}
diff --git a/src/s_err.c b/src/s_err.c
new file mode 100644 (file)
index 0000000..a0171e6
--- /dev/null
@@ -0,0 +1,469 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/s_err.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.
+ *
+ *   You 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 "struct.h"
+#include "numeric.h"
+#include "common.h"
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_err.c   1.12 11/1/93 (C) 1992 Darren Reed";
+#endif
+
+ID_CVS("$Id$");
+
+typedef        struct  {
+       int     num_val;
+       char    *num_form;
+} Numeric;
+
+static char    *prepbuf PROTO((char *, int, char *));
+static char    numbuff[514];
+static char    numbers[] = "0123456789";
+
+static Numeric local_replies[] = {
+/* 000 */      0, (char *)NULL,
+/* 001 */      RPL_WELCOME, ":Welcome to the %s IRC Network %s!%s@%s",
+/* 002 */      RPL_YOURHOST, ":Your host is %s, running version %s",
+/* 003 */      RPL_CREATED, ":This server was created %s",
+/* 004 */       RPL_MYINFO, "%s %s %s %s",
+/* 005 */      RPL_PROTOCTL, "%s :are available on this server",
+/* 006 */       RPL_MAP, ":%s%-*s\2[Users:%5d]  [%2d%%]\2",
+/* 007 */       RPL_MAPEND, ":End of /MAP",
+               0, (char *)NULL
+};
+
+static Numeric numeric_errors[] = {
+/* 401 */      ERR_NOSUCHNICK, "%s :No such nick/channel",
+/* 402 */      ERR_NOSUCHSERVER, "%s :No such server",
+/* 403 */      ERR_NOSUCHCHANNEL, "%s :No such channel",
+/* 404 */      ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel (%s)",
+/* 405 */      ERR_TOOMANYCHANNELS, "%s :You have joined too many channels",
+/* 406 */      ERR_WASNOSUCHNICK, "%s :There was no such nickname",
+/* 407 */      ERR_TOOMANYTARGETS,
+               "%s :Duplicate recipients. No message delivered",
+/* 408 */      ERR_NOSUCHSERVICE, (char *)NULL,
+/* 409 */      ERR_NOORIGIN, ":No origin specified",
+               0, (char *)NULL,
+/* 411 */      ERR_NORECIPIENT, ":No recipient given (%s)",
+/* 412 */      ERR_NOTEXTTOSEND, ":No text to send",
+/* 413 */      ERR_NOTOPLEVEL, "%s :No toplevel domain specified",
+/* 414 */      ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 421 */       ERR_UNKNOWNCOMMAND, "%s :Unknown command",
+/* 422 */      ERR_NOMOTD, ":MOTD File is missing",
+/* 423 */      ERR_NOADMININFO,
+               "%s :No administrative info available",
+/* 424 */      ERR_FILEERROR, ":File error doing %s on %s",
+/* 425*/    ERR_NOOPERMOTD, ":OPERMOTD File is missing",
+               0, (char *) NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 431 */      ERR_NONICKNAMEGIVEN, ":No nickname given",
+/* 432 */      ERR_ERRONEUSNICKNAME, "%s :Erroneous Nickname: %s",
+/* 433 */      ERR_NICKNAMEINUSE, "%s :Nickname is already in use.",
+/* 434 */       ERR_NORULES, ":RULES File is missing",
+/* 435 */      ERR_SERVICECONFUSED, (char *)NULL,
+/* 436 */      ERR_NICKCOLLISION, "%s :Nickname collision KILL",
+/* 437 */      ERR_BANNICKCHANGE,
+               "%s :Cannot change nickname while banned on channel",
+/* 438 */      ERR_NCHANGETOOFAST, "%s :Nick change too fast. Please wait %d seconds",
+/* 439 */      ERR_TARGETTOOFAST, "%s :Message target change too fast. Please wait %d seconds",
+/* 440 */      ERR_SERVICESDOWN, "%s :Services are currently down. Please try again later.",
+/* 441 */      ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel",
+/* 442 */      ERR_NOTONCHANNEL, "%s :You're not on that channel",
+/* 443 */      ERR_USERONCHANNEL, "%s %s :is already on channel",
+/* 444 */      ERR_NOLOGIN, "%s :User not logged in",
+#ifndef        ENABLE_SUMMON
+/* 445 */      ERR_SUMMONDISABLED, ":SUMMON has been disabled",
+#else
+               0, (char *)NULL,
+#endif
+#ifndef        ENABLE_USERS
+/* 446 */      ERR_USERSDISABLED, ":USERS has been disabled",
+#else
+               0, (char *)NULL,
+#endif
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL,
+/* 451 */      ERR_NOTREGISTERED, ":You have not registered",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+#ifdef HOSTILENAME
+/* 455 */      ERR_HOSTILENAME, ":Your username %s contained the invalid "
+                       "character(s) %s and has been changed to %s. "
+                       "Please use only the characters 0-9 a-z A-Z _ - "
+                       "or . in your username. Your username is the part "
+                       "before the @ in your email address.",
+#else
+               0, (char *)NULL,
+#endif
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 459 */       ERR_NOHIDING,  "%s :Cannot join channel (+H)",
+/* 460 */   ERR_NOTFORHALFOPS, ":Halfops cannot set mode %c",
+/* 461 */      ERR_NEEDMOREPARAMS, "%s :Not enough parameters",
+/* 462 */      ERR_ALREADYREGISTRED, ":You may not reregister",
+/* 463 */      ERR_NOPERMFORHOST, ":Your host isn't among the privileged",
+/* 464 */      ERR_PASSWDMISMATCH, ":Password Incorrect",
+/* 465 */      ERR_YOUREBANNEDCREEP, ":You are banned from this server.  Mail %s for more information", 
+/* 466 */      ERR_YOUWILLBEBANNED, (char *)NULL, 
+/* 467 */      ERR_KEYSET, "%s :Channel key already set",
+/* 468 */      ERR_ONLYSERVERSCANCHANGE, "%s :Only servers can change that mode",
+/* 469 */      ERR_LINKSET, "%s :Channel link already set",
+/* 470 */      ERR_LINKCHANNEL, "[Link] %s has become full, so you are automatically being transferred to the linked channel %s",
+/* 471 */      ERR_CHANNELISFULL, "%s :Cannot join channel (+l)",
+/* 472 */      ERR_UNKNOWNMODE  , "%c :is unknown mode char to me",
+/* 473 */      ERR_INVITEONLYCHAN, "%s :Cannot join channel (+i)",
+/* 474 */      ERR_BANNEDFROMCHAN, "%s :Cannot join channel (+b)",
+/* 475 */      ERR_BADCHANNELKEY, "%s :Cannot join channel (+k)",
+/* 476 */      ERR_BADCHANMASK, "%s :Bad Channel Mask",
+/* 477 */      ERR_NEEDREGGEDNICK, "%s :You need a registered nick to join that channel.",
+/* 478 */      ERR_BANLISTFULL, "%s %s :Channel ban/ignore list is full",
+/* 479 */      ERR_LINKFAIL, "%s :Sorry, the channel has an invalid channel link set.",
+/* 480 */      ERR_CANNOTKNOCK, ":Cannot knock on %s (%s)",
+/* 481 */      ERR_NOPRIVILEGES, ":Permission Denied- You do not have the correct IRC operator privileges",
+/* 482 */      ERR_CHANOPRIVSNEEDED, "%s :You're not channel operator",
+/* 483 */      ERR_CANTKILLSERVER, ":You cant kill a server!",
+/* 484 */      ERR_ATTACKDENY, "%s :Cannot kick protected user %s.",
+/* 485 */      ERR_KILLDENY, ":Cannot kill protected user %s.",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL,
+/* 491 */      ERR_NOOPERHOST, ":No O-lines for your host",
+/* 492 */      ERR_NOSERVICEHOST, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL,
+/* 501 */      ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag",
+/* 502 */      ERR_USERSDONTMATCH, ":Cant change mode for other users",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL,
+/* 511 */      ERR_SILELISTFULL, "%s :Your silence list is full",
+/* 512 */      ERR_TOOMANYWATCH, "%s :Maximum size for WATCH-list is 128 entries",
+/* 513 */      ERR_NEEDPONG, ":To connect, type /QUOTE PONG %lX",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 
+               518, ":Cannot invite (+I) at channel",
+        519, ":Cannot join channel (Admin only)",
+               520, ":Cannot join channel (IRCops only)",
+/* 521 */      ERR_LISTSYNTAX, "Bad list syntax, type /quote list ? or /raw list ?"
+};
+
+static Numeric numeric_replies[] = {
+/* 300 */      RPL_NONE, (char *)NULL,
+/* 301 */      RPL_AWAY, "%s :%s",
+/* 302 */      RPL_USERHOST, ":",
+/* 303 */      RPL_ISON, ":",
+/* 304 */      RPL_TEXT, (char *)NULL,
+/* 305 */      RPL_UNAWAY, ":You are no longer marked as being away",
+/* 306 */      RPL_NOWAWAY, ":You have been marked as being away",
+/* 307 */      RPL_WHOISREGNICK, "%s :is a registered nick",
+/* 308 */      RPL_RULESSTART, ":- %s Server Rules - ",
+/* 309 */       RPL_ENDOFRULES, ":End of RULES command.",
+/* 310 */      RPL_WHOISHELPOP, "%s :is available for help.",
+/* 311 */      RPL_WHOISUSER, "%s %s %s * :%s",
+/* 312 */      RPL_WHOISSERVER, "%s %s :%s",
+/* 313 */      RPL_WHOISOPERATOR, "%s :is %s on %s",
+/* 314 */      RPL_WHOWASUSER, "%s %s %s * :%s",
+/* 315 */      RPL_ENDOFWHO, "%s :End of /WHO list.",
+/* 316 */      RPL_WHOISCHANOP, (char *)NULL,
+/* 317 */      RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time",
+/* 318 */      RPL_ENDOFWHOIS, "%s :End of /WHOIS list.",
+/* 319 */      RPL_WHOISCHANNELS, "%s :%s",
+                RPL_WHOISSPECIAL, "%s :%s",
+/* 321 */      RPL_LISTSTART, "Channel :Users  Name",
+/* 322 */      RPL_LIST, "%s %d :%s",
+/* 323 */      RPL_LISTEND, ":End of /LIST",
+/* 324 */      RPL_CHANNELMODEIS, "%s %s %s",
+               0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL,
+/* 329 */ RPL_CREATIONTIME, "%s %lu",
+               0, (char *)NULL,
+/* 331 */      RPL_NOTOPIC, "%s :No topic is set.",
+/* 332 */      RPL_TOPIC, "%s :%s",
+/* 333 */       RPL_TOPICWHOTIME, "%s %s %lu",
+/* 334 */      RPL_LISTSYNTAX, ":%s",
+/* 335 */       RPL_WHOISBOT, "%s :is a \2Bot\2 on %s",
+                0, (char *)NULL, 0, (char *)NULL,
+                0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 341 */      RPL_INVITING, "%s %s",
+/* 342 */      RPL_SUMMONING, "%s :User summoned to irc",
+               0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 
+               RPL_INVITELIST, "%s %s",
+               RPL_ENDOFINVITELIST, "%s :End of Channel Invite List",
+               RPL_EXLIST, "%s %s %s %lu",
+               RPL_ENDOFEXLIST, "%s :End of Channel Exception List",
+               0, (char *)NULL,
+/* 351 */      RPL_VERSION, "%s(%s).%s %s :%s [%s=%li%s]",
+/* 352 */      RPL_WHOREPLY, "%s %s %s %s %s %s :%d %s",
+/* 353 */      RPL_NAMREPLY, "%s",
+               354, ":Reserved for Undernet",
+               
+               0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 
+               0, (char *)NULL, 0, (char *)NULL, 
+/* 361 */      RPL_KILLDONE, (char *)NULL,
+/* 362 */      RPL_CLOSING, "%s :Closed. Status = %d",
+/* 363 */      RPL_CLOSEEND, "%d: Connections Closed",
+/* 364 */      RPL_LINKS, "%s %s :%d %s",
+/* 365 */      RPL_ENDOFLINKS, "%s :End of /LINKS list.",
+/* 366 */      RPL_ENDOFNAMES, "%s :End of /NAMES list.",
+/* 367 */      RPL_BANLIST, "%s %s %s %lu",
+/* 368 */      RPL_ENDOFBANLIST, "%s :End of Channel Ban List",
+/* 369 */      RPL_ENDOFWHOWAS, "%s :End of WHOWAS",
+               0, (char *)NULL,
+/* 371 */      RPL_INFO, ":%s",
+/* 372 */      RPL_MOTD, ":- %s",
+/* 373 */      RPL_INFOSTART, ":Server INFO",
+/* 374 */      RPL_ENDOFINFO, ":End of /INFO list.",
+/* 375 */      RPL_MOTDSTART, ":- %s Message of the Day - ",
+/* 376 */      RPL_ENDOFMOTD, ":End of /MOTD command.",
+               0, (char *)NULL,
+/* 378 */       RPL_WHOISHOST, "%s :is connecting from *@%s",
+/* 379 */       RPL_WHOISMODES, "%s is using modes %s",
+               0, (char *)NULL,
+/* 381 */      RPL_YOUREOPER, ":You are now an IRC Operator",
+/* 382 */      RPL_REHASHING, "%s :Rehashing",
+/* 383 */      RPL_YOURESERVICE, (char *)NULL,
+/* 384 */      RPL_MYPORTIS, "%d :Port to local server is\r\n",
+/* 385 */      RPL_NOTOPERANYMORE, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL,
+/* 391 */      RPL_TIME, "%s :%s",
+#ifdef ENABLE_USERS
+/* 392 */      RPL_USERSSTART, ":UserID   Terminal  Host",
+/* 393 */      RPL_USERS, ":%-8s %-9s %-8s",
+/* 394 */      RPL_ENDOFUSERS, ":End of Users",
+/* 395 */      RPL_NOUSERS, ":Nobody logged in.",
+#else
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL,
+#endif
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL,
+/* 200 */      RPL_TRACELINK, "Link %s%s %s %s",
+/* 201 */      RPL_TRACECONNECTING, "Attempt %d %s",
+/* 202 */      RPL_TRACEHANDSHAKE, "Handshaking %d %s",
+/* 203 */      RPL_TRACEUNKNOWN, "???? %d %s",
+/* 204 */      RPL_TRACEOPERATOR, "Operator %d %s [%s] %ld",
+/* 205 */      RPL_TRACEUSER, "User %d %s [%s] %ld",
+/* 206 */      RPL_TRACESERVER, "Server %d %dS %dC %s %s!%s@%s %ld",
+/* 207 */      RPL_TRACESERVICE, "Service %d %s",
+/* 208 */      RPL_TRACENEWTYPE, "<newtype> 0 %s",
+/* 209 */      RPL_TRACECLASS, "Class %d %d",
+               0, (char *)NULL,
+/* 211 */      RPL_STATSLINKINFO, (char *)NULL,
+#ifdef DEBUGMODE
+/* 212 */      RPL_STATSCOMMANDS, "%s %u %u %u %u %u %u",
+#else
+/* 212 */      RPL_STATSCOMMANDS, "%s %u %u",
+#endif
+/* 213 */      RPL_STATSCLINE, "%c %s * %s %d %d",
+/* 214 */      RPL_STATSNLINE, "%c %s * %s %d %d",
+/* 215 */      RPL_STATSILINE, "%c %s * %s %d %d",
+/* 216 */      RPL_STATSKLINE, "%c %s %s %s %d %d",
+/* 217 */      RPL_STATSQLINE, "%c %s %s %s %d %d",
+/* 218 */      RPL_STATSYLINE, "%c %d %d %d %d %ld",
+/* 219 */      RPL_ENDOFSTATS, "%c :End of /STATS report",
+/* 220 */      RPL_STATSBLINE, "%c %s %s %s %d %d",
+/* 221 */      RPL_UMODEIS, "%s",
+/* 222 */      RPL_SQLINE_NICK, "%s :%s",
+/* 223 */      RPL_STATSGLINE, "%c %s@%s %li %li %s :%s",
+/* 224 */      RPL_STATSTLINE, "T %s %s %s",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 231 */      RPL_SERVICEINFO, (char *)NULL,
+/* 232 */      RPL_RULES, ":- %s",
+/* 233 */      RPL_SERVICE, (char *)NULL,
+/* 234 */      RPL_SERVLIST, (char *)NULL,
+/* 235 */      RPL_SERVLISTEND, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL,
+/* 241 */      RPL_STATSLLINE, "%c %s * %s %d %d",
+/* 242 */      RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d",
+/* 243 */      RPL_STATSOLINE, "%c %s * %s %s %d",
+/* 244 */      RPL_STATSHLINE, "%c %s * %s %d %d", 
+/* 245 */      RPL_STATSSLINE, "%c %s * %s %d %d", 
+               0, (char *)NULL, 
+/* 247 */      RPL_STATSXLINE, "X %s %d", 
+/* 248 */      RPL_STATSULINE, "%c %s * %s %d %d", 
+               0, (char *)NULL, 
+/* 250 */       RPL_STATSCONN,
+                ":Highest connection count: %d (%d clients)",
+/* 251 */      RPL_LUSERCLIENT,
+               ":There are %d users and %d invisible on %d servers",
+/* 252 */      RPL_LUSEROP, "%d :operator(s) online",
+/* 253 */      RPL_LUSERUNKNOWN, "%d :unknown connection(s)",
+/* 254 */      RPL_LUSERCHANNELS, "%d :channels formed",
+/* 255 */      RPL_LUSERME, ":I have %d clients and %d servers",
+/* 256 */      RPL_ADMINME, ":Administrative info about %s",
+/* 257 */      RPL_ADMINLOC1, ":%s",
+/* 258 */      RPL_ADMINLOC2, ":%s",
+/* 259 */      RPL_ADMINEMAIL, ":%s",
+               0, (char *)NULL,
+/* 261 */      RPL_TRACELOG, "File %s %d",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 265 */      RPL_LOCALUSERS, ":Current Local Users: %d  Max: %d",
+/* 266 */      RPL_GLOBALUSERS, ":Current Global Users: %d  Max: %d",
+               0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 271 */      RPL_SILELIST, "%s %s",
+/* 272 */      RPL_ENDOFSILELIST, ":End of Silence List",
+               0, (char *)NULL, 0, (char *)NULL,
+/* 275 */      RPL_STATSDLINE, "%c %s %s",
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+               0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
+/* 294 */      RPL_HELPFWD, ":Your help-request has been forwarded to Help Operators",
+/* 295 */      RPL_HELPIGN, ":Your address has been ignored from forwarding"
+};
+
+/*
+ * NOTE: Unlike the others, this one goes strait through, 600-799
+ */
+static Numeric numeric_replies2[] = {
+/* 600 */      RPL_LOGON, "%s %s %s %d :logged online",
+/* 601 */      RPL_LOGOFF, "%s %s %s %d :logged offline",
+/* 602 */      RPL_WATCHOFF, "%s %s %s %d :stopped watching",
+/* 603 */      RPL_WATCHSTAT, ":You have %d and are on %d WATCH entries",
+/* 604 */      RPL_NOWON, "%s %s %s %d :is online",
+/* 605 */      RPL_NOWOFF, "%s %s %s %d :is offline",
+/* 606 */      RPL_WATCHLIST, ":%s",
+/* 607 */      RPL_ENDOFWATCHLIST, ":End of WATCH %c",
+
+/* 610 */       RPL_MAPMORE, ":%s%-*s --> *more*",
+/* 611 */              0, (char *)NULL,
+/* 612 */              0, (char *)NULL,
+/* 613 */              0, (char *)NULL,
+/* 614 */              0, (char *)NULL,
+/* 615 */              0, (char *)NULL,
+/* 616 */              0, (char *)NULL,
+/* 617 */              0, (char *)NULL,
+/* 618 */              0, (char *)NULL,
+/* 619 */              0, (char *)NULL,
+/* 620 */              0,(char *) NULL,
+/* 621 */              0,(char *) NULL,
+/* 622 */              0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+                       0,(char *) NULL,
+/* 640 */              RPL_DUMPING, ":Dumping clients matching %s",
+/* 641 */              RPL_DUMPRPL, "%s %s %s %s %s%s%s%s",
+/* 642 */              RPL_EODUMP,      ":End of /dusers - %i",
+               0, (char *) NULL,
+               0, (char *)NULL
+};
+
+char   *err_str(numeric)
+int    numeric;
+{
+       Reg1    Numeric *nptr;
+       Reg2    int     num = numeric;
+
+       num -= numeric_errors[0].num_val;
+       if (num < 0 || num > ERR_NEEDPONG)
+               (void)sprintf(numbuff,
+                       ":%%s %d %%s :INTERNAL ERROR: BAD NUMERIC! %d",
+                       numeric, num);
+       else
+           {
+               nptr = &numeric_errors[num];
+               if (!nptr->num_form || !nptr->num_val)
+                       (void)sprintf(numbuff,
+                               ":%%s %d %%s :NO ERROR FOR NUMERIC ERROR %d",
+                               numeric, num);
+               else
+                       (void)prepbuf(numbuff, nptr->num_val, nptr->num_form);
+           }
+       return numbuff;
+}
+
+
+char   *rpl_str(numeric)
+int    numeric;
+{
+       Reg1    Numeric *nptr;
+       Reg2    int     num = numeric;
+
+       if (num > 99)
+               num -= (num > 300) ? 300 : 100;
+
+       if ((num < 0 || num > 200) && (num < 300 || num > 499))
+               (void)sprintf(numbuff,
+                       ":%%s %d %%s :INTERNAL REPLY ERROR: BAD NUMERIC! %d",
+                       numeric, num);
+       else
+           {
+               if (numeric > 599) {
+                       num -= 300;
+                       nptr = &numeric_replies2[num];
+               }
+               else if (numeric > 99)
+                       nptr = &numeric_replies[num];
+               else
+                       nptr = &local_replies[num];
+               Debug((DEBUG_NUM, "rpl_str: numeric %d num %d nptr %x %d %x",
+                       numeric, num, nptr, nptr->num_val, nptr->num_form));
+               if (!nptr->num_form || !nptr->num_val)
+                       (void)sprintf(numbuff,
+                               ":%%s %d %%s :NO REPLY FOR NUMERIC ERROR %d",
+                               numeric, num);
+               else
+                       (void)prepbuf(numbuff, nptr->num_val, nptr->num_form);
+           }
+       return numbuff;
+}
+
+static char    *prepbuf(buffer, num, tail)
+char   *buffer;
+Reg1   int     num;
+char   *tail;
+{
+       Reg1    char    *s;
+
+       (void)strcpy(buffer, ":%s ");
+       s = buffer + 4;
+
+       *s++ = numbers[num/100];
+       num %= 100;
+       *s++ = numbers[num/10];
+       *s++ = numbers[num%10];
+       (void)strcpy(s, " %s ");
+       (void)strcpy(s+4, tail);
+       return buffer;
+}
+
+/* this was the old RPL_MYINFO line .... 
+   RPL_MYINFO, "%s %s oiwsghOkcSNfraAbexTCWq biklmnopstvRzqxOAqa", */
diff --git a/src/s_extra.c b/src/s_extra.c
new file mode 100644 (file)
index 0000000..bc3e28e
--- /dev/null
@@ -0,0 +1,690 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, s_extra.c
+ *   (C) 1999 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org>
+ *
+ *   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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifndef _WIN32
+#include <utmp.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) Carsten Munk 1999");
+
+/*
+    fl->type = 
+       0     = set by dccconf.conf
+       1     = set by services
+       2     = set by ircops by /dccdeny
+*/
+
+#define AllocCpy(x,y) x = (char *) MyMalloc(strlen(y) + 1); strcpy(x,y)
+#define IRCD_DCCDENY  "dccdeny.conf"
+#define IRCD_RESTRICT "chrestrict.conf"
+#define IRCD_VHOST    "vhost.conf"
+
+aFline *flines   = NULL;
+aCRline *crlines = NULL;
+aVhost *vhosts = NULL;
+aHush *hushes = NULL;
+
+char   *cannotjoin_msg = NULL;
+
+/* ircd.dcc configuration */
+
+aFline *dcc_isforbidden(cptr,sptr,target,filename)
+aClient *cptr,*sptr,*target;
+char    *filename;
+{
+       aFline *p;
+       
+       if (!flines || !target || !filename)
+               return NULL;
+
+       if (IsOper(sptr) || IsULine(cptr, sptr))
+               return NULL;
+
+       if (IsOper(target))
+               return NULL;
+       if (IsVictim(target))
+       {
+               return NULL;
+       }       
+       for (p = flines; p; p = p->next) 
+       {
+               if (!match(p->mask, filename))
+                       return p;
+       }
+
+       /* no target found */
+       return NULL;
+}
+
+int    dcc_add_fline(mask, reason, type)
+char *mask, *reason;
+int  type;
+{
+       aFline *fl;
+       
+       fl = (aFline *) MyMalloc(sizeof(aFline));
+       
+       AllocCpy(fl->mask, mask);
+       AllocCpy(fl->reason, reason);
+       fl->type = type;
+       fl->next = flines;
+       fl->prev = NULL;
+       if (flines)
+               flines->prev = fl;
+       flines = fl;
+}
+
+aFline     *dcc_del_fline(fl)
+aFline *fl;
+{
+       aFline *p, *q;
+        for (p = flines; p; p = p->next) {
+                if (p == fl)
+                {
+                        q = p->next;
+                        MyFree((char *) p->mask);
+                        MyFree((char *) p->reason);
+                        /* chain1 to chain3 */
+                        if (p->prev) {
+                                p->prev->next = p->next;
+                        }
+                          else
+                        {
+                                flines = p->next;
+                        }
+                        if (p->next) {
+                                p->next->prev = p->prev;
+                        }
+                        MyFree((aFline *) p);
+                        return q;
+                }
+        }
+        return NULL;
+}
+
+void   dcc_wipe_all(void)
+{
+       aFline *p,q;
+       
+       for (p = flines; p; p = p->next)
+       {
+               q.next = dcc_del_fline(p);
+               p = &q;
+       }
+}
+
+aFline *dcc_find(mask)
+char *mask;
+{
+       aFline *p,q;
+       
+       for (p = flines; p; p = p->next)
+       {
+               if (!strcmp(p->mask, mask))
+                       return(p);
+       }
+       return NULL;
+}
+
+void   dcc_rehash(void)
+{
+       aFline *p,q;
+       
+       for (p = flines; p; p = p->next)
+       {
+               if ((p->type == 0) || (p->type == 2))
+               {
+                        q.next = dcc_del_fline(p);
+                        p = &q;
+               }
+       }
+       dcc_loadconf();
+}
+
+void   dcc_wipe_services(void)
+{
+       aFline *p,q;
+       
+       for (p = flines; p; p = p->next)
+       {
+               if ((p->type == 1))
+               {
+                        q.next = dcc_del_fline(p);
+                        p = &q;
+               }
+       }
+}
+
+void   report_flines(sptr)
+aClient *sptr;
+{
+       aFline *tmp;
+       char    *filemask, *reason;
+       char    a;
+               
+       if (flines)
+       {
+       }
+       for (tmp = flines; tmp; tmp = tmp->next)
+       {
+               filemask = BadPtr(tmp->mask) ? "<NULL>" : tmp->mask;
+               reason  = BadPtr(tmp->reason) ? "<NULL>" : tmp->reason;
+               if (tmp->type == 0)
+                       a = 'c';
+               if (tmp->type == 1)
+                       a = 's';
+               if (tmp->type == 2)
+                       a = 'o';
+               sendto_one(sptr, ":%s NOTICE %s :*** (dcc) [%c] %-22s %s", me.name, sptr->name, a, filemask, reason);
+       }
+       
+}
+
+/* 
+   dccdeny.conf
+   ------------
+# DMSetup trojan
+deny dmsetup.exe - Possible infected file. Please join #nohack for more information
+
+*/
+int    dcc_loadconf(void)
+{
+       char    buf[2048];
+       char    *x,*y,*z;
+       FILE    *f;     
+       
+       f = fopen(IRCD_DCCDENY, "r");
+       if (!f)
+               return -1;      
+               
+       while (fgets(buf, 2048,f))
+       {
+               iCstrip(buf);
+               x = strtok(buf, " ");
+               if (strcmp("deny", x)==0)
+               {
+                       y = strtok(NULL, " ");
+                       z = strtok(NULL, "");
+                       if (!y || !x)
+                               continue;
+                       dcc_add_fline(y,z,0);
+               }
+       }
+       return 0; 
+}
+
+int     m_svsfline(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       if (!IsULine(cptr,sptr))
+               return 0;
+       
+       if (parc < 2)
+               return 0;
+               
+       switch (*parv[1])
+       {
+               case '+': {
+                               if (parc < 4)
+                                       return 0;                       
+                               dcc_add_fline(parv[2], parv[3], 1);
+                               sendto_serv_butone(cptr, ":%s SVSFLINE + %s :%s",
+                                       sptr->name, parv[2], parv[3]);
+                               break;
+                       }
+               case '-':
+                       {
+                               if (parc < 3)
+                                       return 0;
+                               dcc_del_fline(dcc_find(parv[2]));
+                               sendto_serv_butone(cptr, ":%s SVSFLINE - %s",
+                                       sptr->name, parv[2]);
+                               break;
+                       }
+               case '*':
+               {
+                       dcc_wipe_services();
+                       sendto_serv_butone(cptr, ":%s SVSFLINE *", sptr->name);
+                       break;
+               }
+               
+       }
+}
+
+/* restrict channel stuff */
+
+int    channel_canjoin(sptr,name)
+aClient *sptr;
+char *name;
+{
+       aCRline *p;
+       
+       if (IsOper(sptr))
+               return 1;
+       if (IsULine(sptr,sptr))
+               return 1;       
+       if (!crlines)
+               return 1;
+       for (p = crlines; p; p = p->next)
+       {
+               if (!match(p->channel, name))
+                       return 1;
+       }
+       return 0;
+}
+
+int    cr_add(channel, type)
+char *channel;
+int  type;
+{
+       aCRline *fl;
+       
+       fl = (aCRline *) MyMalloc(sizeof(aCRline));
+       
+       AllocCpy(fl->channel, channel);
+       fl->type = type;
+       fl->next = crlines;
+       fl->prev = NULL;
+       if (crlines)
+               crlines->prev = fl;
+       crlines = fl;
+}
+
+aCRline     *cr_del(fl)
+aCRline *fl;
+{
+       aCRline *p, *q;
+        for (p = crlines; p; p = p->next) {
+                if (p == fl)
+                {
+                        q = p->next;
+                        MyFree((char *) p->channel);
+                        /* chain1 to chain3 */
+                        if (p->prev) {
+                                p->prev->next = p->next;
+                        }
+                          else
+                        {
+                                crlines = p->next;
+                        }
+                        if (p->next) {
+                                p->next->prev = p->prev;
+                        }
+                        MyFree((aCRline *) p);
+                        return q;
+                }
+        }
+        return NULL;
+}
+
+/* 
+   chrestrict.conf
+   ------------
+allow #cafe
+allow #teens
+*/
+int    cr_loadconf(void)
+{
+       char    buf[2048];
+       char    *x,*y;
+       FILE    *f;     
+       
+       f = fopen(IRCD_RESTRICT, "r");
+       if (!f)
+               return -1;      
+               
+       while (fgets(buf, 2048,f))
+       {
+               iCstrip(buf);
+               x = strtok(buf, " ");
+               if (strcmp("allow", x)==0)
+               {
+                       y = strtok(NULL, " ");
+                       if (!y)
+                               continue;
+                       cr_add(y,0);
+               }
+               else
+               if (strcmp("msg", x)==0)
+               {
+                       y = strtok(NULL, "");
+                       if (!y)
+                               continue;
+                       if (cannotjoin_msg)
+                               MyFree((char *) cannotjoin_msg);
+                       cannotjoin_msg = MyMalloc(strlen(y) + 1);
+                       strcpy(cannotjoin_msg, y);
+               }
+
+       }
+       return 0; 
+}
+
+void   cr_rehash(void)
+{
+       aCRline *p,q;
+       
+       for (p = crlines; p; p = p->next)
+       {
+               if ((p->type == 0) || (p->type == 2))
+               {
+                        q.next = cr_del(p);
+                        p = &q;
+               }
+       }
+       cr_loadconf();
+}
+
+void   cr_report(sptr)
+aClient *sptr;
+{
+       aCRline *tmp;
+       char    *filemask, *reason;
+       char    a;
+               
+       if (crlines)
+       {
+       }
+       for (tmp = crlines; tmp; tmp = tmp->next)
+       {
+               filemask = BadPtr(tmp->channel) ? "<NULL>" : tmp->channel;
+               if (tmp->type == 0)
+                       a = 'c';
+               if (tmp->type == 1)
+                       a = 's';
+               if (tmp->type == 2)
+                       a = 'o';
+               sendto_one(sptr, ":%s NOTICE %s :*** (allow) [%c] %s", me.name, sptr->name, a, filemask);
+       }
+       
+}
+
+/* vhost configuration (vhost.conf) 
+   vhost - login password vhost
+*/
+
+int    vhost_add(vhost, login, password, usermask, hostmask)
+char *vhost, *login, *password, *usermask, *hostmask;
+{
+       aVhost *fl;
+       
+       fl = (aVhost *) MyMalloc(sizeof(aVhost));
+       
+       AllocCpy(fl->virthost, vhost);
+       AllocCpy(fl->usermask, usermask);
+       AllocCpy(fl->hostmask, hostmask);
+       AllocCpy(fl->login, login);
+       AllocCpy(fl->password, password);
+       fl->next = vhosts;
+       fl->prev = NULL;
+       if (vhosts)
+               vhosts->prev = fl;
+       vhosts = fl;
+}
+
+aVhost     *vhost_del(fl)
+aVhost *fl;
+{
+       aVhost *p, *q;
+        for (p = vhosts; p; p = p->next) {
+                if (p == fl)
+                {
+                        q = p->next;
+                       MyFree((char *) (fl->virthost));
+                       MyFree((char *) (fl->usermask));
+                       MyFree((char *) (fl->hostmask));
+                       MyFree((char *) (fl->login));
+                       MyFree((char *) (fl->password));
+                        /* chain1 to chain3 */
+                        if (p->prev) {
+                                p->prev->next = p->next;
+                        }
+                          else
+                        {
+                                vhosts = p->next;
+                        }
+                        if (p->next) {
+                                p->next->prev = p->prev;
+                        }
+                        MyFree((aVhost *) p);
+                        return q;
+                }
+        }
+        return NULL;
+}
+
+/* 
+  vhost.conf
+   ------------
+# vhost virtualhost username password mask
+
+vhost microsoft.com billgates ilovelinux *@*
+*/
+int    vhost_loadconf(void)
+{
+       char    buf[2048];
+       char    *x,*y, *login, *password, *mask, *usermask, *hostmask;
+       FILE    *f;     
+/* _not_ a failsafe routine .. */      
+       f = fopen(IRCD_VHOST, "r");
+       if (!f)
+               return -1;      
+               
+       while (fgets(buf, 2048,f))
+       {
+               iCstrip(buf);
+               x = strtok(buf, " ");
+               if (strcmp("vhost", x)==0)
+               {
+                       y = strtok(NULL, " ");
+                       if (!y)
+                               continue;
+                       login = strtok(NULL, " ");
+                       password = strtok(NULL, " ");
+                       mask = strtok(NULL, "");
+                       usermask = strtok(mask, "@");
+                       hostmask = strtok(NULL, " ");
+                       vhost_add(y, login,password,usermask, hostmask);
+               }
+       }
+       return 0; 
+}
+
+void   vhost_rehash(void)
+{
+       aVhost *p,q;
+       
+       for (p = vhosts; p; p = p->next)
+       {
+                        q.next = vhost_del(p);
+                        p = &q;
+       }
+       vhost_loadconf();
+}
+
+void   vhost_report(sptr)
+aClient *sptr;
+{
+       aVhost *tmp;
+       char    *filemask, *reason;
+       char    a;
+               
+       for (tmp = vhosts; tmp; tmp = tmp->next)
+       {
+               filemask = BadPtr(tmp->virthost) ? "<NULL>" : tmp->virthost;
+               a = 'V';
+               sendto_one(sptr, ":%s NOTICE %s :*** (vhost) [%c] %s %s (%s@%s)", me.name, sptr->name, a, filemask, tmp->login, tmp->usermask, tmp->hostmask);
+       }
+       
+}
+
+int     m_vhost(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       aVhost *p;
+       char    *user, *pwd;
+       if (check_registered(sptr))
+               return 0;
+       
+       if (parc < 3)
+       {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "VHOST");
+               return 0;
+
+       }
+       if (!MyClient(sptr))
+               return 0;
+               
+       user = parv[1];
+       pwd  = parv[2];
+       
+       for (p = vhosts; p; p = p->next)
+       {
+               if (!strcmp(p->login, user))
+               {
+                       /* First check hostmask.. */
+                       if (!match(p->hostmask, sptr->user->realhost) && !match(p->usermask, sptr->user->username))
+                       {
+                               /* that was okay, lets check password */
+                               if (!strcmp(p->password, pwd))
+                               {
+                                       /* let's vhost him .. */
+                                       strcpy(sptr->user->virthost, p->virthost);
+                                       sptr->umodes |= UMODE_HIDE;
+                                       sptr->umodes |= UMODE_SETHOST;
+                                       sendto_serv_butone(cptr, ":%s SETHOST %s", sptr->name, p->virthost);
+                                       sendto_one(sptr, ":%s MODE %s :+tx", sptr->name, sptr->name);
+                                       sendto_one(sptr, ":%s NOTICE %s :*** Your hostname is now %s", me.name, sptr->name, p->virthost);
+                                       sendto_umode(UMODE_EYES, "[\2vhost\2] %s (%s!%s@%s) is now using vhost %s", 
+                                               user, sptr->name, sptr->user->username, sptr->user->realhost, p->virthost);
+                                       return 0;
+                               }
+                                       else
+                               {
+                                       sendto_one(sptr, ":%s NOTICE %s :*** [\2vhost\2] Login for %s failed - password incorrect", me.name, sptr->name, user);
+                                       return 0;
+                               }
+                       }
+               }       
+       }
+       sendto_one(sptr, ":%s NOTICE %s :*** No vHost lines available for your host", me.name, sptr->name);
+       return 0;                               
+}
+
+/* hush */
+#ifdef MOO
+int    hush_add(vhost, login, password, usermask, hostmask)
+char *vhost, *login, *password, *usermask, *hostmask;
+{
+       aHush *fl;
+       
+       fl = (aHush *) MyMalloc(sizeof(aHush));
+       
+       AllocCpy(fl->virthost, vhost);
+       AllocCpy(fl->usermask, usermask);
+       AllocCpy(fl->hostmask, hostmask);
+       AllocCpy(fl->login, login);
+       AllocCpy(fl->password, password);
+       fl->next = vhosts;
+       fl->prev = NULL;
+       if (vhosts)
+               vhosts->prev = fl;
+       vhosts = fl;
+}
+
+aVhost     *vhost_del(fl)
+aVhost *fl;
+{
+       aVhost *p, *q;
+        for (p = vhosts; p; p = p->next) {
+                if (p == fl)
+                {
+                        q = p->next;
+                       MyFree((char *) (fl->virthost));
+                       MyFree((char *) (fl->usermask));
+                       MyFree((char *) (fl->hostmask));
+                       MyFree((char *) (fl->login));
+                       MyFree((char *) (fl->password));
+                        /* chain1 to chain3 */
+                        if (p->prev) {
+                                p->prev->next = p->next;
+                        }
+                          else
+                        {
+                                vhosts = p->next;
+                        }
+                        if (p->next) {
+                                p->next->prev = p->prev;
+                        }
+                        MyFree((aVhost *) p);
+                        return q;
+                }
+        }
+        return NULL;
+}
+#endif
+/* irc logs.. */
+void   ircd_log(char *format, ...)
+{
+       va_list ap;
+        FILE   *f;
+              
+        va_start(ap, format);
+       f = fopen(lPATH, "a+");
+       if (!f)
+       {
+#if !defined(_WIN32) && !defined(_AMIGA)
+               sendto_realops("Couldn't write to %s - %s", lPATH, strerror(errno));
+#endif
+               return;
+       }
+       fprintf(f, "(%s) ", myctime(TStime()));
+       vfprintf(f, format, ap);
+       fprintf(f, "\n");
+       fclose(f);
+       va_end(ap);        
+}             
+
diff --git a/src/s_kline.c b/src/s_kline.c
new file mode 100644 (file)
index 0000000..ce2e61e
--- /dev/null
@@ -0,0 +1,710 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, s_kline.c
+ *   (C) 1999 Carsten Munk (Techie/Stskeeps) <cmunk@toybox.flirt.org>
+ *   File to take care of dynamic K:/G:/Z: lines
+ *
+ *
+ *   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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <utmp.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "h.h"
+
+
+aTKline        *tklines = NULL;
+
+#define AllocCpy(x,y) x = (char *) MyMalloc(strlen(y) + 1); strcpy(x,y)
+#define GFreeStr(x) MyFree((char *) x)
+#define GFreeGline(x) MyFree((aGline *) x)
+extern char zlinebuf[];
+
+/*
+
+ *     type =  TKL_*
+ *     usermask@hostmask 
+ *     reason
+ *     setby = whom set it
+ *     expire_at = when to expire - 0 if not to expire
+ *     set_at    = was set at
+*/
+
+int    tkl_add_line(type, usermask, hostmask, reason, setby, expire_at, set_at)
+int     type;
+char    *usermask, *hostmask, *reason, *setby;
+time_t          expire_at, set_at;
+{
+       aTKline *nl;
+       
+       nl = (aTKline *) MyMalloc(sizeof(aTKline));
+
+       if (!nl) 
+               return -1;      
+       
+       nl->type                = type;
+       nl->expire_at           = expire_at;
+       nl->set_at              = set_at;
+       AllocCpy(nl->usermask,  usermask);
+       AllocCpy(nl->hostmask,  hostmask);
+       AllocCpy(nl->reason,    reason);
+       AllocCpy(nl->setby,     setby);
+        nl->prev                = NULL;
+        nl->next                = tklines;     
+       if (tklines)
+               tklines->prev   = nl;
+       tklines                 = nl;
+}
+
+aTKline        *tkl_del_line(tkl)
+aTKline        *tkl;
+{
+        aTKline *p, *q;
+        
+        for (p = tklines; p; p = p->next) {
+                if (p == tkl) {
+                        q = p->next;
+                        GFreeStr(p->hostmask);
+                        GFreeStr(p->usermask);
+                        GFreeStr(p->reason);
+                        GFreeStr(p->setby);     
+                        /* chain1 to chain3 */
+                        if (p->prev) {
+                                p->prev->next = p->next;
+                        }
+                          else
+                        {
+                                tklines = p->next;
+                        }
+                        if (p->next) {
+                                p->next->prev = p->prev;
+                        }
+                        MyFree((aTKline *) p);
+                        return q;                       
+                }
+        }       
+        return NULL;
+
+}
+
+aTKline        *tkl_expire(aTKline *tmp)
+{
+       FILE *tklinelog;
+       char whattype[512];
+               
+       if (!tmp)
+               return NULL;
+
+       whattype[0] = 0;
+
+       if ( (tmp->expire_at == 0) || (tmp->expire_at > TStime()) )
+       {
+               sendto_ops("tkl_expire(): expire for not-yet-expired tkline %s@%s",
+                       tmp->usermask,
+                       tmp->hostmask);
+               return (tmp->next);     
+       }
+
+       if (tmp->type & TKL_GLOBAL)
+       {
+               if (tmp->type & TKL_KILL)
+               {
+                       strcpy(whattype, "G:Line");
+               }
+                       else
+               if (tmp->type & TKL_ZAP)
+               {
+                       strcpy(whattype, "Global Z:Line");
+               }
+       }
+               else
+       {
+               if (tmp->type & TKL_KILL)
+               {
+                       strcpy(whattype, "Timed K:Line");
+               }
+                       else
+               if (tmp->type & TKL_ZAP)
+               {
+                       strcpy(whattype, "Timed Z:Line");
+               }
+       }
+       sendto_umode(UMODE_EYES, "*** Expiring %s (%s@%s) made by %s (Reason: %s) set %li seconds ago",
+               whattype, tmp->usermask, tmp->hostmask, tmp->setby, tmp->reason, TStime() - tmp->set_at);
+       
+       ircd_log("Expiring %s (%s@%s) made by %s (Reason: %s) set %li seconds ago",
+               whattype, tmp->usermask, tmp->hostmask, tmp->setby, tmp->reason, TStime() - tmp->set_at);
+
+       return(tkl_del_line(tmp));
+}
+
+void tkl_check_expire (void)
+{
+       aTKline *gp, t;
+       time_t nowtime; 
+
+       nowtime = TStime();
+
+       for (gp = tklines; gp; gp = gp->next)
+       { 
+               if (gp->expire_at <= nowtime && !(gp->expire_at == 0))
+               {
+                       t.next = tkl_expire(gp);
+                       gp = &t;
+               }
+       }
+}
+
+
+
+/*
+       returns -1 if no tkline found
+       returns >= 0 if client exits
+*/
+
+int    find_tkline_match(cptr, xx)
+aClient *cptr;
+int xx;
+{
+       aTKline         *lp;
+        char    *chost, *cname,*cip;
+        time_t  nowtime;
+        int     is_ip;
+        char   msge[1024];                       
+                                
+        if (IsServer(cptr) || IsMe(cptr))
+                return -1;
+
+
+        nowtime = TStime();
+        chost = cptr->sockhost;
+        cname = cptr->user->username;
+
+cip = (char *) inet_ntoa(cptr->ip);
+
+       
+        for (lp = tklines; lp; lp = lp->next)
+       {
+                if (!(*lp->hostmask < '0') && (*lp->hostmask > '9'))
+                        is_ip = 1;
+                else
+                        is_ip = 0;
+               
+               if (is_ip == 0 ? (!match(lp->hostmask, chost) && !match(lp->usermask, cname))
+                      : (!match(lp->hostmask, chost) || !match(lp->hostmask, cip)) && !match(lp->usermask, cname))
+               {
+                       ircstp->is_ref++;
+                       if ((lp->type & (TKL_KILL)) && (xx != 2))
+                       {
+                               if (lp->type & TKL_GLOBAL)
+                               {
+                                       sendto_one(cptr, "NOTICE %s :*** You are banned for %li seconds (%s)", 
+                                               cptr->name, lp->expire_at - TStime(), lp->reason);
+                                       sprintf(msge, "User has been banned from %s", ircnetwork);
+                                       return(exit_client(cptr, cptr, &me, msge));     
+                               }
+                                       else
+                               {
+                                       sendto_one(cptr, "NOTICE %s :*** You are banned for %li seconds (%s)", 
+                                               cptr->name, lp->expire_at - TStime(), lp->reason);
+                                       sprintf(msge, "User has banned from using %s", me.name);
+                                       return(exit_client(cptr, cptr, &me, msge));     
+                               }
+                       }
+                               else                    
+                       if (lp->type & (TKL_ZAP))
+                       {
+                                       sprintf(msge, "ERROR :Closing Link: [%s] Z:Lined (%s)\r\n", inetntoa((char *) &cptr->ip), lp->reason);
+                                       strcpy(zlinebuf, msge);
+                                       return(1);      
+                       }
+               }
+       }       
+       return -1;
+}
+
+
+int    tkl_sweep() {
+       /* just sweeps net for people that should be killed */
+       aClient *acptr;
+               long i,i1;
+
+       tkl_check_expire();
+        for (i1 = 0; i1 <= 5; i1++) 
+        {
+               for (i = 0; i <= (MAXCONNECTIONS -1) ; i++ )
+               {
+                       if (acptr = local[i])
+                               if (MyClient(acptr))
+                                       find_tkline_match(acptr,0);
+               }       
+        }
+       return 1;
+}
+
+void tkl_stats(cptr)
+aClient *cptr;
+{
+       aTKline         *tk;
+       time_t          curtime;
+       
+       /*
+               We output in this row:
+                       Glines,GZlines,KLine, ZLIne
+               Character:
+                       G, Z, K, z                                       
+       */
+       tkl_check_expire();
+       curtime = TStime();     
+       for (tk = tklines; tk; tk = tk->next)
+       {
+               if (tk->type == (TKL_KILL|TKL_GLOBAL))
+               {
+                       sendto_one(cptr, rpl_str(RPL_STATSGLINE), me.name, cptr->name, 
+                               'G', tk->usermask, tk->hostmask, (tk->expire_at - curtime),
+                               (curtime - tk->set_at), tk->setby, tk->reason);
+               }
+       } 
+       for (tk = tklines; tk; tk = tk->next)
+       {
+               if (tk->type == (TKL_ZAP|TKL_GLOBAL))
+               {
+                       sendto_one(cptr, rpl_str(RPL_STATSGLINE), me.name, cptr->name, 
+                               'Z', tk->usermask, tk->hostmask, (tk->expire_at - curtime),
+                               (curtime - tk->set_at), tk->setby, tk->reason);
+               }
+       } 
+       for (tk = tklines; tk; tk = tk->next)
+       {
+               if (tk->type == (TKL_KILL))
+               {
+                       sendto_one(cptr, rpl_str(RPL_STATSGLINE), me.name, cptr->name, 
+                               'K', tk->usermask, tk->hostmask, (tk->expire_at - curtime),
+                               (curtime - tk->set_at), tk->setby, tk->reason);
+               }
+       } 
+       for (tk = tklines; tk; tk = tk->next)
+       {
+               if (tk->type == (TKL_ZAP))
+               {
+                       sendto_one(cptr, rpl_str(RPL_STATSGLINE), me.name, cptr->name, 
+                               'z', tk->usermask, tk->hostmask, (tk->expire_at - curtime),
+                               (curtime - tk->set_at), tk->setby, tk->reason);
+               }
+       } 
+
+}
+
+void   tkl_synch(aClient *sptr)
+{
+       aTKline *tk;
+       
+               
+       for (tk = tklines; tk; tk = tk->next)
+       {
+               if (tk->type & TKL_GLOBAL)
+               {
+                       if ((tk->type & TKL_KILL) && !SupportSJOIN(sptr))
+                               sendto_one(sptr, ":%s GLINE %s@%s %li %li %s :%s", me.name,
+                                       tk->usermask, tk->hostmask, tk->expire_at, tk->set_at, tk->setby, tk->reason);
+                       else
+                               sendto_one(sptr, ":%s %s + %s %s %s %s %li %li :%s",
+                                       me.name, IsToken(sptr) ? TOK_TKL : MSG_TKL, 
+                                       (tk->type & TKL_KILL ? "G" : "Z"), tk->usermask, tk->hostmask,
+                                       tk->setby,  tk->expire_at, tk->set_at, tk->reason);
+               }
+       }
+}
+
+/*
+  Service function for timed *:lines
+  
+  add:  TKL + type user host setby expire_at set_at reason
+  del:  TKL - type user host removedby
+  list: TKL ?
+
+  only global lines are spread out this way.
+     type= G = G:Line
+           Z = Z:Line  
+*/
+
+int     m_tkl(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+       aTKline *tk;
+       int     type;
+       int     found = 0;
+       char    gmt[256], gmt2[256];
+       char    txt[256];
+       time_t  expiry_1, setat_1;
+
+       
+       if (!IsServer(sptr) && !IsOper(sptr) && !IsMe(sptr))
+               return 0;
+       if (parc < 2)
+               return 0;
+       
+       tkl_check_expire();
+       
+       switch (*parv[1])
+       {
+               case    '+': {
+                       /* we relay on servers to be failsafe.. */
+                       if (!IsServer(sptr) && !IsMe(sptr))
+                               return 0;
+                       if (parc < 9)
+                               return 0;
+                               
+                       if (*parv[2] == 'G')
+                               type = TKL_KILL|TKL_GLOBAL;
+                       else if (*parv[2] == 'Z')
+                               type = TKL_ZAP|TKL_GLOBAL;
+                       else if (*parv[2] == 'z')
+                               type = TKL_ZAP;
+                       else if (*parv[2] == 'k') 
+                               type = TKL_KILL;
+                       else return 0;
+                       
+                       found = 0;
+                       for (tk = tklines; tk; tk = tk->next)
+                       {
+                               if (tk->type == type)
+                               {
+                                       if (!strcmp(tk->hostmask, parv[4]) 
+                                           && !strcmp(tk->usermask, parv[3]))
+                                       {
+                                               found = 1;
+                                               break;
+                                       }
+                               }
+                       }
+                       /* G:Line already exists, don't add */
+                       if (found == 1)
+                               return 0;
+                       
+                       tkl_add_line(type, parv[3], parv[4], parv[8], parv[5], atol(parv[6]), atol(parv[7]));
+                       
+                       expiry_1 = atol(parv[6]);
+                       setat_1 = atol(parv[7]);
+                       
+                       strncpy(gmt, asctime(gmtime((clock_t*)&setat_1)), sizeof(gmt));
+                       strncpy(gmt2, asctime(gmtime((clock_t*)&expiry_1)), sizeof(gmt2));
+                       gmt[strlen(gmt) - 1] = '\0';
+                       gmt2[strlen(gmt2) - 1] = '\0';
+                       
+                       switch(type)
+                       {
+                               case TKL_KILL:
+                                       strcpy(txt, "Timed K:Line");
+                                       break;
+                               case TKL_ZAP:
+                                       strcpy(txt, "Timed Z:Line");
+                                       break;
+                               case TKL_KILL|TKL_GLOBAL:
+                                       strcpy(txt, "G:Line");
+                                       break;
+                               case TKL_ZAP|TKL_GLOBAL:
+                                       strcpy(txt, "Global Z:line");
+                                       break;
+                               default:
+                                       strcpy(txt, "Unknown *:Line");
+                       }
+                                                                                                                                               
+                       sendto_umode(UMODE_EYES, "*** %s added for %s@%s on %s GMT (from %s to expire at %s GMT: %s)",
+                               txt,                            
+                               parv[3], parv[4], gmt, parv[5], gmt2, parv[8]);
+                       ircd_log("%s added for %s@%s on %s GMT (from %s to expire at %s GMT: %s)",
+                               txt,
+                               parv[3], parv[4], gmt, parv[5], gmt2, parv[8]);
+                       tkl_sweep();
+                       if (type & TKL_GLOBAL)
+                       {
+                               sendto_serv_sjoin(cptr, ":%s TKL %s %s %s %s %s %s :%s",
+                                       sptr->name, parv[1], parv[2], parv[3], parv[4],
+                                       parv[5], parv[6], parv[7], parv[8]);
+                               if (type & TKL_KILL)
+                                       sendto_serv_butone_sjoin(cptr, ":%s GLINE %s@%s %s %s %s :%s",
+                                               me.name, parv[3], parv[4], parv[6], parv[7], parv[5], 
+                                               parv[8]);
+                       }
+                       return 0;                               
+               }
+               case    '-':
+                       if (!IsServer(sptr) && !IsMe(sptr))
+                               return 0;
+                       if (*parv[2] == 'G')
+                               type = TKL_KILL|TKL_GLOBAL;
+                       else if (*parv[2] == 'Z')
+                               type = TKL_ZAP|TKL_GLOBAL;
+                       else if (*parv[2] == 'z')
+                               type = TKL_ZAP;
+                       else if (*parv[2] == 'k') 
+                               type = TKL_KILL;
+                       else return 0;
+
+                       switch(type)
+                       {
+                               case TKL_KILL:
+                                       strcpy(txt, "Timed K:Line");
+                                       break;
+                               case TKL_ZAP:
+                                       strcpy(txt, "Timed Z:Line");
+                                       break;
+                               case TKL_KILL|TKL_GLOBAL:
+                                       strcpy(txt, "G:Line");
+                                       break;
+                               case TKL_ZAP|TKL_GLOBAL:
+                                       strcpy(txt, "Global Z:line");
+                                       break;
+                               default:
+                                       strcpy(txt, "Unknown *:Line");
+                       }
+                       
+                       found = 0;
+                       for (tk = tklines; tk; tk = tk->next)
+                       {
+                               if (tk->type == type)
+                               {
+                                       if (!strcmp(tk->hostmask, parv[4]) 
+                                           && !strcmp(tk->usermask, parv[3]))
+                                       {
+                                               strncpy(gmt, asctime(gmtime((clock_t*)&tk->set_at)), sizeof(gmt));
+                                               gmt[strlen(gmt) - 1] = '\0';
+                                               sendto_umode(UMODE_EYES, "%s removed %s %s@%s (set at %s - reason: %s)",
+                                                       parv[5], txt,
+                                                       tk->usermask, tk->hostmask, 
+                                                       gmt, tk->reason);
+                                               tkl_del_line(tk);
+                                                                                               if (type & TKL_GLOBAL)
+                                                       sendto_serv_sjoin(cptr, ":%s TKL %s %s %s %s %s",
+                                                               sptr->name, parv[1], parv[2], parv[3], parv[4], parv[5]);
+                                               if (type & (TKL_GLOBAL|TKL_KILL))
+                                                       sendto_serv_butone_sjoin(cptr, ":%s REMGLINE %s@%s", me.name, parv[3], parv[4]);
+                                               break;
+                                       }
+                               }
+                       }
+                                       
+                       break;
+                       
+               case    '?':
+                       if (IsAnOper(sptr))
+                               tkl_stats(sptr);
+       }
+}
+
+/*
+** m_gline (oper function - /TKL takes care of distribution)
+** /gline [+|-]u@h mask time :reason
+**
+** parv[0] = sender
+** parv[1] = [+|-]u@h mask
+** parv[2] = for how long
+** parv[3] = reason
+*/
+
+int m_gline (aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+       aTKline *tk;
+       time_t  secs;
+       int     whattodo = 0; /* 0 = add  1 = del */
+       int     found = 0;
+       int     i;
+       char    *mask    = NULL;
+       char    mo[1024], mo2[1024];
+       char    *p, *usermask, *hostmask;
+       char    *tkllayer[9] = 
+               {
+                       me.name,        /*0  server.name*/
+                       NULL,           /*1  +|- */
+                       "G",            /*2  G   */
+                       NULL,           /*3  user */
+                       NULL,           /*4  host */
+                       NULL,           /*5  setby */
+                       NULL,           /*6  expire_at */
+                       NULL,           /*7  set_at */
+                       NULL            /*8  reason */  
+               };
+       
+       if (parc == 1)
+       {
+               tkl_stats(sptr);
+               return 0;
+       }       
+       
+       if (IsServer(sptr))
+       {
+               tkllayer[1] = "+";
+               tkllayer[2] = "G";
+               tkllayer[3] = strtok(parv[1], "@");
+               tkllayer[4] = strtok(NULL, "@");
+               tkllayer[5] = parv[4];
+               tkllayer[6] = parv[2];
+               tkllayer[7] = parv[3];
+               tkllayer[8] = parv[5];
+               m_tkl(&me, &me, 9, tkllayer);                   
+               return;
+       }
+       if (!IsOper(sptr))
+       {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
+               return 0;
+       }
+       
+       if (parc < 2)
+       {
+               sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                       me.name, sptr->name, "GLINE");
+               return;
+       }
+       
+       mask = parv[1];
+       if (*mask == '-')
+       {
+               if (parc < 2)
+               {
+                       sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                               me.name, sptr->name, "GLINE");
+                       return;
+               }
+               whattodo = 1;
+               mask++;
+       }
+               else
+       if (*mask == '+')
+       {
+               if (parc < 4)
+               {
+                       sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                               me.name, sptr->name, "GLINE");
+                       return;
+               }
+               whattodo = 0;
+               mask++;
+       }
+       if (whattodo == 0)
+       {
+               if (parc < 4)
+               {
+                       sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                               me.name, sptr->name, "GLINE");
+                       return;
+               }
+       }
+
+       /* Check if its a hostmask and legal .. */
+       p = strchr(mask, '@');
+       if (!p || (p == mask))
+       {
+               sendto_one(sptr, ":%s NOTICE %s :*** [G:Line error] Please use a user@host mask.", me.name, sptr->name); 
+               return 0;
+       }
+
+       if (whattodo == 1)
+               goto nochecks;
+       if (p)
+       {
+               p++;
+               i = 0;
+               while (*p)
+               {
+                       if (*p != '*' && *p != '.') i++;
+                       p++;
+               }
+               if (i<4)
+               {
+                       sendto_one(sptr, ":%s NOTICE %s :*** [G:Line error] Too broad mask", me.name, sptr->name);
+                       return 0;
+               }
+       }
+
+nochecks:
+       usermask = strtok(mask, "@");
+       hostmask = strtok(NULL, "@");
+       tkl_check_expire();
+
+       for (tk = tklines; tk; tk = tk->next)
+       {
+               if (tk->type = (TKL_GLOBAL|TKL_KILL))
+               {
+                       if (!match(tk->hostmask, usermask) 
+                           && !match(tk->usermask, hostmask))
+                       {
+                               found = 1;
+                               break;
+                       }
+               }
+       }
+
+       if ((found == 1) && whattodo == 0)
+       {
+               sendto_one(sptr, ":%s NOTICE %s :*** [G:Line error] Match already exists!", me.name, sptr->name);
+               return 0;               
+       }
+       if ((found == 1) && whattodo == 1)
+       {
+               sendto_one(sptr, ":%s NOTICE %s :*** [G:Line error] No such G:Line", me.name, sptr->name);
+               return 0;               
+       }
+       if (whattodo == 0)
+       {
+               secs = atol(parv[2]);
+               if (secs < 1)
+               {
+                       sendto_one(sptr, ":%s NOTICE %s :*** [G:Line error] Please specify a positive value for time", me.name, sptr->name);
+                       return 0;
+               }       
+       }
+       tkllayer[1] = whattodo == 0 ? "+" : "-";        
+       tkllayer[3] = usermask;
+       tkllayer[4] = hostmask;
+       tkllayer[5] = make_nick_user_host(sptr->name, sptr->user->username, (IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost));
+       if (whattodo == 0)
+       {
+               sprintf(mo, "%li", secs+TStime());
+               sprintf(mo2, "%li", TStime());
+               tkllayer[6] = mo;
+               tkllayer[7] = mo2;
+               tkllayer[8] = parv[3];
+               /* call the tkl layer .. */
+               m_tkl(&me, &me, 9, tkllayer);
+       }
+        else
+       {
+               /* call the tkl layer .. */
+               m_tkl(&me, &me, 6, tkllayer);
+
+       }
+} 
\ No newline at end of file
diff --git a/src/s_misc.c b/src/s_misc.c
new file mode 100644 (file)
index 0000000..133c9db
--- /dev/null
@@ -0,0 +1,852 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.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.
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_misc.c  2.42 3/1/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "userload.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
+    !defined(__convex__) && !defined(_WIN32)
+# include <sys/param.h>
+#endif
+#if defined(PCS) || defined(AIX) || defined(SVR3)
+# include <time.h>
+#endif
+#ifdef HPUX
+#include <unistd.h>
+#endif
+#ifdef DYNIXPTX
+#include <sys/types.h>
+#include <time.h>
+#endif
+#ifdef _WIN32
+# include <io.h>
+#endif
+#include "h.h"
+#include "channel.h"
+
+#ifndef NO_FDLIST
+extern fdlist serv_fdlist;
+extern fdlist oper_fdlist;
+extern float  currentrate;
+extern float  currentrate2;
+#endif
+
+ID_CVS("$Id$");
+static void    exit_one_client PROTO((aClient *,aClient *,aClient *,char *));
+static void    exit_one_client_in_split PROTO((aClient *,aClient *,aClient *,char *));
+
+static char    *months[] = {
+       "January",      "February",     "March",        "April",
+       "May",          "June",         "July",         "August",
+       "September",    "October",      "November",     "December"
+};
+
+static char    *weekdays[] = {
+       "Sunday",       "Monday",       "Tuesday",      "Wednesday",
+       "Thursday",     "Friday",       "Saturday"
+};
+
+/*
+ * stats stuff
+ */
+struct stats   ircst, *ircstp = &ircst;
+
+char   *date(clock) 
+time_t clock;
+{
+       static  char    buf[80], plus;
+       Reg1    struct  tm *lt, *gm;
+       struct  tm      gmbuf;
+       int     minswest;
+
+       if (!clock) 
+               time(&clock);
+       gm = gmtime(&clock);
+       bcopy((char *)gm, (char *)&gmbuf, sizeof(gmbuf));
+       gm = &gmbuf;
+       lt = localtime(&clock);
+
+       if (lt->tm_yday == gm->tm_yday)
+               minswest = (gm->tm_hour - lt->tm_hour) * 60 +
+                          (gm->tm_min - lt->tm_min);
+       else if (lt->tm_yday > gm->tm_yday)
+               minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
+       else
+               minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
+
+       plus = (minswest > 0) ? '-' : '+';
+       if (minswest < 0)
+               minswest = -minswest;
+
+       (void)sprintf(buf, "%s %s %d %d -- %02d:%02d %c%02d:%02d",
+               weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday,
+               1900+lt->tm_year,
+               lt->tm_hour, lt->tm_min,
+               plus, minswest/60, minswest%60);
+
+       return buf;
+}
+
+/*
+ *  Fixes a string so that the first white space found becomes an end of
+ * string marker (`\-`).  returns the 'fixed' string or "*" if the string
+ * was NULL length or a NULL pointer.
+ */
+char   *check_string(s)
+Reg1   char *s;
+{
+       static  char    star[2] = "*";
+       char    *str = s;
+
+       if (BadPtr(s))
+               return star;
+
+       for ( ;*s; s++)
+               if (isspace(*s))
+                   {
+                       *s = '\0';
+                       break;
+                   }
+
+       return (BadPtr(str)) ? star : str;
+}
+
+/*
+ * create a string of form "foo!bar@fubar" given foo, bar and fubar
+ * as the parameters.  If NULL, they become "*".
+ */
+char *make_nick_user_host(nick, name, host)
+Reg1   char    *nick, *name, *host;
+{
+       static  char    namebuf[NICKLEN+USERLEN+HOSTLEN+6];
+       Reg2    char    *s = namebuf;
+
+       bzero(namebuf, sizeof(namebuf));
+       nick = check_string(nick);
+       strncpyzt(namebuf, nick, NICKLEN + 1);
+       s += strlen(s);
+       *s++ = '!';
+       name = check_string(name);
+       strncpyzt(s, name, USERLEN + 1);
+       s += strlen(s);
+       *s++ = '@';
+       host = check_string(host);
+       strncpyzt(s, host, HOSTLEN + 1);
+       s += strlen(s);
+       *s = '\0';
+       return (namebuf);
+}
+
+/**
+ ** myctime()
+ **   This is like standard ctime()-function, but it zaps away
+ **   the newline from the end of that string. Also, it takes
+ **   the time value as parameter, instead of pointer to it.
+ **   Note that it is necessary to copy the string to alternate
+ **   buffer (who knows how ctime() implements it, maybe it statically
+ **   has newline there and never 'refreshes' it -- zapping that
+ **   might break things in other places...)
+ **
+ **/
+
+char   *myctime(value)
+time_t value;
+{
+       static  char    buf[28];
+       Reg1    char    *p;
+
+       (void)strcpy(buf, ctime(&value));
+       if ((p = (char *)index(buf, '\n')) != NULL)
+               *p = '\0';
+
+       return buf;
+}
+
+/*
+** check_registered_user is used to cancel message, if the
+** originator is a server or not registered yet. In other
+** words, passing this test, *MUST* guarantee that the
+** sptr->user exists (not checked after this--let there
+** be coredumps to catch bugs... this is intentional --msa ;)
+**
+** There is this nagging feeling... should this NOT_REGISTERED
+** error really be sent to remote users? This happening means
+** that remote servers have this user registered, althout this
+** one has it not... Not really users fault... Perhaps this
+** error message should be restricted to local clients and some
+** other thing generated for remotes...
+*/
+int    check_registered_user(sptr)
+aClient        *sptr;
+{
+       if (!IsRegisteredUser(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
+               return -1;
+           }
+       return 0;
+}
+
+/*
+** check_registered user cancels message, if 'x' is not
+** registered (e.g. we don't know yet whether a server
+** or user)
+*/
+int    check_registered(sptr)
+aClient        *sptr;
+{
+       if (!IsRegistered(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
+               return -1;
+           }
+       return 0;
+}
+
+/*
+** get_client_name
+**      Return the name of the client for various tracking and
+**      admin purposes. The main purpose of this function is to
+**      return the "socket host" name of the client, if that
+**     differs from the advertised name (other than case).
+**     But, this can be used to any client structure.
+**
+**     Returns:
+**       "name[user@ip#.port]" if 'showip' is true;
+**       "name[sockethost]", if name and sockhost are different and
+**       showip is false; else
+**       "name".
+**
+** NOTE 1:
+**     Watch out the allocation of "nbuf", if either sptr->name
+**     or sptr->sockhost gets changed into pointers instead of
+**     directly allocated within the structure...
+**
+** NOTE 2:
+**     Function return either a pointer to the structure (sptr) or
+**     to internal buffer (nbuf). *NEVER* use the returned pointer
+**     to modify what it points!!!
+*/
+char   *get_client_name(sptr, showip)
+aClient *sptr;
+int    showip;
+{
+       static char nbuf[HOSTLEN * 2 + USERLEN + 5];
+
+       if (MyConnect(sptr))
+           {
+               if (IsUnixSocket(sptr))
+                   {
+                       if (showip)
+                               (void) sprintf(nbuf, "%s[%s]",
+                                       sptr->name, sptr->sockhost);
+                       else
+                               (void) sprintf(nbuf, "%s[%s]",
+                                       sptr->name, me.sockhost);
+                   }
+               else
+                   {
+                       if (showip)
+                               (void)sprintf(nbuf, "%s[%s@%s.%u]",
+                                       sptr->name,
+                                       (!(sptr->flags & FLAGS_GOTID)) ? "" :
+                                       sptr->username,
+                                       inetntoa((char *)&sptr->ip),
+                                       (unsigned int)sptr->port);
+                       else
+                           {
+                               if (mycmp(sptr->name, sptr->sockhost))
+                                       (void)sprintf(nbuf, "%s[%s]",
+                                               sptr->name, sptr->sockhost);
+                               else
+                                       return sptr->name;
+                           }
+                   }
+               return nbuf;
+           }
+       return sptr->name;
+}
+
+char   *get_client_host(cptr)
+aClient        *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))
+               (void) sprintf(nbuf, "%s[%s]", cptr->name, me.name);
+       else
+               (void)sprintf(nbuf, "%s[%-.*s@%-.*s]",
+                       cptr->name, USERLEN,
+                       (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->username,
+                       HOSTLEN, cptr->hostp->h_name);
+       return nbuf;
+}
+
+/*
+ * Form sockhost such that if the host is of form user@host, only the host
+ * portion is copied.
+ */
+void   get_sockhost(cptr, host)
+Reg1   aClient *cptr;
+Reg2   char    *host;
+{
+       Reg3    char    *s;
+       if ((s = (char *)index(host, '@')))
+               s++;
+       else
+               s = host;
+       strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
+}
+
+/*
+ * Return wildcard name of my server name according to given config entry
+ * --Jto
+ */
+char   *my_name_for_link(name, aconf)
+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 = (char *)index(name, '.');
+           }
+       if (!name)
+               return start;
+
+       namebuf[0] = '*';
+       (void)strncpy(&namebuf[1], name, HOSTLEN - 1);
+       namebuf[HOSTLEN - 1] = '\0';
+
+       return namebuf;
+}
+
+/*
+** exit_client
+**     This is old "m_bye". Name  changed, because this is not a
+**     protocol function, but a general server utility function.
+**
+**     This function exits a client of *any* type (user, server, etc)
+**     from this server. Also, this generates all necessary prototol
+**     messages that this exit may cause.
+**
+**   1) If the client is a local client, then this implicitly
+**     exits all other clients depending on this connection (e.g.
+**     remote clients having 'from'-field that points to this.
+**
+**   2) If the client is a remote client, then only this is exited.
+**
+** For convenience, this function returns a suitable value for
+** m_funtion return value:
+**
+**     FLUSH_BUFFER    if (cptr == sptr)
+**     0               if (cptr != sptr)
+*/
+int    exit_client(cptr, sptr, from, comment)
+aClient *cptr; /*
+               ** The local client originating the exit or NULL, if this
+               ** exit is generated by this server for internal reasons.
+               ** This will not get any of the generated messages.
+               */
+aClient *sptr; /* Client exiting */
+aClient *from; /* Client firing off this Exit, never NULL! */
+char   *comment;       /* Reason for the exit */
+    {
+       Reg1    aClient *acptr;
+       Reg2    aClient *next;
+#ifdef FNAME_USERLOG
+       time_t  on_for;
+#endif
+       static  char    comment1[HOSTLEN + HOSTLEN + 2];
+        static  int     recurse=0;
+
+       if (MyConnect(sptr))
+           {
+#ifndef NO_FDLIST
+               if (IsAnOper(sptr))
+                      delfrom_fdlist(sptr->fd, &oper_fdlist); 
+               if (IsServer(sptr))
+                   delfrom_fdlist(sptr->fd,&serv_fdlist);
+#endif
+
+               sptr->flags |= FLAGS_CLOSING;
+                if (IsPerson(sptr)) {
+                        sendto_umode(UMODE_OPER|UMODE_CLIENT,"*** Notice -- Client exiting: %s (%s@%s) [%s]", 
+                         sptr->name, sptr->user->username, sptr->user->realhost, comment);
+                        sendto_conn_hcn("*** Notice -- Client exiting: %s (%s@%s) [%s] [%s]",
+                               sptr->name, sptr->user->username,sptr->user->realhost, comment,
+                               sptr->sockhost);
+       
+               }
+               current_load_data.conn_count--;
+               if (IsPerson(sptr)) {
+                 char mydom_mask[HOSTLEN + 1];
+                 mydom_mask[0] = '\0';
+                 strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1);
+                 current_load_data.client_count--;
+                 if (match(mydom_mask, sptr->sockhost) == 0)
+                   current_load_data.local_count--;
+                 /* Clean out list and watch structures -Donwulff */
+                 hash_del_notify_list(sptr);
+                 if (sptr->lopt) {
+                   free_str_list(sptr->lopt->yeslist);
+                   free_str_list(sptr->lopt->nolist);
+                   MyFree(sptr->lopt);
+                 }
+               }
+               update_load();
+#ifdef FNAME_USERLOG
+               on_for = TStime() - sptr->firsttime;
+# if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
+               if (IsPerson(sptr))
+                       syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s@%s (%s)\n",
+                              myctime(sptr->firsttime),
+                              on_for / 3600, (on_for % 3600)/60,
+                              on_for % 60, sptr->user->username,
+                              sptr->sockhost, sptr->name);
+# else
+           {
+               char    linebuf[160];
+               int     logfile;
+
+               /*
+                * This conditional makes the logfile active only after
+                * it's been created - thus logging can be turned off by
+                * removing the file.
+                *
+                * stop NFS hangs...most systems should be able to open a
+                * file in 3 seconds. -avalon (curtesy of wumpus)
+                */
+               if (IsPerson(sptr) &&
+                   (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1)
+                   {
+                       (void)sprintf(linebuf,
+                               "%s (%3d:%02d:%02d): %s@%s [%s]\n",
+                               myctime(sptr->firsttime),
+                               on_for / 3600, (on_for % 3600)/60,
+                               on_for % 60,
+                               sptr->user->username, sptr->user->realhost,
+                               sptr->username);
+                       (void)write(logfile, linebuf, strlen(linebuf));
+                       (void)close(logfile);
+                   }
+               /* Modification by stealth@caen.engin.umich.edu */
+           }
+# endif
+#endif
+               if (sptr->fd >= 0 && !IsConnecting(sptr))
+                   {
+                     if (cptr != NULL && sptr != cptr)
+                       sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)",
+                                  get_client_name(sptr,FALSE),
+                                  cptr->name, comment);
+                     else
+                       sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
+                                  get_client_name(sptr,FALSE), comment);
+                   }
+               /*
+               ** Currently only server connections can have
+               ** depending remote clients here, but it does no
+               ** harm to check for all local clients. In
+               ** future some other clients than servers might
+               ** have remotes too...
+               **
+               ** Close the Client connection first and mark it
+               ** so that no messages are attempted to send to it.
+               ** (The following *must* make MyConnect(sptr) == FALSE!).
+               ** It also makes sptr->from == NULL, thus it's unnecessary
+               ** to test whether "sptr != acptr" in the following loops.
+               */
+               close_connection(sptr);
+           }
+
+       /*
+        * Recurse down the client list and get rid of clients who are no
+        * longer connected to the network (from my point of view)
+        * Only do this expensive stuff if exited==server -Donwulff
+        */
+
+       if (IsServer(sptr)) {
+               /*
+                * Is this right? Not recreateing the split message if
+                * we have been called recursivly? I hope so, cuz thats
+                * the only way I could make this give the right servers
+                * in the quit msg. -Cabal95
+                */
+               if (cptr && !recurse) {
+                       (void)strcpy(comment1, sptr->srvptr->name);
+                       (void)strcat(comment1, " ");
+                       (void)strcat(comment1, sptr->name);
+               }
+               /*
+                * First, remove the clients on the server itself.
+                */
+               for (acptr = client; acptr; acptr=next) {
+                       next = acptr->next;
+                       if (IsClient(acptr) && (acptr->srvptr == sptr))
+                               exit_one_client_in_split(NULL, acptr,
+                                       &me, comment1);
+#ifdef DEBUGMODE
+                       else if (IsClient(acptr) &&
+                           (find_server(acptr->user->server,NULL)==sptr)) {
+                               sendto_ops("WARNING, srvptr!=sptr but "
+                                       "find_server did!  User %s on %s "
+                                       "thought it was on %s while "
+                                       "loosing %s.  Tell coding team.",
+                                       acptr->name, acptr->user->server,
+                                       acptr->srvptr?acptr->srvptr->name:"<noserver>",
+                                       sptr->name);
+                               exit_one_client_in_split(NULL, acptr,
+                                       &me, comment1);
+                       }
+#endif
+               }
+
+               /*
+                * Now, go SQUIT off the servers which are down-stream of
+                * the one we just lost.
+                */
+               recurse++;
+               for (acptr = client; acptr; acptr=next) {
+                       next = acptr->next;
+                       if (IsServer(acptr) && acptr->srvptr == sptr)
+                               exit_client(sptr, acptr, /* RECURSION */
+                                           sptr, comment1);
+                       /*
+                        * I am not masking SQUITS like I do QUITs.  This
+                        * is probobly something we could easily do, but
+                        * how much savings is there really in something
+                        * like that?
+                        */
+#ifdef DEBUGMODE
+                       else if (IsServer(acptr) &&
+                           (find_server(acptr->serv->up, NULL)==sptr)) {
+                               sendto_ops("WARNING, srvptr!=sptr but "
+                                       "find_server did!  Server %s on "
+                                       "%s thought it was on %s while "
+                                       "loosing %s.  Tell coding team.",
+                                       acptr->name, acptr->serv->up,
+                                       acptr->srvptr?acptr->srvptr->name:"<noserver>",
+                                       sptr->name);
+                               exit_client(sptr, acptr, sptr, comment1);
+                       }
+#endif
+               }
+               recurse--;
+       }
+
+       /*
+        * Finally, clear out the server we lost itself
+        */
+       exit_one_client(cptr, sptr, from, comment);
+       return cptr == sptr ? FLUSH_BUFFER : 0;
+    }
+
+/*
+** Exit one client, local or remote. Assuming all dependants have
+** been already removed, and socket closed for local client.
+*/
+/* DANGER: Ugly hack follows. */
+/* Yeah :/ */
+static void    exit_one_client_backend(cptr, sptr, from, comment, split)
+aClient *sptr;
+aClient *cptr;
+aClient *from;
+char   *comment;
+int    split;
+{
+       Reg1    aClient *acptr;
+       Reg2    int     i;
+       Reg3    Link    *lp;
+
+       /*
+       **  For a server or user quitting, propagage the information to
+       **  other servers (except to the one where is came from (cptr))
+       */
+       if (IsMe(sptr))
+           {
+               sendto_ops("ERROR: tried to exit me! : %s", comment);
+               return; /* ...must *never* exit self!! */
+           }
+       else if (IsServer(sptr)) {
+        /*
+        ** 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++)
+                   {
+                       Reg4    aConfItem *aconf;
+
+                       if (!(acptr = local[i]) || !IsServer(acptr) ||
+                           acptr == cptr || IsMe(acptr))
+                               continue;
+                       if ((aconf = acptr->serv->nline) &&
+                           (match(my_name_for_link(me.name, aconf),
+                                    sptr->name) == 0))
+                               continue;
+                       /*
+                       ** SQUIT going "upstream". This is the remote
+                       ** squit still hunting for the target. Use prefixed
+                       ** form. "from" will be either the oper that issued
+                       ** the squit or some server along the path that
+                       ** didn't have this fix installed. --msa
+                       */
+                       if (sptr->from == acptr)
+                           {
+                               sendto_one(acptr, ":%s SQUIT %s :%s",
+                                          from->name, sptr->name, comment);
+                           }
+                       else
+                           {
+                               sendto_one(acptr, "SQUIT %s :%s",
+                                          sptr->name, comment);
+                           }
+           }
+       } else if (!(IsPerson(sptr) || IsService(sptr)))
+                                   /* ...this test is *dubious*, would need
+                                   ** some thougth.. but for now it plugs a
+                                   ** nasty hole in the server... --msa
+                                   */
+               ; /* Nothing */
+       else if (sptr->name[0]) /* ...just clean all others with QUIT... */
+           {
+               /*
+               ** If this exit is generated from "m_kill", then there
+               ** is no sense in sending the QUIT--KILL's have been
+               ** sent instead.
+               */
+               if ((sptr->flags & FLAGS_KILLED) == 0)
+                   {
+                       if (split == 0)
+                       sendto_serv_butone(cptr,":%s QUIT :%s",
+                                          sptr->name, comment);
+                       else
+                               /*
+                                * Then this is a split, only old (stupid)
+                                * clients need to get quit messages
+                                */
+                               sendto_serv_butone_quit(cptr, ":%s QUIT :%s",
+                                       sptr->name, comment);
+                   }
+               /*
+               ** If a person is on a channel, send a QUIT notice
+               ** to every client (person) on the same channel (so
+               ** that the client can show the "**signoff" message).
+               ** (Note: The notice is to the local clients *only*)
+               */
+               if (sptr->user)
+                   {
+                       sendto_common_channels(sptr, ":%s QUIT :%s",
+                                               sptr->name, comment);
+
+                       if (!IsULine(cptr,sptr) && !MyClient(sptr) && !split)
+                               sendto_umode(UMODE_FCLIENT, "*** Notice -- Client exiting at %s: %s!%s@%s (%s)",
+                                       sptr->user->server, sptr->name, sptr->user->username, sptr->user->realhost,
+                                               comment);
+                       while ((lp = sptr->user->channel))
+                               remove_user_from_channel(sptr,lp->value.chptr);
+
+                       /* Clean up invitefield */
+                       while ((lp = sptr->user->invited))
+                               del_invite(sptr, lp->value.chptr);
+                               /* again, this is all that is needed */
+
+                       /* Clean up silencefield */
+                       while ((lp = sptr->user->silence))
+                               (void)del_silence(sptr, lp->value.cp);
+                   }
+           }
+
+       /* Remove sptr from the client list */
+       if (del_from_client_hash_table(sptr->name, sptr) != 1)
+               Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
+                       sptr, sptr->name,
+                       sptr->from ? sptr->from->sockhost : "??host",
+                       sptr->from, sptr->next, sptr->prev, sptr->fd,
+                       sptr->status, sptr->user));
+       if (IsRegisteredUser(sptr))
+               hash_check_notify(sptr, RPL_LOGOFF);
+       remove_client_from_list(sptr);
+       return;
+}
+
+static void    exit_one_client(cptr, sptr, from, comment)
+aClient        *sptr, *cptr, *from;
+char   *comment;
+{
+       exit_one_client_backend(cptr, sptr, from, comment, 0);
+}
+
+static void    exit_one_client_in_split(cptr, sptr, from, comment)
+aClient        *sptr, *cptr, *from;
+char   *comment;
+{
+       exit_one_client_backend(cptr, sptr, from, comment, 1);
+}
+
+
+void   checklist()
+{
+       Reg1    aClient *acptr;
+       Reg2    int     i,j;
+
+       if (!(bootopt & BOOT_AUTODIE))
+               return;
+       for (j = i = 0; i <= highest_fd; i++)
+               if (!(acptr = local[i]))
+                       continue;
+               else if (IsClient(acptr))
+                       j++;
+       if (!j)
+           {
+#ifdef USE_SYSLOG
+               syslog(LOG_WARNING,"ircd exiting: autodie");
+#endif
+               exit(0);
+           }
+       return;
+}
+
+void   initstats()
+{
+       bzero((char *)&ircst, sizeof(ircst));
+}
+
+void   tstats(cptr, name)
+aClient        *cptr;
+char   *name;
+{
+       Reg1    aClient *acptr;
+       Reg2    int     i;
+       Reg3    struct stats    *sp;
+       struct  stats   tmp;
+       time_t  now = TStime();
+
+       sp = &tmp;
+       bcopy((char *)ircstp, (char *)sp, sizeof(*sp));
+#ifndef _WIN32
+       for (i = 0; i < MAXCONNECTIONS; i++)
+#else
+       for (i = 0; i < highest_fd; i++)
+#endif
+           {
+               if (!(acptr = local[i]))
+                       continue;
+               if (IsServer(acptr))
+                   {
+                       sp->is_sbs += acptr->sendB;
+                       sp->is_sbr += acptr->receiveB;
+                       sp->is_sks += acptr->sendK;
+                       sp->is_skr += acptr->receiveK;
+                       sp->is_sti += now - acptr->firsttime;
+                       sp->is_sv++;
+                       if (sp->is_sbs > 1023)
+                           {
+                               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;
+                           }
+                   }
+               else if (IsClient(acptr))
+                   {
+                       sp->is_cbs += acptr->sendB;
+                       sp->is_cbr += acptr->receiveB;
+                       sp->is_cks += acptr->sendK;
+                       sp->is_ckr += acptr->receiveK;
+                       sp->is_cti += now - acptr->firsttime;
+                       sp->is_cl++;
+                       if (sp->is_cbs > 1023)
+                           {
+                               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;
+                           }
+                   }
+               else if (IsUnknown(acptr))
+                       sp->is_ni++;
+           }
+
+       sendto_one(cptr, ":%s %d %s :accepts %u refused %u",
+                  me.name, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
+       sendto_one(cptr, ":%s %d %s :unknown commands %u prefixes %u",
+                  me.name, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
+       sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u",
+                  me.name, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni);
+       sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u",
+                  me.name, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
+       sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u",
+                  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 :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);
+       sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK",
+                  me.name, RPL_STATSDEBUG, name,
+                  sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
+       sendto_one(cptr, ":%s %d %s :bytes recv %u.%uK %u.%uK",
+                  me.name, RPL_STATSDEBUG, name,
+                  sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
+       sendto_one(cptr, ":%s %d %s :time connected %u %u",
+                  me.name, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
+#ifndef NO_FDLIST
+       sendto_one(cptr, ":%s %d %s :incoming rate %0.2f kb/s - outgoing rate %0.2f kb/s",
+                  me.name, RPL_STATSDEBUG, name, currentrate, currentrate2);
+#endif
+}
+
diff --git a/src/s_numeric.c b/src/s_numeric.c
new file mode 100644 (file)
index 0000000..a8ecad8
--- /dev/null
@@ -0,0 +1,133 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/s_numeric.c
+ *   Copyright (C) 1990 Jarkko Oikarinen
+ *
+ *   Numerous fixes by Markku Savela
+ *
+ *   This program is free software; you can 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.
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_numeric.c       2.14 1/30/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h" 
+#include "numeric.h"
+#include "h.h"
+
+ID_CVS("$Id$");
+
+static char buffer[1024];
+
+/*
+** DoNumeric (replacement for the old do_numeric)
+**
+**     parc    number of arguments ('sender' counted as one!)
+**     parv[0] pointer to 'sender' (may point to empty string) (not used)
+**     parv[1]..parv[parc-1]
+**             pointers to additional parameters, this is a NULL
+**             terminated list (parv[parc] == NULL).
+**
+** *WARNING*
+**     Numerics are mostly error reports. If there is something
+**     wrong with the message, just *DROP* it! Don't even think of
+**     sending back a neat error message -- big danger of creating
+**     a ping pong error message...
+*/
+int    do_numeric(numeric, cptr, sptr, parc, parv)
+int    numeric;
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       aChannel *chptr;
+       char    *nick, *p;
+       int     i;
+
+       if (parc < 1 || !IsServer(sptr))
+               return 0;
+       /* Remap low number numerics. */
+       if (numeric < 100)
+               numeric += 100;
+       /*
+       ** Prepare the parameter portion of the message into 'buffer'.
+       ** (Because the buffer is twice as large as the message buffer
+       ** for the socket, no overflow can occur here... ...on current
+       ** assumptions--bets are off, if these are changed --msa)
+       ** Note: if buffer is non-empty, it will begin with SPACE.
+       */
+       buffer[0] = '\0';
+       if (parc > 2)
+           {
+               for (i = 2; i < (parc - 1); i++)
+                   {
+                       (void)strcat(buffer, " ");
+                       (void)strcat(buffer, parv[i]);
+                   }
+               (void)strcat(buffer, " :");
+               (void)strcat(buffer, parv[parc-1]);
+           } else sendto_realops("do_numeric( %i, %s, %s, %i, { %s, %s } )!",
+                                       numeric, cptr->name, sptr->name, parc,
+                                       parv[0], parv[1]?parv[1]:"<null>");
+       for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL)
+           {
+               if ((acptr = find_client(nick, (aClient *)NULL)))
+                   {
+                       /*
+                       ** Drop to bit bucket if for me...
+                       ** ...one might consider sendto_ops
+                       ** here... --msa
+                       ** And so it was done. -avalon
+                       ** And regretted. Dont do it that way. Make sure
+                       ** it goes only to non-servers. -avalon
+                       ** Check added to make sure servers don't try to loop
+                       ** with numerics which can happen with nick collisions.
+                       ** - Avalon
+                       */
+                       if (!IsMe(acptr) && IsPerson(acptr))
+                       {
+                       /* Added for .U3.2. drop remote 'You are not on
+                       ** that channel', we should be synced anyway,
+                       ** and this is an annoying message with TSpre7
+                       ** still on the net; would result in numeric 442 for
+                       ** every KICK... Can be removed when TSpre7 is gone.
+                       ** --Run
+                       */
+                               if (numeric==ERR_NOTONCHANNEL) return 0;
+
+                               sendto_prefix_one(acptr, sptr,":%s %d %s%s",
+                                       parv[0], numeric, nick, buffer);
+                       }
+                       else if (IsServer(acptr) && acptr->from != cptr)
+                               sendto_prefix_one(acptr, sptr,":%s %d %s%s",
+                                       parv[0], numeric, nick, buffer);
+                   }
+               else if ((acptr = find_server(nick, (aClient *)NULL)))
+                   {
+                       if (!IsMe(acptr) && acptr->from != cptr)
+                               sendto_prefix_one(acptr, sptr,":%s %d %s%s",
+                                       parv[0], numeric, nick, buffer);
+                   }
+               else if ((chptr = find_channel(nick, (aChannel *)NULL)))
+                       sendto_channel_butone(cptr,sptr,chptr,":%s %d %s%s",
+                                             parv[0],
+                                             numeric, chptr->chname, buffer);
+           }
+       return 0;
+}
diff --git a/src/s_serv.c b/src/s_serv.c
new file mode 100644 (file)
index 0000000..d9c8d61
--- /dev/null
@@ -0,0 +1,4146 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/s_serv.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.
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_serv.c  2.55 2/7/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include "version.h"
+#if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
+#include <time.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifndef _WIN32
+#include <utmp.h>
+#else
+#include <io.h>
+#endif
+#include <time.h>
+#include "h.h"
+
+ID_CVS("$Id$");
+
+
+static char    buf[BUFSIZE];
+
+int     max_connection_count = 1, max_client_count = 1;
+
+/*
+** 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.
+*/
+#ifndef NO_FDLIST
+extern fdlist serv_fdlist;
+#endif
+
+/*
+** m_version
+**     parv[0] = sender prefix
+**     parv[1] = remote server
+*/
+int    m_version(cptr, sptr, parc, parv)
+aClient *sptr, *cptr;
+int    parc;
+char   *parv[];
+{
+       extern  char    serveropts[];
+       char    *x;
+       
+       if (TRUEHUB == 1)
+               x = "(H)";
+       else
+               x = "";
+               if (check_registered(sptr))
+               return 0;
+
+       if (hunt_server(cptr,sptr,":%s VERSION :%s",1,parc,parv)==HUNTED_ISME)
+
+               sendto_one(sptr, rpl_str(RPL_VERSION), me.name,
+                          parv[0], version, ircnetwork, debugmode, me.name, 
+                          serveropts,
+                          (IsAnOper(sptr) ? MYOSNAME : "*"),
+                          UnrealProtocol,
+               x);
+       return 0;
+}
+
+/*int IsMe (acptr)
+aClient *acptr, server;
+{
+if (memcmp (acptr, server, sizeof(aClient)) == 0)
+return 1;
+return 0;
+ }*/
+
+
+/*
+** m_squit
+**     parv[0] = sender prefix
+**     parv[1] = server name
+**     parv[parc-1] = comment
+*/
+int    m_squit(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       Reg1    aConfItem *aconf;
+       char    *server;
+       Reg2    aClient *acptr;
+       char    *comment = (parc > 2 && parv[parc-1]) ?
+                    parv[parc-1] : cptr->name;
+
+         if (check_registered(sptr))
+                 return 0;
+
+       if (!IsPrivileged(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+
+       if (parc > 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.
+               */
+               while ((*server == '*') && IsServer(cptr))
+                   {
+                       aconf = cptr->serv->nline;
+                       if (!aconf)
+                               break;
+                       if (!mycmp(server, my_name_for_link(me.name, aconf)))
+                               server = cptr->name;
+                       break; /* WARNING is normal here */
+                   }
+               /*
+               ** 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 && IsMe(acptr))
+                   {
+                       acptr = cptr;
+                       server = cptr->sockhost;
+                   }
+           }
+       else
+           {
+               /*
+               ** This is actually protocol error. But, well, closing
+               ** the link is very proper answer to that...
+               */
+               server = cptr->sockhost;
+               acptr = cptr;
+           }
+
+       /*
+       ** SQUIT semantics is tricky, be careful...
+       **
+       ** The old (irc2.2PL1 and earlier) code just cleans away the
+       ** server client from the links (because it is never true
+       ** "cptr == acptr".
+       **
+       ** This logic here works the same way until "SQUIT host" hits
+       ** the server having the target "host" as local link. Then it
+       ** will do a real cleanup spewing SQUIT's and QUIT's to all
+       ** directions, also to the link from which the orinal SQUIT
+       ** came, generating one unnecessary "SQUIT host" back to that
+       ** link.
+       **
+       ** One may think that this could be implemented like
+       ** "hunt_server" (e.g. just pass on "SQUIT" without doing
+       ** nothing until the server having the link as local is
+       ** reached). Unfortunately this wouldn't work in the real life,
+       ** because either target may be unreachable or may not comply
+       ** with the request. In either case it would leave target in
+       ** links--no command to clear it away. So, it's better just
+       ** clean out while going forward, just to be sure.
+       **
+       ** ...of course, even better cleanout would be to QUIT/SQUIT
+       ** dependant users/servers already on the way out, but
+       ** currently there is not enough information about remote
+       ** clients to do this...   --msa
+       */
+       if (!acptr)
+           {
+               sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
+                          me.name, parv[0], server);
+               return 0;
+           }
+       if (MyClient(sptr) && ((!OPCanGRoute(sptr) && !MyConnect(acptr)) ||
+                              (!OPCanLRoute(sptr) && MyConnect(acptr))))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+       /*
+       **  Notify all opers, if my local link is remotely squitted
+       */
+       if (MyConnect(acptr) && !IsAnOper(cptr))
+         {
+         
+            sendto_locfailops("Received SQUIT %s from %s (%s)",
+                acptr->name, get_client_name(sptr,FALSE), comment);
+           sendto_serv_butone(&me, ":%s GLOBOPS :Received SQUIT %s from %s (%s)",
+               me.name, server, get_client_name(sptr,FALSE), comment);
+#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
+           syslog(LOG_DEBUG,"SQUIT From %s : %s (%s)",
+                  parv[0], server, comment);
+#endif
+         }
+       else if (MyConnect(acptr)) {
+               if (acptr->user) {
+                 sendto_one(sptr, ":%s NOTICE :*** Cannot do fake kill by SQUIT !!!", me.name);
+                 sendto_ops("%s tried to do a fake kill using SQUIT (%s (%s))", sptr->name, acptr->name, comment);
+                 sendto_serv_butone(&me, ":%s GLOBOPS :%s tried to fake kill using SQUIT (%s (%s))", me.name, sptr->name, acptr->name, comment);
+                    return 0;
+               }                                                               
+               sendto_locfailops("Received SQUIT %s from %s (%s)",
+                          acptr->name, get_client_name(sptr,FALSE), comment);
+               sendto_serv_butone(&me, ":%s GLOBOPS :Received SQUIT %s from %s (%s)",
+                          me.name, acptr->name, get_client_name(sptr,FALSE), comment);
+       }
+       if (IsAnOper(sptr)) {
+               /*
+                * It was manually /squit'ed by a human being(we hope),
+                * there is a very good chance they don't want us to
+                * reconnect right away.  -Cabal95
+                */
+               acptr->flags |= FLAGS_SQUIT;
+       }
+
+       return exit_client(cptr, acptr, sptr, comment);
+    }
+
+/*
+ * m_protoctl
+ *     parv[0] = Sender prefix
+ *     parv[1+] = Options
+ */
+int    m_protoctl(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       int     i;
+       char    proto[128], *options, *equal;
+       static  char    *dummyblank=""; /* Yes, it is kind of ugly */
+
+
+       if (GotProtoctl(sptr)) {
+               /*
+                * But we already GOT a protoctl msg!
+                */
+               if (!IsServer(sptr))
+                       sendto_one(cptr, "ERROR :Already got a PROTOCTL from you.");
+               return 0;
+       }
+
+       cptr->flags |= FLAGS_PROTOCTL;
+       /* parv[parc - 1]*/
+       for (i = 1; i < parc; i++) {
+               strncpy(proto, parv[i], 127);
+               proto[127] = '\0'; /* Just to be safe... */
+               equal = (char *)index(proto, '=');
+               if (equal == NULL)
+                       options = dummyblank;
+               else {
+                       options = &equal[1]; /* Variable-byte-size safe */
+                       equal[0] = '\0';
+               }
+
+               if (strcmp(proto, "NOQUIT") == 0) {
+                       Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
+                       SetNoQuit(cptr);
+               } else if (strcmp(proto, "TOKEN") == 0) {
+                       Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
+                       SetToken(cptr);
+               } else if (strcmp(proto, "HCN")==0)
+               {
+                       Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
+                       SetHybNotice(cptr);
+               } else if (strcmp(proto, "SJOIN")==0)
+               {
+                       Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
+                       SetSJOIN(cptr);
+               }
+                else if (strcmp(proto, "SJOIN2")==0)
+               {
+                       Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
+                       SetSJOIN2(cptr);
+               } else if (strcmp(proto, "NICKv2")==0)
+               {
+                       Debug((DEBUG_ERROR, "Chose protocol %s for link %s", proto, cptr->name));
+                       SetNICKv2(cptr);
+               }
+               /*
+                * Add other protocol extensions here, with proto
+                * containing the base option, and options containing
+                * what it equals, if anything.
+                *
+                * DO NOT error or warn on unknown proto; we just don't
+                * support it.
+                */
+       }
+
+       return 0;
+}
+
+
+/*
+** m_server
+**     parv[0] = sender prefix
+**     parv[1] = servername
+**     parv[2] = serverinfo/hopcount
+**      parv[3] = serverinfo
+*/
+int    m_server(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    char    *ch;
+       Reg2    int     i;
+       char    info[REALLEN+1], *inpath, *host, *encr;
+       aClient *acptr, *bcptr;
+       aConfItem *aconf, *cconf;
+       int     hop, ts = 0;
+
+       info[0] = '\0';
+       inpath = get_client_name(cptr,FALSE);
+       if (parc < 2 || *parv[1] == '\0')
+           {
+                       sendto_one(cptr,"ERROR :No servername");
+                       return 0;
+           }
+       hop = 0;
+       host = parv[1];
+       if (parc > 4) {
+               ts = atoi(parv[3]);
+               hop = atoi(parv[2]);
+               (void)strncpy(info, parv[4], REALLEN);
+               info[REALLEN] = '\0';
+       }
+       else if (parc > 3 && atoi(parv[2]))
+           {
+               hop = atoi(parv[2]);
+               (void)strncpy(info, parv[3], REALLEN);
+               info[REALLEN] = '\0';
+           }
+       else if (parc > 2)
+           {
+               (void)strncpy(info, parv[2], REALLEN);
+               if (parc > 3 && ((i = strlen(info)) < (REALLEN-2)))
+                   {
+                               (void)strcat(info, " ");
+                               (void)strncat(info, parv[3], REALLEN - i - 2);
+                               info[REALLEN] = '\0';
+                   }
+           }
+       /*
+       ** 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 || !index(host, '.'))
+           {
+               sendto_one(sptr,"ERROR :Bogus server name (%s)",
+                          sptr->name, host);
+               sendto_ops("Bogus server name (%s) from %s", host,
+                          get_client_name(cptr, TRUE));
+               sptr->since += 7;
+               return 0;
+           }
+
+       if (IsPerson(cptr))
+           {
+               /*
+               ** A local link that has been identified as a USER
+               ** tries something fishy... ;-)
+               */
+               sendto_one(cptr, err_str(ERR_ALREADYREGISTRED),
+                          me.name, parv[0]);
+//             sendto_one(cptr, ":%s NOTICE %s :Sorry, but your IRC program doesn't appear to support changing servers.", me.name, cptr->name);
+               sendto_ops("User %s trying to become a server %s",
+                          get_client_name(cptr, TRUE),host);
+               sptr->since += 7;
+               return 0;
+           }
+       /* *WHEN* can it be that "cptr != sptr" ????? --msa */
+       /* When SERVER command (like now) has prefix. -avalon */
+               
+       /* take a prepeek at the password..*/
+       if (IsUnknown(cptr))  {
+         aconf = find_conf_servern(host);
+         if (!aconf) {
+           sendto_locfailops("ERROR :No Access (No N line) %s",
+                      inpath);
+           sendto_locfailops("Access denied (No N line) %s", inpath);
+           return exit_client(cptr, cptr, cptr, "No N line");
+         }
+#ifdef CRYPT_LINK_PASSWORD
+         /* use first two chars of the password they send in as salt */
+         
+         /* passwd may be NULL. Head it off at the pass... */
+         if(*cptr->passwd)
+           {
+             char    salt[3];
+             extern  char *crypt();
+             
+             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 */
+         if (*aconf->passwd && !StrEq(aconf->passwd, encr))
+           {
+             sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
+                        inpath);
+             sendto_locfailops("Access denied (passwd mismatch) %s", inpath);
+             return exit_client(cptr, cptr, cptr, "Bad Password");
+           }
+       /*      bzero(cptr->passwd, sizeof(cptr->passwd));*/
+       }
+
+       if ((acptr = find_name(host, NULL)))
+           {
+               aClient *ocptr;
+
+               /*
+                * This link is trying feed me a server that I already have
+                * access through another path -- multiple paths not accepted
+                * currently, kill this link immeatedly!!
+                *
+                * Rather than KILL the link which introduced it, KILL the
+                * youngest of the two links. -avalon
+                */
+               acptr = acptr->from;
+               ocptr = (cptr->firsttime > acptr->firsttime) ? acptr : cptr;
+               acptr = (cptr->firsttime > acptr->firsttime) ? cptr : acptr;
+               sendto_one(acptr,"ERROR :Server %s already exists from %s",
+                          host,
+                          (ocptr->from ? ocptr->from->name : "<nobody>"));
+               sendto_ops("Link %s cancelled, server %s already exists from %s",
+                          get_client_name(acptr, TRUE), host,
+                          (ocptr->from ? ocptr->from->name : "<nobody>"));
+               return exit_client(acptr, acptr, acptr, "Server Exists");
+           }
+       if ((acptr = find_client(host, NULL)))
+           {
+               /*
+               ** Server trying to use the same name as a person. Would
+               ** cause a fair bit of confusion. Enough to make it hellish
+               ** for a while and servers to send stuff to the wrong place.
+               */
+               sendto_one(cptr,"ERROR :Nickname %s already exists!", host);
+                sendto_locfailops("Link %s cancelled: Server/nick collision on %s",
+                           inpath, host);
+               sendto_serv_butone(&me, ":%s GLOBOPS : Link %s cancelled: Server/nick collision on %s",
+                          parv[0], inpath, host);
+               return exit_client(cptr, cptr, cptr, "Nick as Server");
+           }
+
+       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...
+               */
+               if (parc == 1 || info[0] == '\0')
+                   {
+                       sendto_one(cptr,
+                                  "ERROR :No server info specified for %s",
+                                  host);
+                       return 0;
+                   }
+
+               /*
+               ** See if the newly found server is behind a guaranteed
+               ** leaf (L-line). If so, close the link.
+               */
+               if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
+                   (!aconf->port || (hop > aconf->port)))
+                   {
+                       sendto_ops("Leaf-only link %s->%s - Closing",
+                                  get_client_name(cptr,  TRUE),
+                                  aconf->host ? aconf->host : "*");
+                       sendto_one(cptr, "ERROR :Leaf-only link, sorry.");
+                       return exit_client(cptr, cptr, cptr, "Leaf Only");
+                   }
+               /*
+               **
+               */
+               if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) ||
+                   (aconf->port && (hop > aconf->port)) )
+                   {
+                       sendto_ops("Non-Hub link %s introduced %s(%s).",
+                                  get_client_name(cptr,  TRUE), host,
+                                  aconf ? (aconf->host ? aconf->host : "*") :
+                                  "!");
+                       return exit_client(cptr, cptr, cptr,
+                                          "Too many servers");
+                   }
+               /*
+               ** See if the newly found server has a Q line for it in
+               ** our conf. If it does, lose the link that brought it
+               ** into our network. Format:
+               **
+               ** Q:<unused>:<reason>:<servername>
+               **
+               ** Example:  Q:*:for the hell of it:eris.Berkeley.EDU
+               */
+               if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER)))
+                   {
+                       sendto_ops_butone(NULL, &me,
+                               ":%s WALLOPS * :%s brought in %s, %s %s",
+                               me.name, get_client_name(cptr,FALSE),
+                               host, "closing link because",
+                               BadPtr(aconf->passwd) ? "reason unspecified" :
+                               aconf->passwd);
+
+                       sendto_one(cptr,
+                                  "ERROR :%s is not welcome: %s. %s",
+                                  host, BadPtr(aconf->passwd) ?
+                                  "reason unspecified" : aconf->passwd,
+                                  "Try another network");
+
+                       return exit_client(cptr, cptr, cptr, "Q-Lined Server");
+                   }
+
+               acptr = make_client(cptr, find_server(parv[0], NULL));
+               (void)make_server(acptr);
+               acptr->hopcount = hop;
+               strncpyzt(acptr->name, host, sizeof(acptr->name));
+               strncpyzt(acptr->info, info, sizeof(acptr->info));
+               strncpyzt(acptr->serv->up, parv[0], sizeof(acptr->serv->up));
+               SetServer(acptr);
+               acptr->flags|=FLAGS_TS8;
+               add_client_to_list(acptr);
+               (void)add_to_client_hash_table(acptr->name, 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 = local[i]) || !IsServer(bcptr) ||
+                           bcptr == cptr || IsMe(bcptr))
+                               continue;
+                       if (!(aconf = bcptr->serv->nline))
+                           {
+                               sendto_ops("Lost N-line for %s on %s. Closing",
+                                          get_client_name(cptr, TRUE), host);
+                               return exit_client(cptr, cptr, cptr,
+                                                  "Lost N line");
+                           }
+                       if (match(my_name_for_link(me.name, aconf),
+                                   acptr->name) == 0)
+                               continue;
+                       if (ts)
+                           sendto_one(bcptr, ":%s SERVER %s %d %d :%s",
+                                      parv[0], acptr->name, hop+1, ts,
+                                      acptr->info);
+                       else
+                           sendto_one(bcptr, ":%s SERVER %s %d :%s",
+                                      parv[0], acptr->name, hop+1,
+                                      acptr->info);
+                   }
+               /* Check for U-line status -- Barubary */
+               if (find_conf_host(cptr->confs, acptr->name, CONF_UWORLD))
+                       acptr->flags |= FLAGS_ULINE;
+               return 0;
+           }
+
+       if (!IsUnknown(cptr) && !IsHandshake(cptr))
+               return 0;
+       /*
+       ** A local link that is still in undefined state wants
+       ** to be a SERVER. Check if this is allowed and change
+       ** status accordingly...
+       */
+       strncpyzt(cptr->name, host, sizeof(cptr->name));
+       strncpyzt(cptr->info, info[0] ? info:me.name, sizeof(cptr->info));
+       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.",
+                          get_client_host(cptr));
+               return exit_client(cptr, cptr, cptr,
+                                  "Disallowed by connection rule");
+             }
+
+       switch (check_server_init(cptr))
+       {
+       case 0 :
+               return m_server_estab(cptr);
+       case 1 :
+               sendto_ops("Access check for %s in progress",
+                          get_client_name(cptr,TRUE));
+               return 1;
+       default :
+               ircstp->is_ref++;
+               sendto_ops("Received unauthorized connection from %s.", get_client_host(cptr));
+               sendto_serv_butone(&me, ":%s GLOBOPS :Recieved unauthorized connection from %s.",
+                       parv[0], get_client_host(cptr));
+               return exit_client(cptr, cptr, cptr, "No C/N conf lines");
+       }
+
+}
+
+int    m_server_estab(cptr)
+Reg1   aClient *cptr;
+{
+       Reg2    aClient *acptr;
+       Reg3    aConfItem       *aconf, *bconf;
+       char    *inpath, *host, *s, *encr;
+       int     split, i;
+
+       inpath = get_client_name(cptr,TRUE); /* "refresh" inpath with host */
+       split = mycmp(cptr->name, cptr->sockhost);
+       host = cptr->name;
+
+       current_load_data.conn_count++;
+       update_load();
+
+       if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
+           {
+               ircstp->is_ref++;
+               sendto_one(cptr,
+                          "ERROR :Access denied. No N line for server %s",
+                          inpath);
+               sendto_ops("Access denied. No N line for server %s", inpath);
+               return exit_client(cptr, cptr, cptr, "No N line for server");
+           }
+       if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER)))
+           {
+               ircstp->is_ref++;
+               sendto_one(cptr, "ERROR :Only N (no C) field for server %s",
+                          inpath);
+               sendto_ops("Only N (no C) field for server %s",inpath);
+               return exit_client(cptr, cptr, cptr, "No C line for server");
+           }
+
+#ifdef CRYPT_LINK_PASSWORD
+       /* use first two chars of the password they send in as salt */
+
+       /* passwd may be NULL. Head it off at the pass... */
+       if(*cptr->passwd)
+           {
+               char    salt[3];
+               extern  char *crypt();
+
+               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 */
+       if (*aconf->passwd && !StrEq(aconf->passwd, encr))
+           {
+               ircstp->is_ref++;
+               sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
+                          inpath);
+               sendto_ops("Access denied (passwd mismatch) %s", inpath);
+               return exit_client(cptr, cptr, cptr, "Bad Password");
+           }
+       bzero(cptr->passwd, sizeof(cptr->passwd));
+#ifndef        HUB
+       for (i = 0; i <= highest_fd; i++)
+               if (local[i] && IsServer(local[i]))
+                   {
+                       ircstp->is_ref++;
+                       sendto_one(cptr, "ERROR :I'm a leaf not a hub");
+                       return exit_client(cptr, cptr, cptr, "I'm a leaf");
+                   }
+#endif
+       if (IsUnknown(cptr))
+           {
+               sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
+               if (bconf->passwd[0])
+                       sendto_one(cptr,"PASS :%s",bconf->passwd);
+               /*
+               ** Pass my info to the new server
+               */
+               sendto_one(cptr, "SERVER %s 1 :%s",
+                          my_name_for_link(me.name, aconf), 
+                          (me.info[0]) ? (me.info) : "IRCers United");
+           }
+       else
+           {
+               s = (char *)index(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, TRUE));
+                       sendto_one(cptr, "ERROR :No Username Match");
+                       return exit_client(cptr, cptr, cptr, "Bad User");
+                   }
+               *s = '@';
+               sendto_one(cptr, "PROTOCTL %s", PROTOCTL_SERVER);
+           }
+
+       det_confs_butmask(cptr,
+           CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER|CONF_UWORLD);
+       /*
+       ** *WARNING*
+       **      In the following code in place of plain server's
+       **      name we send what is returned by get_client_name
+       **      which may add the "sockhost" after the name. It's
+       **      *very* *important* that there is a SPACE between
+       **      the name and sockhost (if present). The receiving
+       **      server will start the information field from this
+       **      first blank and thus puts the sockhost into info.
+       **      ...a bit tricky, but you have been warned, besides
+       **      code is more neat this way...  --msa
+       */
+       SetServer(cptr);
+#ifndef NO_FDLIST
+        addto_fdlist(cptr->fd,&serv_fdlist); 
+#endif
+       if (find_conf_host(cptr->confs, cptr->name, CONF_UWORLD))
+               cptr->flags |= FLAGS_ULINE;
+       cptr->flags|=FLAGS_TS8;
+       nextping = TStime();
+
+       if (TRUEHUB == 1)
+               sendto_serv_butone(&me, ":%s GLOBOPS :Link with %s established.",
+                       me.name, inpath);
+       sendto_locfailops("Link with %s established.", inpath);
+       /* Insert here */
+       (void)add_to_client_hash_table(cptr->name, cptr);
+       /* doesnt duplicate cptr->serv if allocted this struct already */
+       (void)make_server(cptr);
+       (void)strcpy(cptr->serv->up, me.name);
+       cptr->srvptr = &me;
+       cptr->serv->nline = aconf;
+       if (find_conf_host(cptr->confs, cptr->name, CONF_UWORLD))
+                       cptr->flags |= FLAGS_ULINE;
+
+       /*
+       ** Old sendto_serv_but_one() call removed because we now
+       ** need to send different names to different servers
+       ** (domain name matching) Send new server to other servers.
+       */
+       for (i = 0; i <= highest_fd; i++) 
+           {
+               if (!(acptr = local[i]) || !IsServer(acptr) ||
+                   acptr == cptr || IsMe(acptr))
+                       continue;
+               if ((aconf = acptr->serv->nline) &&
+                   !match(my_name_for_link(me.name, aconf), cptr->name))
+                       continue;
+               if (split)
+                       sendto_one(acptr,":%s %s %s 2 :%s",
+                                  me.name, 
+                                  (IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
+                                  cptr->name,
+                                  cptr->info);
+               else
+                       sendto_one(acptr,":%s %s %s 2 :%s",
+                                  me.name, 
+                                    (IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
+
+                                  cptr->name, cptr->info);
+           }
+
+       /*
+       ** Pass on my client information to the new server
+       **
+       ** First, pass only servers (idea is that if the link gets
+       ** cancelled beacause the server was already there,
+       ** there are no NICK's to be cancelled...). Of course,
+       ** if cancellation occurs, all this info is sent anyway,
+       ** and I guess the link dies when a read is attempted...? --msa
+       ** 
+       ** Note: Link cancellation to occur at this point means
+       ** that at least two servers from my fragment are building
+       ** up connection this other fragment at the same time, it's
+       ** a race condition, not the normal way of operation...
+       **
+       ** ALSO NOTE: using the get_client_name for server names--
+       **      see previous *WARNING*!!! (Also, original inpath
+       **      is destroyed...)
+       */
+
+       aconf = cptr->serv->nline;
+       for (acptr = &me; acptr; acptr = acptr->prev)
+           {
+               /* acptr->from == acptr for acptr == cptr */
+               if (acptr->from == cptr)
+                       continue;
+               if (IsServer(acptr))
+                   {
+                       if (match(my_name_for_link(me.name, aconf),
+                                   acptr->name) == 0)
+                               continue;
+                       split = (MyConnect(acptr) &&
+                                mycmp(acptr->name, acptr->sockhost));
+                       if (split)
+                               sendto_one(cptr, ":%s %s %s %d :%s",
+                                          acptr->serv->up, 
+                                          (IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
+
+                                          acptr->name,
+                                          acptr->hopcount+1,
+                                          acptr->info);
+                       else
+                               sendto_one(cptr, ":%s %s %s %d :%s",
+                                          acptr->serv->up, 
+                                          (IsToken(cptr) ? TOK_SERVER : MSG_SERVER),
+                          
+                                          acptr->name,
+                                          acptr->hopcount+1, acptr->info);
+                                          
+                   }
+           }
+
+       for (acptr = &me; acptr; acptr = acptr->prev)
+           {
+               /* acptr->from == acptr for acptr == cptr */
+               if (acptr->from == cptr)
+                       continue;
+               if (IsPerson(acptr))
+                   {
+                       /*
+                       ** IsPerson(x) is true only when IsClient(x) is true.
+                       ** These are only true when *BOTH* NICK and USER have
+                       ** been received. -avalon
+                       ** Apparently USER command was forgotten... -Donwulff
+                       */
+
+                                               
+                       if (!SupportNICKv2(cptr))                       
+                       {
+                               sendto_one(cptr,"%s %s %d %d %s %s %s %lu :%s",
+                                        (IsToken(cptr)?TOK_NICK:MSG_NICK),
+                                         acptr->name, acptr->hopcount + 1, acptr->lastnick,
+                                               acptr->user->username, acptr->user->realhost,
+                                               acptr->user->server, acptr->user->servicestamp,
+                                                acptr->info);
+                               send_umode(cptr, acptr, 0, SEND_UMODES, buf);
+                               if (IsHidden(acptr))
+                                       sendto_one(cptr, ":%s %s %s", acptr->name, 
+                                               (IsToken(cptr)?TOK_SETHOST:MSG_SETHOST),
+                                               acptr->user->virthost);
+                       }
+                       else    
+                       {
+                               send_umode(NULL, acptr, 0, SEND_UMODES, buf);
+                               sendto_one(cptr,"%s %s %d %d %s %s %s %lu %s %s :%s",
+                                        (IsToken(cptr)?TOK_NICK:MSG_NICK),
+                                         acptr->name, acptr->hopcount + 1, acptr->lastnick,
+                                               acptr->user->username, acptr->user->realhost,
+                                               acptr->user->server, 
+                                               acptr->user->servicestamp,
+                                               (!buf || *buf == '\0' ? "+" : buf),
+                               ((IsHidden(acptr) && (acptr->umodes & UMODE_SETHOST)) ? acptr->user->virthost : "*"), 
+                                               acptr->info);
+                               
+                       }
+       
+                       if (acptr->user->away)
+                               sendto_one(cptr,":%s %s :%s", acptr->name,
+                                  (IsToken(cptr)?TOK_AWAY:MSG_AWAY),
+                                  acptr->user->away);
+                       if (acptr->user->swhois)
+                               if (*acptr->user->swhois != '\0')
+                                       sendto_one(cptr, "%s %s :%s", 
+                                               (IsToken(cptr)?TOK_SWHOIS:MSG_SWHOIS),
+                                               acptr->name, acptr->user->swhois);
+                                       
+                       if (!SupportSJOIN(cptr))
+                               send_user_joins(cptr, acptr);
+                   }
+               else if (IsService(acptr))
+                   {
+                       sendto_one(cptr,"NICK %s :%d",
+                                  acptr->name, acptr->hopcount + 1);
+                       sendto_one(cptr,":%s SERVICE * * :%s",
+                                  acptr->name, acptr->info);
+                   }
+           }
+       /*
+       ** Last, pass all channels plus statuses
+       */
+       {
+               Reg1 aChannel *chptr;
+               for (chptr = channel; chptr; chptr = chptr->nextch)
+                  {
+                       if (!SupportSJOIN(cptr))
+                               send_channel_modes(cptr, chptr);
+                       else
+                               send_channel_modes_sjoin(cptr, chptr);
+                       if (chptr->topic_time)
+                               sendto_one(cptr,"%s %s %s %lu :%s",
+                                          (IsToken(cptr)?TOK_TOPIC:MSG_TOPIC),
+                                          chptr->chname, chptr->topic_nick,
+                                          chptr->topic_time, chptr->topic);
+                  }
+       }
+       /* pass on TKLs */
+               tkl_synch(cptr);
+       /*
+       ** Pass on all services based q-lines
+       */
+       {
+               Reg1 aSqlineItem *tmp;
+
+               for(tmp=sqline;tmp;tmp=tmp->next) {
+                       if(tmp->status != CONF_ILLEGAL)
+                               if(tmp->reason)
+                                       sendto_one(cptr,":%s %s %s :%s", me.name,
+                                               (IsToken(cptr)?TOK_SQLINE:MSG_SQLINE),
+                                               tmp->sqline, tmp->reason);
+                               else
+                                       sendto_one(cptr,":%s %s %s", me.name,
+                                               tmp->sqline);
+               }
+       }
+
+       sendto_one(cptr, "%s %li %li %li 0 0 0 0 :%s", 
+                         (IsToken(cptr)?TOK_NETINFO:MSG_NETINFO),
+                         lu_mglobalu,
+                         TStime(),
+                         UnrealProtocol,
+                         ircnetwork); 
+               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(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       char *mask;
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+    
+       if (parc > 2 && IsOper(cptr))
+           {
+               if (hunt_server(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, (void)collapse(mask); acptr; acptr = acptr->next) 
+           {
+               if (!IsServer(acptr) && !IsMe(acptr))
+                       continue;
+               if (!BadPtr(mask) && match(mask, acptr->name))
+                       continue;
+               if (HIDE_ULINES == 1) {
+               if (IsULine(acptr, acptr) && !IsAnOper(sptr))
+                       continue;
+               }
+               sendto_one(sptr, rpl_str(RPL_LINKS),
+                          me.name, parv[0], acptr->name, acptr->serv->up,
+                          acptr->hopcount, (acptr->info[0] ? acptr->info :
+                          "(Unknown Location)"));
+           }
+
+       sendto_one(sptr, rpl_str(RPL_ENDOFLINKS), me.name, parv[0],
+                  BadPtr(mask) ? "*" : mask);
+       return 0;
+}
+
+
+/*
+** m_netinfo
+** by Stskeeps
+**  parv[0] = sender prefix
+**  parv[1] = max global count
+**  parv[2] = time of end sync 
+**  parv[3] = unreal protocol using (numeric)
+**  parv[4] = free(for unrealprotocol > 2100)
+**  parv[5] = free(**)
+**  parv[6] = free(**)
+**  parv[7] = free(**)
+**  parv[8] = ircnet
+**/
+
+int m_netinfo(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       long    lmax;
+       time_t  xx;
+       long    endsync, protocol;
+
+       if (IsPerson(sptr))
+               return 0;
+       if (!IsServer(cptr))
+               return 0;
+       
+       if (parc < 3) {
+               /* Talking to a UnProtocol 2090 */
+               sendto_realops("Link %s is using a too old UnProtocol - (parc < 3)", cptr->name);
+               if (KILLDIFF == 1) {
+                       sendto_realops("Dropped link %s - unProtocol 2090 is not compatible with unProtocol %li", cptr->name, UnrealProtocol);
+                       sendto_one(cptr, "ERROR :unProtocol 2090 is not compatible with unProtocol %li", 
+                               UnrealProtocol);
+                       exit_client(cptr, cptr, cptr, "Link using unProtocol 2090");
+               }
+               return 0;
+       }
+       if (parc < 9) {
+               return 0;
+       }
+
+       if (GotNetInfo(cptr)) {
+               sendto_realops("Already got NETINFO from Link %s", cptr->name);
+               return 0;
+       }
+       /* is a long therefore not ATOI */
+       lmax = atol(parv[1]);
+       endsync = atol(parv[2]);
+       protocol = atol(parv[3]);
+               
+       /* update stats */
+       check_lusers();
+       
+       /* max global count != max_global_count --sts */
+       if (lmax > lu_mglobalu) {
+               lu_mglobalu = lmax;
+               sendto_realops("Max Global Count is now %li (set by link %s)", lmax, cptr->name);
+       }
+       
+       xx = TStime();
+       if ((xx - endsync) < 0) {
+               sendto_realops("Possible negative TS split at link %s (%li - %li = %li)",
+                                       cptr->name,
+                                       (xx),
+                                       (endsync),
+                                       (xx - endsync));   
+               sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Possible negative TS split at link %s (%li - %li = %li)",
+                                       me.name,
+                                       cptr->name,
+                                       (xx),
+                                       (endsync),
+                                       (xx - endsync));
+       }
+       sendto_realops("Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]",
+               cptr->name,
+               me.name,
+               (TStime() - endsync),
+               sptr->receiveK,
+               sptr->receiveB,
+               sptr->sendK,
+               sptr->sendB);
+
+       sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Link %s -> %s is now synced [secs: %li recv: %li.%li sent: %li.%li]",
+               me.name,
+               cptr->name,
+               me.name,
+               (TStime() - endsync),
+               sptr->receiveK,
+               sptr->receiveB,
+               sptr->sendK,
+               sptr->sendB);
+
+       if (!(strcmp(ircnetwork, parv[8])==0)) {
+               sendto_realops("Network name mismatch from link %s (%s != %s)", cptr->name, parv[8], ircnetwork);
+               sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Network name mismatch from link %s (%s != %s)", me.name, cptr->name, parv[8], ircnetwork);
+       }       
+       
+       if (protocol != UnrealProtocol) {
+               sendto_realops("Link %s is running Protocol u%li while we are running %li!",
+                                       cptr->name, protocol, UnrealProtocol);
+               sendto_serv_butone(&me, ":%s SMO o :\2(sync)\2 Link %s is running u%li while %s is running %li!",
+                   me.name, cptr->name, protocol,me.name,UnrealProtocol);
+                
+       }
+
+       SetNetInfo(cptr);
+}
+
+#ifndef IRCDTOTALVERSION
+#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9
+#endif
+
+/* 
+ * sends m_info into to sptr
+*/
+
+void   m_info_send(sptr)
+aClient *sptr;
+{
+       sendto_one(sptr, ":%s %d %s :=-=-=-=-=-==-== %s =-=-=-=-=-==-==",
+                me.name, RPL_INFO, sptr->name, ircnetwork);
+       sendto_one(sptr, ":%s %d %s :|Web Page:      | http://www.%s",
+         me.name, RPL_INFO, sptr->name, netdomain);
+       sendto_one(sptr, ":%s %d %s :|FTP Archive:   | ftp://ftp.%s",
+         me.name, RPL_INFO, sptr->name, netdomain);
+       sendto_one(sptr, ":%s %d %s :|Help channel:  | %s",
+         me.name, RPL_INFO, sptr->name, helpchan);
+       sendto_one(sptr, ":%s %d %s :|=-=-=-=-=-==-==|-=-=-=-=-=-=-==-==-=-=-=-=-=-=-=",
+         me.name, RPL_INFO, sptr->name);
+       sendto_one(sptr, ":%s %d %s :|IRCd version:  | %s",
+      me.name, RPL_INFO, sptr->name, IRCDTOTALVERSION);        
+       sendto_one(sptr, ":%s %d %s :| Developers:   | Stskeeps <stskeeps@tspre.org>",
+         me.name, RPL_INFO, sptr->name);
+       sendto_one(sptr, ":%s %d %s :|               | codemastr <codemastr@tspre.org>>",
+        me.name, RPL_INFO, sptr->name);
+
+#ifdef _WIN32
+#ifdef WIN32_SPECIFY
+       sendto_one(sptr, ":%s %d %s :| wIRCd porter: | %s",
+         me.name, RPL_INFO, sptr->name, WIN32_PORTER);
+       sendto_one(sptr, ":%s %d %s :|     >>URL:    | %s",
+         me.name, RPL_INFO, sptr->name, WIN32_URL);
+#endif
+#endif
+       sendto_one(sptr, ":%s %d %s :|Credits:       | Type /Credits",
+         me.name, RPL_INFO, sptr->name);
+       sendto_one(sptr, ":%s %d %s :|DALnet Credits | Type /DalInfo",
+         me.name, RPL_INFO, sptr->name);
+       sendto_one(sptr, ":%s %d %s :-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-",
+         me.name, RPL_INFO, sptr->name);
+       sendto_one(sptr, ":%s %d %s :Birth Date: %s, compile # %s",
+                  me.name, RPL_INFO, sptr->name, creation, generation);
+       sendto_one(sptr, ":%s %d %s :On-line since %s",
+                  me.name, RPL_INFO, sptr->name,
+                  myctime(me.firsttime));
+       sendto_one(sptr, ":%s %d %s :ReleaseID (%s)",
+                  me.name, RPL_INFO, sptr->name,
+                  RELEASEID);
+       sendto_one(sptr, rpl_str(RPL_ENDOFINFO), me.name, sptr->name);
+}
+
+/*
+** m_info
+**     parv[0] = sender prefix
+**     parv[1] = servername
+**  Modified for hardcode by Stskeeps  
+*/
+
+int    m_info(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       char **text = infotext;
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME)
+       {
+               m_info_send(sptr);
+       }
+
+    return 0;
+}
+
+/*
+** m_dalinfo
+**      parv[0] = sender prefix
+**      parv[1] = servername
+*/
+int     m_dalinfo(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        char **text = dalinfotext;
+        if (check_registered(sptr))
+                return 0;
+
+        if (hunt_server(cptr,sptr,":%s DALINFO :%s",1,parc,parv) == HUNTED_ISME)
+            {
+                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_license
+**      parv[0] = sender prefix
+**      parv[1] = servername
+*/
+int     m_license(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        char **text = gnulicense;
+        if (check_registered(sptr))
+                return 0;
+
+        if (hunt_server(cptr,sptr,":%s LICENSE :%s",1,parc,parv) == HUNTED_ISME)
+            {
+                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, rpl_str(RPL_ENDOFINFO), me.name, parv[0]);
+            }
+
+    return 0;
+}
+
+/*
+** m_credits
+**      parv[0] = sender prefix
+**      parv[1] = servername
+*/
+int     m_credits(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        char **text = unrealcredits;
+        if (check_registered(sptr))
+                return 0;
+
+        if (hunt_server(cptr,sptr,":%s CREDITS :%s",1,parc,parv) == HUNTED_ISME)
+            {
+                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;
+}
+
+
+/*
+ * RPL_NOWON   - Online at the moment (Succesfully added to WATCH-list)
+ * RPL_NOWOFF  - Offline at the moement (Succesfully added to WATCH-list)
+ * RPL_WATCHOFF        - Succesfully removed from WATCH-list.
+ * ERR_TOOMANYWATCH - Take a guess :>  Too many WATCH entries.
+ */
+static void    show_watch(cptr, name, rpl1, rpl2)
+aClient        *cptr;
+char   *name;
+int    rpl1, rpl2;
+{
+       aClient *acptr;
+
+
+       if ((acptr = find_person(name, NULL))) {
+               make_virthost(acptr->user->realhost, acptr->user->virthost);
+               sendto_one(cptr, rpl_str(rpl1), me.name, cptr->name,
+                          acptr->name, acptr->user->username,
+                          acptr->user->virthost, acptr->lastnick);
+       }
+       else
+               sendto_one(cptr, rpl_str(rpl2), me.name, cptr->name,
+                          name, "*", "*", 0);
+}
+
+/*
+ * m_watch
+ */
+int    m_watch(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+    char       namebuf[USERLEN+HOSTLEN+4];
+    Reg1       aClient *acptr;
+    Reg2       char    *s, **pav = parv, *user;
+    Reg3       int     len;
+    char       *p = NULL, *def = "l";
+
+
+    if (check_registered(sptr))
+       return 0;
+
+    if (parc < 2) {
+       /*
+        * Default to 'l' - list who's currently online
+        */
+       parc = 2;
+       parv[1] = def;
+    }
+
+    for (s = (char *)strtoken(&p, *++pav, " "); s;
+         s = (char *)strtoken(&p, NULL, " ")) {
+       if ((user = (char *)index(s, '!')))
+           *user++ = '\0'; /* Not used */
+
+       /*
+        * Prefix of "+", they want to add a name to their WATCH
+        * list.
+        */
+       if (*s == '+') {
+           if (do_nick_name(s+1)) {
+               if (sptr->notifies >= MAXWATCH) {
+                   sendto_one(sptr, err_str(ERR_TOOMANYWATCH),
+                              me.name, cptr->name, s+1);
+
+                   continue;
+               }
+
+               add_to_notify_hash_table(s+1, sptr);
+           }
+
+           show_watch(sptr, s+1, RPL_NOWON, RPL_NOWOFF);
+           continue;
+       }
+
+       /*
+        * Prefix of "-", coward wants to remove somebody from their
+        * WATCH list.  So do it. :-)
+        */
+       if (*s == '-') {
+           del_from_notify_hash_table(s+1, sptr);
+           show_watch(sptr, s+1, RPL_WATCHOFF, RPL_WATCHOFF);
+
+           continue;
+       }
+
+       /*
+        * Fancy "C" or "c", they want to nuke their WATCH list and start
+        * over, so be it.
+        */
+       if (*s == 'C' || *s == 'c') {
+           hash_del_notify_list(sptr);
+
+           continue;
+       }
+
+       /*
+        * Now comes the fun stuff, "S" or "s" returns a status report of
+        * their WATCH list.  I imagine this could be CPU intensive if its
+        * done alot, perhaps an auto-lag on this?
+        */
+       if (*s == 'S' || *s == 's') {
+           Link        *lp;
+           aNotify     *anptr;
+           int count = 0;
+
+           /*
+            * Send a list of how many users they have on their WATCH list
+            * and how many WATCH lists they are on.
+            */
+           anptr = hash_get_notify(sptr->name);
+           if (anptr)
+               for (lp = anptr->notify, count = 1; (lp = lp->next); count++)
+                   ;
+           sendto_one(sptr, rpl_str(RPL_WATCHSTAT), me.name, parv[0],
+                      sptr->notifies, count);
+
+           /*
+            * Send a list of everybody in their WATCH list. Be careful
+            * not to buffer overflow.
+            */
+           if ((lp = sptr->notify) == NULL) {
+               sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
+                          *s);
+               continue;
+           }
+           *buf = '\0';
+           strcpy(buf, lp->value.nptr->nick);
+           count = strlen(parv[0])+strlen(me.name)+10+strlen(buf);
+           while ((lp = lp->next)) {
+               if (count+strlen(lp->value.nptr->nick)+1 > BUFSIZE - 2) {
+                   sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name,
+                              parv[0], buf);
+                   *buf = '\0';
+                   count = strlen(parv[0])+strlen(me.name)+10;
+               }
+               strcat(buf, " ");
+               strcat(buf, lp->value.nptr->nick);
+               count += (strlen(lp->value.nptr->nick)+1);
+           }
+           sendto_one(sptr, rpl_str(RPL_WATCHLIST), me.name, parv[0], buf);
+
+           sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
+                      *s);
+           continue;
+       }
+
+       /*
+        * Well that was fun, NOT.  Now they want a list of everybody in
+        * their WATCH list AND if they are online or offline? Sheesh,
+        * greedy arn't we?
+        */
+       if (*s == 'L' || *s == 'l') {
+           Link        *lp = sptr->notify;
+
+           while (lp) {
+               if ((acptr = find_person(lp->value.nptr->nick, NULL))) {
+                       make_virthost(acptr->user->realhost, acptr->user->virthost);
+
+                           sendto_one(sptr, rpl_str(RPL_NOWON), me.name, parv[0],
+                              acptr->name, acptr->user->username,
+                           acptr->user->virthost, acptr->lastnick);
+               }
+               /*
+                * But actually, only show them offline if its a capital
+                * 'L' (full list wanted).
+                */
+               else if (isupper(*s))
+                   sendto_one(sptr, rpl_str(RPL_NOWOFF), me.name, parv[0],
+                              lp->value.nptr->nick, "*", "*",
+                              lp->value.nptr->lasttime);
+               lp = lp->next;
+           }
+
+           sendto_one(sptr, rpl_str(RPL_ENDOFWATCHLIST), me.name, parv[0],
+                      *s);
+
+           continue;
+       }
+
+       /*
+        * Hmm.. unknown prefix character.. Ignore it. :-)
+        */
+    }
+
+    return 0;
+}
+
+
+
+
+/*
+** m_summon should be redefined to ":prefix SUMMON host user" so
+** that "hunt_server"-function could be used for this too!!! --msa
+** As of 2.7.1e, this was the case. -avalon
+**
+**     parv[0] = sender prefix
+**     parv[1] = user
+**     parv[2] = server
+**     parv[3] = channel (optional)
+*/
+int    m_summon(cptr, sptr, parc, parv)
+aClient *sptr, *cptr;
+int    parc;
+char   *parv[];
+{
+       char    *host, *user, *chname;
+#ifdef ENABLE_SUMMON
+       char    hostbuf[17], namebuf[10], linebuf[10];
+#  ifdef LEAST_IDLE
+        char   linetmp[10], ttyname[15]; /* Ack */
+        struct stat stb;
+        time_t ltime = (time_t)0;
+#  endif
+       int     fd, flag = 0;
+#endif
+
+       if (check_registered_user(sptr))
+               return 0;
+       if (parc < 2 || *parv[1] == '\0')
+           {
+               sendto_one(sptr, err_str(ERR_NORECIPIENT),
+                          me.name, parv[0], "SUMMON");
+               return 0;
+           }
+       user = parv[1];
+       host = (parc < 3 || BadPtr(parv[2])) ? me.name : parv[2];
+       chname = (parc > 3) ? parv[3] : "*";
+       /*
+       ** Summoning someone on remote server, find out which link to
+       ** use and pass the message there...
+       */
+       parv[1] = user;
+       parv[2] = host;
+       parv[3] = chname;
+       parv[4] = NULL;
+       if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) ==
+           HUNTED_ISME)
+           {
+#ifdef ENABLE_SUMMON
+               if ((fd = utmp_open()) == -1)
+                   {
+                       sendto_one(sptr, err_str(ERR_FILEERROR),
+                                  me.name, parv[0], "open", UTMP);
+                       return 0;
+                   }
+#  ifndef LEAST_IDLE
+               while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf,
+                                        sizeof(hostbuf))) == 0) 
+                       if (StrEq(namebuf,user))
+                               break;
+#  else
+                /* use least-idle tty, not the first
+                 * one we find in utmp. 10/9/90 Spike@world.std.com
+                 * (loosely based on Jim Frost jimf@saber.com code)
+                 */
+               
+                while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf,
+                                        sizeof(hostbuf))) == 0)
+                   {
+                       if (StrEq(namebuf,user))
+                           {
+                               (void)sprintf(ttyname,"/dev/%s",linetmp);
+                               if (stat(ttyname,&stb) == -1)
+                                   {
+                                       sendto_one(sptr,
+                                                  err_str(ERR_FILEERROR),
+                                                  me.name, sptr->name,
+                                                  "stat", ttyname);
+                                       return 0;
+                                   }
+                               if (!ltime)
+                                   {
+                                       ltime= stb.st_mtime;
+                                       (void)strcpy(linebuf,linetmp);
+                                   }
+                               else if (stb.st_mtime > ltime) /* less idle */
+                                   {
+                                       ltime= stb.st_mtime;
+                                       (void)strcpy(linebuf,linetmp);
+                                   }
+                           }
+                   }
+#  endif
+               (void)utmp_close(fd);
+#  ifdef LEAST_IDLE
+                if (ltime == 0)
+#  else
+               if (flag == -1)
+#  endif
+                       sendto_one(sptr, err_str(ERR_NOLOGIN),
+                                  me.name, parv[0], user);
+               else
+                       summon(sptr, user, linebuf, chname);
+#else
+               sendto_one(sptr, err_str(ERR_SUMMONDISABLED),
+                          me.name, parv[0]);
+#endif /* ENABLE_SUMMON */
+           }
+       return 0;
+}
+
+
+/*
+** m_stats
+**     parv[0] = sender prefix
+**     parv[1] = statistics selector (defaults to Message frequency)
+**     parv[2] = server name (current server defaulted, if omitted)
+**
+**     Currently supported are:
+**             M = Message frequency (the old stat behaviour)
+**             L = Local Link statistics
+**              C = Report C and N configuration lines
+*/
+/*
+** m_stats/stats_conf
+**    Report N/C-configuration lines from this server. This could
+**    report other configuration lines too, but converting the
+**    status back to "char" is a bit akward--not worth the code
+**    it needs...
+**
+**    Note:   The info is reported in the order the server uses
+**            it--not reversed as in ircd.conf!
+*/
+
+static int report_array[18][3] = {
+               { CONF_CONNECT_SERVER,    RPL_STATSCLINE, 'C'},
+               { CONF_NOCONNECT_SERVER,  RPL_STATSNLINE, 'N'},
+               { CONF_CLIENT,            RPL_STATSILINE, 'I'},
+           { CONF_KILL,              RPL_STATSKLINE, 'K'},
+               { CONF_EXCEPT,          RPL_STATSKLINE, 'E'},
+               { CONF_ZAP,                               RPL_STATSKLINE, 'Z'},
+               { CONF_QUARANTINED_NICK,  RPL_STATSQLINE, 'Q'},
+               { CONF_LEAF,                      RPL_STATSLLINE, 'L'},
+               { CONF_OPERATOR,                  RPL_STATSOLINE, 'O'},
+               { CONF_HUB,                   RPL_STATSHLINE, 'H'},
+               { CONF_LOCOP,             RPL_STATSOLINE, 'o'},
+               { CONF_CRULEALL,          RPL_STATSDLINE, 'D'},
+               { CONF_CRULEAUTO,         RPL_STATSDLINE, 'd'},
+               { CONF_UWORLD,            RPL_STATSULINE, 'U'},
+               { CONF_MISSING,           RPL_STATSXLINE, 'X'},
+               { CONF_TLINE,             RPL_STATSTLINE, 't'},
+               { 0, 0}
+                               };
+
+static  void   report_sqlined_nicks(sptr)
+aClient *sptr;
+{
+       aSqlineItem *tmp;
+       char *nickmask, *reason;
+
+       for(tmp = sqline; tmp; tmp=tmp->next) {
+               if(tmp->status != CONF_ILLEGAL) {
+                       nickmask = BadPtr(tmp->sqline) ? "<NULL>" : tmp->sqline;
+                       reason = BadPtr(tmp->reason) ? "<NULL>" : tmp->reason;
+                       sendto_one(sptr, rpl_str(RPL_SQLINE_NICK), me.name,
+                               sptr->name, nickmask, reason);
+               }
+       }
+}
+
+static void    report_configured_links(sptr, mask)
+aClient *sptr;
+int    mask;
+{
+       static  char    null[] = "<NULL>";
+       aConfItem *tmp;
+       int     *p, port, tmpmask;
+       char    c, *host, *pass, *name;
+       char *pp, *ppx; 
+       tmpmask = (mask == CONF_MISSING) ? CONF_CONNECT_SERVER : mask;
+
+       for (tmp = conf; tmp; tmp = tmp->next)
+               if (tmp->status & tmpmask)
+                   {
+                       for (p = &report_array[0][0]; *p; p += 3)
+                               if (*p == tmp->status)
+                                       break;
+                       if (!*p)
+                               continue;
+                       c = (char)*(p+2);
+                       host = BadPtr(tmp->host) ? null : tmp->host;
+                       pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
+                       name = BadPtr(tmp->name) ? null : tmp->name;
+                       port = (int)tmp->port;
+                       /*
+                        * On K line the passwd contents can be
+                        * displayed on STATS reply.    -Vesa
+                        */
+                       /* Same with Z-lines and q/Q-lines -- Barubary */
+                       if ((tmp->status == CONF_KILL) || (tmp->status &
+                           CONF_QUARANTINE) || (tmp->status & CONF_EXCEPT)
+                             ||
+                           (tmp->status == CONF_ZAP))
+                       {
+/* These mods are to tell the difference between the different kinds
+ * of klines.  the only effect it has is in the display.  --Russell
+ */
+/* Now translates spaces to _'s to show comments in klines -- Barubary */
+                               char *temp;
+                               if (!pass) strcpy(buf, "<NULL>");
+                               else {
+                                       strcpy(buf, pass);
+                                       for (temp = buf; *temp; temp++)
+                                       if (*temp == ' ') *temp = '_';
+                               }
+                               /* semicolon intentional -- Barubary */
+                               if (tmp->status == CONF_QUARANTINED_NICK);
+                               /* Hide password for servers -- Barubary */
+                               else if (tmp->status & CONF_QUARANTINE)
+                                       strcpy(buf, "*");
+                               else {
+/* This wasn't documented before - comments aren't displayed for akills
+   because they are all the same. -- Barubary */
+                               if (tmp->tmpconf == KLINE_AKILL)
+                                       strcpy(buf, "*");
+
+       /*                Show comments in E:Lines..
+                               if (tmp->tmpconf == KLINE_EXCEPT)
+                                       strcpy(buf, "*");
+       */
+                               /* KLINE_PERM == 0 - watch out when doing
+                                  Z-lines. -- Barubary */
+                               if (tmp->status != CONF_ZAP)
+                                {
+                               if (tmp->tmpconf == KLINE_PERM) c = 'K';
+                               if (tmp->tmpconf == KLINE_TEMP) c = 'k';
+                               if (tmp->tmpconf == KLINE_AKILL) c = 'A';
+                               if (tmp->tmpconf == KLINE_EXCEPT) c = 'E';
+                                }
+                                 else
+                                {
+                               if (tmp->tmpconf == KLINE_PERM) c = 'Z';
+                               if (tmp->tmpconf == KLINE_TEMP) c = 'z';
+                               if (tmp->tmpconf == KLINE_AKILL) c = 'S';
+                               if (tmp->tmpconf == KLINE_EXCEPT) c = 'e';
+                                }
+                                }
+                               sendto_one(sptr, rpl_str(p[1]), me.name,
+                                          sptr->name, c,  host,
+                                          buf, name, port,
+                                          get_conf_class(tmp));
+                       }
+                         else if (mask & CONF_OPS)
+                            {
+                               sendto_one(sptr, rpl_str(p[1]), me.name,
+                               sptr->name,c,host,name, oflagstr(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);
+                       /* Only display on X if server is missing */
+                       else if (mask == CONF_MISSING) {
+                           if (!find_server(name, NULL))
+                               sendto_one(sptr, rpl_str(RPL_STATSXLINE), me.name,
+                                          sptr->name, name, port);
+                       }
+                               else if (mask == CONF_TLINE)
+                   {
+                       sendto_one(sptr, rpl_str(RPL_STATSTLINE), me.name,
+                               sptr->name, host, pass, name);
+                   }
+/*                     else if (mask == CONF_EXCEPT)
+                       {
+                               ppx = MyMalloc(strlen(tmp->passwd) + 1);
+                               strcpy(ppx, tmp->passwd);
+                               for (pp = ppx; *pp != '\0'; pp++) {
+                                       if (*pp == ' ')
+                                               *pp = '_';
+                               }
+                               sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
+                                       sptr->name, "E", host, ppx, name, 0,0, -1);
+                               MyFree(ppx);
+                       } */
+                        else {
+                            if(!IsOper(sptr)&&(mask&CONF_NOCONNECT_SERVER ||
+                                mask&CONF_CONNECT_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;
+}
+       
+                                                                                                                                                                 
+
+/* Used to blank out ports -- Barubary */
+char *get_client_name2(aClient *acptr, int showports)
+{
+       char *pointer = get_client_name(acptr, TRUE);
+
+       if (!pointer) return NULL;
+       if (showports) return pointer;
+       if (!strrchr(pointer, '.')) return NULL;
+       strcpy((char *) strrchr((char *) pointer, '.'), ".0]");
+
+       return pointer;
+}
+
+int    m_stats(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+#ifndef DEBUGMODE
+       static  char    Sformat[]  = ":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since :Idle";
+       static  char    Lformat[]  = ":%s %d %s %s %u %u %u %u %u %u :%u";
+#else
+       static  char    Sformat[]  = ":%s %d %s SendQ SendM SendBytes RcveM RcveBytes Open_since CPU :Idle";
+       static  char    Lformat[]  = ":%s %d %s %s %u %u %u %u %u %u %s";
+       char    pbuf[96];       /* Should be enough for to ints */
+#endif
+       struct  Message *mptr;
+       aClient *acptr;
+       char    stat = parc > 1 ? parv[1][0] : '\0';
+       Reg1    int     i;
+       int     doall = 0, wilds = 0, showports = IsAnOper(sptr), remote=0;
+       char    *name;
+
+       if (check_registered(sptr))
+               return 0;
+
+#ifdef STATS_ONLYOPER
+       if (!IsAnOper(sptr))
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+
+#endif
+
+       if (hunt_server(cptr,sptr,":%s STATS %s :%s",2,parc,parv)!=HUNTED_ISME)
+               return 0;
+
+       if (parc > 2)
+           {
+               name = parv[2];
+               if (!mycmp(name, me.name))
+                       doall = 2;
+               else if (match(name, me.name) == 0)
+                       doall = 1;
+               if (index(name, '*') || index(name, '?'))
+                       wilds = 1;
+           }
+       else
+               name = me.name;
+
+        if (stat != '\0')
+                sendto_umode(UMODE_EYES,"Stats \'%c\' requested by %s (%s@%s)", stat, sptr->name,
+                                sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+        else
+                sendto_umode(UMODE_EYES,"Stats \'NULL\' requested by %s (%s@%s)", sptr->name,
+                                sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+
+       switch (stat)
+       {
+       case 'L' : case 'l' :
+               /*
+                * 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]);
+               if (IsServer(cptr)) {
+                       remote = 1;
+                       wilds = 0;
+               }
+               for (i = 0; i <= highest_fd; i++)
+                   {
+                       if (!(acptr = local[i]))
+                               continue;
+                       if (IsInvisible(acptr) && (doall || wilds) &&
+                           !(MyConnect(sptr) && IsOper(sptr)) &&
+                           !IsAnOper(acptr) && (acptr != sptr))
+                               continue;
+                       if (remote && doall && !IsServer(acptr) &&
+                           !IsMe(acptr))
+                               continue;
+                       if (remote && !doall && IsServer(acptr))
+                               continue;
+                       if (!doall && wilds && match(name, acptr->name))
+                               continue;
+                       if (!(parc == 2 && IsServer(acptr)) &&
+                           !(doall || wilds) && mycmp(name, acptr->name))
+                               continue;
+#ifdef DEBUGMODE
+                       sprintf(pbuf, "%d :%d", acptr->cputime,
+                               (acptr->user && MyConnect(acptr)) ?
+                               TStime() - acptr->user->last : 0);
+#endif
+                if(IsOper(sptr)) {
+                        sendto_one(sptr, Lformat, me.name,
+                                   RPL_STATSLINKINFO, parv[0],
+                                   (isupper(stat)) ?
+                                   get_client_name2(acptr, showports) :
+                                   get_client_name(acptr, FALSE),
+                                   (int)DBufLength(&acptr->sendQ),
+                                   (int)acptr->sendM, (int)acptr->sendK,
+                                   (int)acptr->receiveM, (int)acptr->receiveK,
+                                   TStime() - acptr->firsttime,
+#ifndef DEBUGMODE
+                                   (acptr->user && MyConnect(acptr)) ?
+                                    TStime() - acptr->user->last : 0);
+#else
+                                   pbuf);
+#endif
+                       if (!IsServer(acptr) && IsAnOper(acptr))
+                               sendto_one(acptr, ":%s NOTICE %s :*** %s did a /stats L on you! IP may have been shown", me.name, acptr->name, sptr->name);
+                       }
+                        else if(!strchr(acptr->name,'.'))
+                       sendto_one(sptr, Lformat, me.name,
+                                  RPL_STATSLINKINFO, parv[0],
+                                   IsHidden(acptr) ? acptr->name :
+                                   (isupper(stat)) ? /* Potvin - PreZ */
+                                   get_client_name2(acptr, showports) :
+                                   get_client_name(acptr, FALSE),
+                                  (int)DBufLength(&acptr->sendQ),
+                                  (int)acptr->sendM, (int)acptr->sendK,
+                                  (int)acptr->receiveM, (int)acptr->receiveK,
+                                  TStime() - acptr->firsttime,
+#ifndef DEBUGMODE
+                                  (acptr->user && MyConnect(acptr)) ?
+                                   TStime() - acptr->user->last : 0);
+#else
+                                  pbuf);
+#endif
+                   }
+               break;
+       case 'C' : case 'c' :
+                report_configured_links(sptr, CONF_CONNECT_SERVER|
+                                       CONF_NOCONNECT_SERVER);
+               break;
+       case 'f' : case 'F' :
+               report_flines(sptr);
+               break;
+       
+       case 'G' : case 'g' :
+               tkl_stats (sptr);
+               break;
+       case 'H' : case 'h' :
+                report_configured_links(sptr, CONF_HUB|CONF_LEAF);
+               break;
+       case 'I' : case 'i' :
+               report_configured_links(sptr, CONF_CLIENT);
+               break;
+       case 'E' : case 'e' : 
+               report_configured_links(sptr, CONF_EXCEPT);
+               break;
+       case 'K' : case 'k' :
+               report_configured_links(sptr, CONF_KILL|CONF_ZAP|CONF_EXCEPT);
+               break;
+       case 'M' : case 'm' :
+               for (mptr = msgtab; mptr->cmd; mptr++)
+                       if (mptr->count)
+#ifndef DEBUGMODE
+                               sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
+                                          me.name, parv[0], mptr->cmd,
+                                          mptr->count, mptr->bytes);
+#else
+                               sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
+                                          me.name, parv[0], mptr->cmd,
+                                          mptr->count, mptr->bytes,
+                                          mptr->lticks,
+                                          mptr->lticks/CLOCKS_PER_SEC,
+                                          mptr->rticks,
+                                          mptr->rticks/CLOCKS_PER_SEC);
+#endif
+               break;
+       case 'N': case 'n':
+               if (IsOper(sptr))
+               report_network(sptr);
+               break;
+       case 'o' : case 'O' :
+/*                     if (SHOWOPERS == 1) {
+                               if(IsOper(sptr)) {
+                                       report_configured_links(sptr, CONF_OPS);
+                                       break;
+                               }
+                       }
+                               else
+                       if (SHOWOPERS == 0) {
+                               report_configured_links(sptr, CONF_OPS);                        
+*/
+               if (SHOWOPERS == 0 && (IsOper(sptr))) {
+                       report_configured_links(sptr, CONF_OPS);
+                       break;
+               }               
+               if (SHOWOPERS == 1)
+                       report_configured_links(sptr, CONF_OPS);
+               break;
+       case 'Q' :
+               report_configured_links(sptr, CONF_QUARANTINE);
+               break;
+       case 'q' :
+               report_sqlined_nicks(sptr);
+               break;
+       case 'R' : 
+#ifdef DEBUGMODE
+               send_usage(sptr,parv[0]);
+#endif
+               break;
+       case 'S' :
+               if (IsOper(sptr))
+               report_dynconf(sptr);
+               break;
+       case 'D' :
+               report_configured_links(sptr, CONF_CRULEALL);
+               break;
+       case 'd' :
+               report_configured_links(sptr, CONF_CRULE);
+               break;
+       case 'r' :
+               cr_report(sptr);
+               break;
+       case 't' : 
+           report_configured_links(sptr, CONF_TLINE);
+           break;
+       case 'T' : /* /stats T not t:lines .. */ 
+               tstats(sptr, parv[0]);
+               break;
+       case 'U' :
+                report_configured_links(sptr, CONF_UWORLD);
+               break;
+       case 'u' :
+           {
+               register time_t tmpnow;
+
+               tmpnow = TStime() - me.since;
+               sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
+                          tmpnow/86400, (tmpnow/3600)%24, (tmpnow/60)%60, tmpnow%60);
+                sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
+                          max_connection_count, max_client_count);
+               break;
+           }
+        case 'v' : case 'V' :
+               vhost_report(sptr);
+               break;
+        case 'W' : case 'w' :
+                calc_load(sptr, parv[0]);
+                break;
+       case 'X' : case 'x' :
+               report_configured_links(sptr, CONF_MISSING);
+               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_users
+**     parv[0] = sender prefix
+**     parv[1] = servername
+*/
+int    m_users(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+#ifdef ENABLE_USERS
+       char    namebuf[10],linebuf[10],hostbuf[17];
+       int     fd, flag = 0;
+#endif
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (hunt_server(cptr,sptr,":%s USERS :%s",1,parc,parv) == HUNTED_ISME)
+           {
+#ifdef ENABLE_USERS
+               if ((fd = utmp_open()) == -1)
+                   {
+                       sendto_one(sptr, err_str(ERR_FILEERROR),
+                                  me.name, parv[0], "open", UTMP);
+                       return 0;
+                   }
+
+               sendto_one(sptr, rpl_str(RPL_USERSSTART), me.name, parv[0]);
+               while (utmp_read(fd, namebuf, linebuf,
+                                hostbuf, sizeof(hostbuf)) == 0)
+                   {
+                       flag = 1;
+                       sendto_one(sptr, rpl_str(RPL_USERS), me.name, parv[0],
+                                  namebuf, linebuf, hostbuf);
+                   }
+               if (flag == 0) 
+                       sendto_one(sptr, rpl_str(RPL_NOUSERS),
+                                  me.name, parv[0]);
+
+               sendto_one(sptr, rpl_str(RPL_ENDOFUSERS), me.name, parv[0]);
+               (void)utmp_close(fd);
+#else
+               sendto_one(sptr, err_str(ERR_USERSDISABLED), me.name, parv[0]);
+#endif
+           }
+       return 0;
+}
+
+/*
+** Note: At least at protocol level ERROR has only one parameter,
+** although this is called internally from other functions
+** --msa
+**
+**     parv[0] = sender prefix
+**     parv[*] = parameters
+*/
+int    m_error(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       Reg1    char    *para;
+
+       para = (parc > 1 && *parv[1] != '\0') ? parv[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 (IsPerson(cptr) || IsUnknown(cptr) || IsService(cptr))
+               return 0;
+       if (cptr == sptr) {
+               sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s -- %s",
+                          me.name, get_client_name(cptr, FALSE), para);
+               sendto_locfailops("ERROR :from %s -- %s",
+                          get_client_name(cptr, FALSE), para);
+       }
+       else {
+                sendto_serv_butone(&me, ":%s GLOBOPS :ERROR from %s via %s -- %s",
+                           me.name, sptr->name, get_client_name(cptr, FALSE), para);
+               sendto_ops("ERROR :from %s via %s -- %s", sptr->name,
+                          get_client_name(cptr,FALSE), para);
+       }
+       return 0;
+    }
+
+Link *helpign=NULL;
+
+/* Now just empty ignore-list, in future reload dynamic help. 
+ * Move out to help.c -Donwulff */
+void reset_help() {
+       free_str_list(helpign);
+}
+
+
+
+
+/*
+** m_help (help/write to +h currently online) -Donwulff
+**     parv[0] = sender prefix
+**     parv[1] = optional message text
+*/
+int    m_help(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       int i;
+        char    *message, *pv[4], *s;
+        Link   *tmpl;
+
+         if (check_registered(sptr))
+                 return 0;
+  
+       message = parc > 1 ? parv[1] : NULL;
+
+/* Drags along from wallops code... I'm not sure what it's supposed to do, 
+   at least it won't do that gracefully, whatever it is it does - but
+   checking whether or not it's a person _is_ good... -Donwulff */
+
+       if (!IsServer(sptr) && MyConnect(sptr) && !IsPerson(sptr))
+           {
+               check_registered(sptr);
+               return 0;
+           }
+
+       if (IsServer(sptr) || IsHelpOp(sptr)) {
+               if(BadPtr(message)) return 0;
+           if(message[0]=='?') {
+                       parse_help(sptr, parv[0], message+1);
+                       return 0;
+       }
+               if (message[1]=='!')
+               sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                                  ":%s HELP %s", parv[0], message);
+               if(!myncmp(message, "IGNORE ", 7)) {
+                       tmpl=make_link();
+                       DupString(tmpl->value.cp, message+7);
+                       tmpl->next = helpign;
+                       helpign=tmpl;
+               }
+               sendto_helpops("from %s (HelpOp): %s", parv[0], message);
+       } else if (MyConnect(sptr)) {
+               /* New syntax: ?... never goes out, !... always does. */
+               if(!BadPtr(message)) {
+                       parse_help(sptr, parv[0], message);
+                       return 0;
+               }
+               if((!BadPtr(message)&&!(message[0]=='!'))||BadPtr(message))
+                       if(parse_help(sptr, parv[0], message)) return 0;
+
+               s = make_nick_user_host(cptr->name, cptr->user->username,
+                                         cptr->user->realhost);
+               for (tmpl = helpign; tmpl; tmpl = tmpl->next)
+                       if (match(tmpl->value.cp, s) == 0) {
+                               sendto_one(sptr, rpl_str(RPL_HELPIGN), me.name, parv[0]);
+                               return 0;
+                       }
+
+               sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                                  ":%s HELP %s", parv[0], message);
+               sendto_helpops("from %s (Local): %s", parv[0], message);
+               sendto_one(sptr, rpl_str(RPL_HELPFWD), me.name, parv[0]);
+       } else {
+               sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                                  ":%s HELP %s", parv[0], message);
+               sendto_helpops("from %s: %s", parv[0], message);
+       }
+       
+       return 0;
+}
+
+/*
+ * parv[0] = sender
+ * parv[1] = host/server mask.
+ * parv[2] = server to query
+ */
+int     m_lusers(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       int     s_count, c_count, u_count, i_count;
+       int     o_count, m_client, m_client_local, m_server;
+        char mydom_mask[HOSTLEN + 1];
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+/*     Doesn't work anyways --Stskeeps
+
+       if (parc > 2)
+               if(hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
+                               != HUNTED_ISME)
+                       return 0;
+*/
+
+       mydom_mask[0] = '*';
+       strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1); 
+       if(parc==1) {
+               s_count = lu_serv;
+               c_count = lu_noninv;
+               u_count = lu_unknown;
+               i_count = lu_inv;
+               o_count = lu_oper;
+               m_client = lu_lu;
+               m_client_local = lu_lulocal;
+               m_server = lu_lserv;
+               global_count=lu_cglobalu;
+       }
+       else {
+               s_count=c_count=u_count=i_count=o_count=m_client=
+                       m_client_local=m_server=0;
+               (void)collapse(parv[1]);
+               for (acptr = client; acptr; acptr = acptr->next)
+               {
+                       if (parc>1)
+                               if (!IsServer(acptr) && acptr->user)
+                               {
+                                       if (match(parv[1], acptr->user->server))
+                                               continue;
+                               }
+                               else
+                                       if (match(parv[1], acptr->name))
+                                               continue;
+
+                       switch (acptr->status)
+                       {
+                       case STAT_SERVER:
+                               if (MyConnect(acptr))
+                                       m_server++;
+                       case STAT_ME:
+                               s_count++;
+                               break;
+                       case STAT_CLIENT:
+                               if (IsOper(acptr))
+                                       o_count++;
+                               if (MyConnect(acptr)) {
+                                       m_client++;
+                                       if (match(mydom_mask, acptr->sockhost) == 0)
+                                         m_client_local++;
+                                     }
+                               if (!IsInvisible(acptr))
+                                       c_count++;
+                               else
+                                       i_count++;
+                               break;
+                       default:
+                               u_count++;
+                               break;
+                       }
+                    }
+       }
+       sendto_one(sptr, rpl_str(RPL_LUSERCLIENT), me.name, parv[0],
+                  c_count, i_count, s_count);
+          max_client_count = lu_mlu;
+         max_global_count = lu_mglobalu;
+
+       if (o_count)
+               sendto_one(sptr, rpl_str(RPL_LUSEROP),
+                          me.name, parv[0], o_count);
+       if (u_count > 0)
+               sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN),
+                          me.name, parv[0], u_count);
+       if ((c_count = count_channels(sptr))>0)
+               sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS),
+                          me.name, parv[0], lu_channel);
+       sendto_one(sptr, rpl_str(RPL_LUSERME),
+                  me.name, parv[0], m_client, m_server);
+       sendto_one(sptr, rpl_str(RPL_LOCALUSERS),
+                   me.name, parv[0], m_client, max_client_count);
+       sendto_one(sptr, rpl_str(RPL_GLOBALUSERS),
+                   me.name, parv[0], global_count, max_global_count);
+        if ((m_client + m_server) > max_connection_count) {
+          max_connection_count = m_client + m_server;
+          if (max_connection_count % 10 == 0)  /* only send on even tens */
+            sendto_ops("Maximum connections: %d (%d clients)",
+                     max_connection_count, max_client_count);
+        }
+        current_load_data.local_count = m_client_local;
+        current_load_data.client_count = m_client;
+        current_load_data.conn_count = m_client + m_server;
+       return 0;
+}
+
+  
+void   save_tunefile(void)
+{
+       FILE    *tunefile;
+       
+       tunefile = fopen(IRCDTUNE, "w+");
+       if (!tunefile) {
+#if !defined(_WIN32) && !defined(_AMIGA)
+               sendto_ops("Unable to write tunefile.. %s", strerror(errno));
+#else
+               sendto_ops("Unable to write tunefile..");
+#endif
+               return;
+       }
+       fprintf(tunefile, "%li\n", TSoffset);   
+       fprintf(tunefile, "%li\n", lu_mlu);
+       fclose(tunefile);
+}
+
+void   load_tunefile(void)
+{
+       FILE *tunefile;
+       char    buf[1024];
+       
+       tunefile = fopen(IRCDTUNE, "r");
+       if (!tunefile)
+               return;
+       fprintf(stderr, "* Loading tunefile..\n");                      
+       fgets(buf, 1023, tunefile);
+       TSoffset = atol(buf);
+       fgets(buf, 1023, tunefile);
+       lu_mlu = atol(buf);
+       fclose(tunefile);
+}
+
+/***********************************************************************
+ * m_connect() - Added by Jto 11 Feb 1989
+ ***********************************************************************/
+
+/*
+** m_connect
+**     parv[0] = sender prefix
+**     parv[1] = servername
+**     parv[2] = port number
+**     parv[3] = remote server
+*/
+int    m_connect(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       int     port, tmpport, retval;
+       aConfItem *aconf, *cconf;
+       aClient *acptr;
+
+         if (check_registered(sptr))
+                 return 0;
+  
+       if (!IsPrivileged(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return -1;
+           }
+
+       if (MyClient(sptr) && !OPCanGRoute(sptr) && parc > 3)
+           {                           /* Only allow LocOps to make */
+                                       /* local CONNECTS --SRB      */
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+       if (MyClient(sptr) && !OPCanLRoute(sptr) && parc <= 3)
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;   
+           }
+       if (hunt_server(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 = find_server(parv[1], NULL)))
+           {
+               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;
+           }
+
+       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], index(aconf->host, '@')+1) == 0))
+                               break;
+
+       if (!aconf)
+           {
+             sendto_one(sptr,
+                        "NOTICE %s :Connect: Host %s not listed in ircd.conf",
+                        parv[0], parv[1]);
+             return 0;
+           }
+       /*
+       ** Get port number from user, if given. If not specified,
+       ** use the default form configuration structure. If missing
+       ** from there, then use the precompiled default.
+       */
+       tmpport = port = aconf->port;
+       if (parc > 2 && !BadPtr(parv[2]))
+           {
+               if ((port = atoi(parv[2])) <= 0)
+                   {
+                       sendto_one(sptr,
+                                  "NOTICE %s :Connect: Illegal port number",
+                                  parv[0]);
+                       return 0;
+                   }
+           }
+       else if (port <= 0 && (port = PORTNUM) <= 0)
+           {
+               sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number",
+                          me.name, parv[0]);
+               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))
+             {
+               sendto_one(sptr,
+                          "NOTICE %s :Connect: Disallowed by rule: %s",
+                          parv[0], cconf->name);
+               return 0;
+             }
+
+       /*
+       ** Notify all operators about remote connect requests
+       */
+       if (!IsAnOper(cptr))
+           {
+               sendto_serv_butone(&me,
+                                 ":%s GLOBOPS :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:
+               sendto_one(sptr,
+                          ":%s NOTICE %s :*** Connecting to %s[%s].",
+                          me.name, parv[0], aconf->host, aconf->name);
+               break;
+       case -1:
+               sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
+                          me.name, parv[0], aconf->host);
+               break;
+       case -2:
+               sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
+                          me.name, parv[0], aconf->host);
+               break;
+       default:
+               sendto_one(sptr,
+                          ":%s NOTICE %s :*** Connection to %s failed: %s",
+                          me.name, parv[0], aconf->host, strerror(retval));
+       }
+       aconf->port = tmpport;
+       return 0;
+    }
+
+/*
+** m_wallops (write to *all* opers currently online)
+**     parv[0] = sender prefix
+**     parv[1] = message text
+*/
+int    m_wallops(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       char    *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+  
+       message = parc > 1 ? parv[1] : NULL;
+
+       if (BadPtr(message))
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "WALLOPS");
+               return 0;
+           }
+       if (MyClient(sptr) && !OPCanWallOps(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_gnotice  (Russell) sort of like wallop, but only to +g clients on 
+** this server.
+**     parv[0] = sender prefix
+**     parv[1] = message text
+*/
+int    m_gnotice(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       char *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+  
+        message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "GNOTICE");
+                return 0;
+            }
+        if (!IsServer(sptr) && MyConnect(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+       sendto_serv_butone(IsServer(cptr) ? cptr : NULL, ":%s GNOTICE :%s",
+                parv[0], message);
+       sendto_failops("from %s: %s", parv[0], message);
+       return 0;
+}
+
+/*
+** m_addline (write a line to ircd.conf)
+**
+** De-Potvinized by codemastr
+*/
+int     m_addline(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+        FILE *conf;
+               int     i;
+               char *text;
+               text = parc > 1 ? parv[1] : NULL;
+
+       if (check_registered(sptr))
+               return 0;
+               
+
+        if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+        if (parc < 2)
+        {
+                sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                            me.name, parv[0], "ADDLINE");
+                return 0;
+        }
+        conf = fopen (CPATH, "a");
+        if (conf == NULL)
+        {
+                return 0;
+        }
+               /* Display what they wrote too */
+        sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to ircd.conf",
+                               me.name, parv[0], text);
+       fprintf(conf, "# Added by %s\n", make_nick_user_host(sptr->name,sptr->user->username,sptr->user->realhost));
+/*     for (i=1 ; i<parc ; i++)
+       {
+               if (i!=parc-1)
+                       fprintf (conf,"%s ",parv[i]);
+               else
+                       fprintf (conf,"%s\n",parv[i]);
+       } 
+       /* I dunno what Potvin was smoking when he made this code, but it plain SUX
+        * this should work just as good, and no need for a loop -- codemastr */
+       fprintf(conf, "%s\n", text);
+     
+       fclose (conf);
+        return 1;
+}
+
+/*
+** m_addmotd (write a line to ircd.motd)
+**
+** De-Potvinized by codemastr
+*/
+int     m_addmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+        FILE *conf;
+               char *text;
+               
+               int     i;
+
+               text = parc > 1 ? parv[1] : NULL;
+
+               if (check_registered(sptr))
+                       return 0;
+               if (!MyConnect(sptr))
+                       return 0;
+
+        if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+        if (parc < 2)
+        {
+                sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                            me.name, parv[0], "ADDMOTD");
+                return 0;
+        }
+        conf = fopen (MOTD, "a");
+        if (conf == NULL)
+        {
+                return 0;
+        }
+        sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to file: ircd.motd",
+                               me.name, parv[0], text);
+       /*      for (i=1 ; i<parc ; i++)
+               {
+                       if (i!=parc-1)
+                               fprintf (conf,"%s ",parv[i]);
+                       else
+                               fprintf (conf,"%s\n",parv[i]);
+               } */
+               fprintf(conf, "%s\n", text);
+     
+               fclose (conf);
+        return 1;
+}
+
+/*
+** m_svsmotd
+**
+*/
+int     m_svsmotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+        FILE *conf = NULL;
+               int     i;
+
+               if (check_registered(sptr))
+                       return 0;
+
+        if (!IsULine(cptr, sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+
+        if (parc < 2)
+        {
+                sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                            me.name, parv[0], "SVSMOTD");
+                return 0;
+        }
+               
+               if ((*parv[1] != '!') && parc < 3) {
+                               sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                            me.name, parv[0], "SVSMOTD");
+                return 0;
+               }
+               
+               switch (*parv[1]) {
+                       case '#' : conf = fopen(VPATH, "a");
+                                          sendto_ops("Added '%s' to services motd", parv[2]);
+                                          break;
+                       case '!' : {
+                                          remove(VPATH);
+                                          sendto_ops("Wiped out services motd data");
+                                          break;
+                               }
+                       default: break;
+               }
+
+       sendto_serv_butone(cptr, ":%s SVSMOTD %s :%s", parv[0], parv[1], parv[2]);
+
+        if (conf == NULL)
+        {
+                return 0;
+        }
+
+               if (parc < 3 && (*parv[1]=='!')) {
+                       fclose(conf);
+                       return 1;       
+               }
+               fprintf(conf, "%s\n", parv[2]);
+               if (*parv[1]=='!')
+                       sendto_ops("Added '%s' to services motd", parv[2]);
+                               
+               fclose (conf);
+        return 1;
+}
+
+/*
+** m_addomotd (write a line to opermotd)
+**
+** De-Potvinized by codemastr
+*/
+int     m_addomotd(aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+        FILE *conf;
+               char *text;
+               int     i;
+
+               text = parc > 1 ? parv[1] : NULL;
+
+               if (check_registered(sptr))
+                       return 0;
+               if (!MyConnect(sptr))
+                       return 0;
+
+        if (!(IsAdmin(sptr) || IsCoAdmin(sptr)))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+        if (parc < 2)
+        {
+                sendto_one (sptr, err_str(ERR_NEEDMOREPARAMS),
+                            me.name, parv[0], "ADDMOTD");
+                return 0;
+        }
+        conf = fopen (OPATH, "a");
+        if (conf == NULL)
+        {
+                return 0;
+        }
+        sendto_one(sptr, ":%s NOTICE %s :*** Wrote (%s) to OperMotd",
+                               me.name, parv[0], text);
+       /*      for (i=1 ; i<parc ; i++)
+               {
+                       if (i!=parc-1)
+                               fprintf (conf,"%s ",parv[i]);
+                       else
+                               fprintf (conf,"%s\n",parv[i]);
+               } */
+               fprintf(conf, "%s\n", text);
+     
+               fclose (conf);
+        return 1;
+}
+
+
+/*
+** m_globops (write to opers who are +g currently online)
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_globops(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+        message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "GLOBOPS");
+                return 0;
+            }
+       if (MyClient(sptr) && !OPCanGlobOps(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+        sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                        ":%s GLOBOPS :%s", parv[0], message);
+        sendto_failops_whoare_opers("from %s: %s", parv[0], message);
+        return 0;
+    }
+
+/*
+** m_locops (write to opers who are +g currently online *this* server)
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_locops(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+
+        if (check_registered_user(cptr))
+                return 0;
+         message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "LOCOPS");
+                return 0;
+            }
+        if (MyClient(sptr) && !OPCanLocOps(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+        sendto_locfailops("from %s: %s", parv[0], message);
+        return 0;
+    }
+
+/*
+** m_chatops (write to opers who are +b currently online)
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_chatops(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+        message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "CHATOPS");
+                return 0;
+            }
+               if (ALLOW_CHATOPS == 1) {
+                       if (MyClient(sptr) && !SendChatops(sptr)) {
+                       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                       return 0;
+           }
+               }
+               else {
+       if (MyClient(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+       }
+        sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                        ":%s CHATOPS :%s", parv[0], message);
+               if (ALLOW_CHATOPS == 1) 
+               /* sendto_chatops("from %s: %s", parv[0], message); */
+               sendto_umode(UMODE_CHATOP, "*** ChatOps -- from %s: %s", parv[0], message);
+
+        return 0;
+    }
+
+/* m_goper  (Russell) sort of like wallop, but only to ALL +o clients on
+** every server.
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_goper(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+       message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "GOPER");
+                return 0;
+            }
+/*      if (!IsServer(sptr) && MyConnect(sptr) && !IsAnOper(sptr))*/
+       if (!IsServer(sptr) || !IsULine(cptr,sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+       sendto_serv_butone(IsServer(cptr) ? cptr : NULL, ":%s GOPER :%s", 
+               parv[0], message);
+        sendto_opers("from %s: %s", parv[0], message);
+       return 0;
+}
+/*
+** m_time
+**     parv[0] = sender prefix
+**     parv[1] = servername
+*/
+int    m_time(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       if (check_registered_user(sptr))
+               return 0;
+       if (hunt_server(cptr,sptr,":%s TIME :%s",1,parc,parv) == HUNTED_ISME)
+               sendto_one(sptr, rpl_str(RPL_TIME), me.name,
+                          parv[0], me.name, date((long)0));
+       return 0;
+    }
+
+/*
+** m_svskill
+**     parv[0] = servername
+**     parv[1] = client
+**     parv[2] = kill message
+*/
+int    m_svskill(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       char    *comment;
+       
+       (parc > 2 && parv[2]) ? parv[2] : "SVS Killed";
+       if (parc < 2)
+               return -1;
+       if (parc == 3)
+               comment = parv[2];
+       
+       if (parc == 2)
+               comment = "SVS Killed";
+                       
+       if(!IsULine(cptr, sptr))
+               return -1;
+
+/*     if (hunt_server(cptr,sptr,":%s SVSKILL %s :%s",1,parc,parv) != HUNTED_ISME)
+               return 0;
+*/
+       
+       if(parc < 1 || (!(acptr = find_client(parv[1], NULL))))
+               return 0;
+       sendto_serv_butone(cptr, ":%s SVSKILL %s :%s", parv[0], parv[1], comment);
+
+       return exit_client(cptr, acptr, sptr, comment);
+
+}
+
+/*
+** m_admin
+**     parv[0] = sender prefix
+**     parv[1] = servername
+*/
+int    m_admin(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       aConfItem *aconf;
+
+       /* Users may want to get the address in case k-lined, etc. -- Barubary
+       if (check_registered(sptr))
+               return 0; */
+
+       /* Only allow remote ADMINs if registered -- Barubary */
+       if (IsPerson(sptr) || IsServer(cptr))
+       if (hunt_server(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 ? aconf->host : "-"));
+               sendto_one(sptr, rpl_str(RPL_ADMINLOC2),
+                          me.name, parv[0],
+                          (aconf->passwd ? aconf->passwd : "-"));
+               sendto_one(sptr, rpl_str(RPL_ADMINEMAIL),
+                          me.name, parv[0],
+                          (aconf->name ? aconf->name : "-"));
+           }
+       else
+               sendto_one(sptr, err_str(ERR_NOADMININFO),
+                          me.name, parv[0], me.name);
+       return 0;
+    }
+
+
+/*
+** m_rehash
+** remote rehash by binary
+** now allows the -flags in remote rehash
+** ugly code but it seems to work :) -- codemastr
+*/
+int     m_rehash(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        int x;
+
+/*        if ((!MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)) && !IsULine(cptr, sptr)) ||
+                (MyClient(sptr) && !OPCanRehash(sptr)))
+*/     if (MyClient(sptr) && !OPCanRehash(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+       if (!MyClient(sptr) && !(IsTechAdmin(sptr) ||IsNetAdmin(sptr)) && !IsULine(cptr, sptr))
+       {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+       }
+        x = 0;
+               
+        if (!BadPtr(parv[1]))
+        {
+                       if (*parv[1] == '-')
+                       {
+                               if (!match("-dcc*", parv[1]))
+                               {
+                                       sendto_ops("Rehashing dccdeny.conf on request of %s", sptr->name);
+                               dcc_rehash();
+                                       return 0;
+                               }
+                               if (!match("-dyn*", parv[1]))
+                               {
+                                       if (!IsAdmin(sptr))
+                                       return 0;
+                                       sendto_ops("Rehashing dynamic configuration on request of %s", sptr->name);
+                                       load_conf(ZCONF, 1);
+                                       return 0;
+                               }
+                               if (!match("-rest*", parv[1]))
+                               {
+                                       if (!IsAdmin(sptr))
+                                       return 0;
+                              sendto_ops("Rehashing channel restrict configuration on request of %s", sptr->name);
+                              cr_rehash();
+                               return 0;
+                               }
+                               if (!match("-vhos*", parv[1]))
+                               {
+                                       if (!IsAdmin(sptr))
+                                       return 0;
+                              sendto_ops("Rehashing vhost configuration on request of %s", sptr->name);
+                              vhost_rehash();
+                               return 0;
+                               }
+                       }
+                if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+                {
+                        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                        return 0;
+                }
+                               /* This little number allows us to send a -param to another server,
+                                * but only if it exists -- codemastr*/
+                               if (parv[2] != NULL) {
+                if ((x=hunt_server(cptr,sptr,":%s REHASH %s %s",1,parc,parv))
+                                != HUNTED_ISME)
+                        return 0;
+                               }
+                               if (parv[2] == NULL) {
+                                       if ((x=hunt_server(cptr,sptr,":%s REHASH %s",1,parc,parv))
+                                != HUNTED_ISME)
+                        return 0;
+                               }
+
+        }
+
+        if (cptr != sptr)
+        {
+
+#ifndef REMOTE_REHASH
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+#else
+                               if (parv[2] == NULL) {
+                sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing server config file",
+                        me.name, sptr->name);
+                sendto_ops("%s is remotely rehashing server config file", parv[0]);
+                               }
+                               /* Then we have a hack here to parse the flags (thats the ugly part) */
+                               else {
+               if (!BadPtr(parv[2]))
+        {
+                       if (*parv[2] == '-')
+                       {
+                               if (!match("-dcc*", parv[2]))
+                               {
+                                       sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing dccdeny.conf",
+                        me.name, sptr->name);
+                                       sendto_ops("Remotely rehashing dccdeny.conf on request of %s", sptr->name);
+                               dcc_rehash();
+                                       return 0;
+                               }
+                               if (!match("-dyn*", parv[2]))
+                               {
+                                       sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing dynamic configuration",
+                        me.name, sptr->name);
+                                       sendto_ops("Remotely rehashing dynamic configuration on request of %s", sptr->name);
+                                       load_conf(ZCONF, 1);
+                                       return 0;
+                               }
+                               if (!match("-rest*", parv[2]))
+                               {
+                                       sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing channel restrict configuration",
+                        me.name, sptr->name);
+                          sendto_ops("Remotely rehashing channel restrict configuration on request of %s", sptr->name);
+                              cr_rehash();
+                               return 0;
+                               }
+                               if (!match("-vhos*", parv[2]))
+                               {
+                                       sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely rehashing vhost configuration",
+                        me.name, sptr->name);
+                          sendto_ops("Remotely rehashing vhost configuration on request of %s", sptr->name);
+                              vhost_rehash();
+                               return 0;
+                               }
+                       }
+               }
+                               }
+
+#endif
+               }
+                               else {
+                sendto_ops("%s is rehashing server config file", parv[0]);
+                               }
+        sendto_one(sptr, rpl_str(RPL_REHASHING), me.name, parv[0], configfile);
+#ifdef USE_SYSLOG
+        syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
+#endif
+        return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q')?2:0) : 0);
+}
+
+/*
+** m_restart
+**
+** parv[1] - password *OR* reason if no X:line
+** parv[2] - reason for restart (optional & only if X:line exists)
+**
+** The password is only valid if there is a matching X line in the
+** config file. If it is not,  then it becomes the 
+*/
+int    m_restart(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+    char *pass = NULL;
+       int x;    
+    if (check_registered(sptr))
+       return 0;
+    
+       if (MyClient(sptr) && !OPCanRestart(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+       if (!MyClient(sptr) && !(IsTechAdmin(sptr) ||IsNetAdmin(sptr)) && !IsULine(cptr, sptr))
+       {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+       }
+   if (parc > 2)
+   {
+       /* Remote restart. */
+                if (MyClient(sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+                {
+                        sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                        return 0;
+                }
+                    
+                if ((x=hunt_server(cptr,sptr,":%s RESTART %s %s :%s",2,parc,parv))
+                                != HUNTED_ISME)
+                        return 0;
+   }
+
+       if (cptr != sptr) {
+                       sendto_serv_butone(&me, ":%s GLOBOPS :%s is remotely restarting server (%s)",
+                        me.name, sptr->name, parv[3]);
+                sendto_ops("%s is remotely restarting IRCd (%s)", parv[0], parv[3]);
+
+       }
+               
+   if ((pass = find_restartpass()))
+       {       
+           if (parc < 2)
+               {
+                   sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "RESTART");
+                   return 0;    
+               }
+               
+           if (strcmp(pass, parv[1]))
+               {
+                   sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+                   return 0;
+               }
+           /* Hack to make the code after this if { } easier: we assign the comment to the
+            * first param, as if we had not had an X:line. We do not need the password
+            * now anyways. Accordingly we decrement parc ;)    -- NikB
+            */
+           parv[1] = parv[2];
+           parc--;
+       }
+       
+#ifdef USE_SYSLOG
+       syslog(LOG_WARNING, "Server RESTART by %s - %s\n",
+               get_client_name(sptr,FALSE), 
+               (!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason")
+                : (parc > 1 ? parv[2] : "No reason")));
+#endif 
+       sendto_ops("Server is Restarting by request of %s", parv[0]);
+       server_reboot((!MyClient(sptr) ? (parc > 2 ? parv[3] : "No reason")
+                : (parc > 1 ? parv[2] : "No reason")));
+       return 0;       
+}
+
+/*
+** m_trace
+**     parv[0] = sender prefix
+**     parv[1] = servername
+*/
+int    m_trace(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    int     i;
+       Reg2    aClient *acptr, *acptr2;
+       aClass  *cltmp;
+       char    *tname;
+       int     doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS];
+       int     cnt = 0, wilds, dow;
+       time_t  now;
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (parc > 2)
+               if (hunt_server(cptr, sptr, ":%s TRACE %s :%s",
+                               2, parc, parv))
+                       return 0;
+
+       if (parc > 1)
+               tname = parv[1];
+       else
+               tname = me.name;
+
+         if(!IsOper(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+
+       switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv))
+       {
+       case HUNTED_PASS: /* note: gets here only if parv[1] exists */
+           {
+               aClient *ac2ptr;
+
+               ac2ptr = next_client(client, tname);
+               sendto_one(sptr, rpl_str(RPL_TRACELINK), me.name, parv[0],
+                          version, debugmode, tname, ac2ptr->from->name);
+               return 0;
+           }
+       case HUNTED_ISME:
+               break;
+       default:
+               return 0;
+       }
+
+       doall = (parv[1] && (parc > 1)) ? !match(tname, me.name): TRUE;
+       wilds = !parv[1] || index(tname, '*') || index(tname, '?');
+       dow = wilds || doall;
+
+#ifndef _WIN32
+       for (i = 0; i < MAXCONNECTIONS; i++)
+               link_s[i] = 0, link_u[i] = 0;
+#else
+       bzero(link_s, sizeof(link_s));
+       bzero(link_u, sizeof(link_u));
+#endif
+
+       if (doall)
+               for (acptr = client; acptr; acptr = acptr->next)
+#ifdef SHOW_INVISIBLE_LUSERS
+                       if (IsPerson(acptr))
+                               link_u[acptr->from->fd]++;
+#else
+                       if (IsPerson(acptr) &&
+                           (!IsInvisible(acptr) || IsOper(sptr)))
+                               link_u[acptr->from->fd]++;
+#endif
+                       else if (IsServer(acptr))
+                               link_s[acptr->from->fd]++;
+
+       /* report all direct connections */
+       
+       now = TStime();
+       for (i = 0; i <= highest_fd; i++)
+           {
+               char    *name;
+               int     class;
+
+               if (!(acptr = local[i])) /* Local Connection? */
+                       continue;
+/* More bits of code to allow oers to see all users on remote traces
+ *             if (IsInvisible(acptr) && dow &&
+ *             if (dow &&
+ *                 !(MyConnect(sptr) && IsOper(sptr)) && */
+               if (!IsOper(sptr) &&
+                   !IsAnOper(acptr) && (acptr != sptr))
+                       continue;
+               if (!doall && wilds && match(tname, acptr->name))
+                       continue;
+               if (!dow && mycmp(tname, acptr->name))
+                       continue;
+               name = get_client_name(acptr,FALSE);
+               class = get_client_class(acptr);
+
+               switch(acptr->status)
+               {
+               case STAT_CONNECTING:
+                       sendto_one(sptr, rpl_str(RPL_TRACECONNECTING), me.name,
+                                  parv[0], class, name);
+                       cnt++;
+                       break;
+               case STAT_HANDSHAKE:
+                       sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE), me.name,
+                                  parv[0], class, name);
+                       cnt++;
+                       break;
+               case STAT_ME:
+                       break;
+               case STAT_UNKNOWN:
+                       sendto_one(sptr, rpl_str(RPL_TRACEUNKNOWN),
+                                  me.name, parv[0], class, name);
+                       cnt++;
+                       break;
+               case STAT_CLIENT:
+                       /* Only opers see users if there is a wildcard
+                        * but anyone can see all the opers.
+                        */
+/*                     if (IsOper(sptr) &&
+ * Allow opers to see invisible users on a remote trace or wildcard 
+ * search  ... sure as hell  helps to find clonebots.  --Russell
+ *                         (MyClient(sptr) || !(dow && IsInvisible(acptr)))
+ *                           || !dow || IsAnOper(acptr)) */
+                       if (IsOper(sptr) ||
+                           (IsAnOper(acptr) && !IsInvisible(acptr)))
+                           {
+                               if (IsAnOper(acptr))
+                                       sendto_one(sptr,
+                                                  rpl_str(RPL_TRACEOPERATOR),
+                                                  me.name,
+                                                  parv[0], class, acptr->name, IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost,
+                                                  now - acptr->lasttime);
+                               else
+                                       sendto_one(sptr,rpl_str(RPL_TRACEUSER),
+                                                  me.name, parv[0],
+                                                  class, acptr->name, acptr->user->realhost,
+                                                  now - acptr->lasttime);
+                               cnt++;
+                           }
+                       break;
+               case STAT_SERVER:
+                       if (acptr->serv->user)
+                               sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                                          me.name, parv[0], class, link_s[i],
+                                          link_u[i], name, acptr->serv->by,
+                                          acptr->serv->user->username,
+                                          acptr->serv->user->realhost,
+                                          now - acptr->lasttime);
+                       else
+                               sendto_one(sptr, rpl_str(RPL_TRACESERVER),
+                                          me.name, parv[0], class, link_s[i],
+                                          link_u[i], name, *(acptr->serv->by) ?
+                                          acptr->serv->by : "*", "*", me.name,
+                                          now - acptr->lasttime);
+                       cnt++;
+                       break;
+               case STAT_SERVICE:
+                       sendto_one(sptr, rpl_str(RPL_TRACESERVICE),
+                                  me.name, parv[0], class, name);
+                       cnt++;
+                       break;
+               case STAT_LOG:
+                       sendto_one(sptr, rpl_str(RPL_TRACELOG), me.name,
+                                  parv[0], LOGFILE, acptr->port);
+                       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)
+                       return 0;
+               /* 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], me.name, "*", "*", me.name);
+               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], Class(cltmp), Links(cltmp));
+       return 0;
+    }
+/*
+** m_motd
+**     parv[0] = sender prefix
+**     parv[1] = servername
+** Modified for T:Lines by Stskeeps
+*/
+int    m_motd(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       int     fd, nr;
+       char    line[80];
+       Reg1    char     *tmp;
+       struct  stat    sb;
+       struct  tm      *tm;
+       aConfItem *motdconf;
+       int     svsnofile = 0;
+       if (check_registered(sptr))
+               return 0;
+
+       if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1,parc,parv)!=HUNTED_ISME)
+               return 0;
+       /*
+        * stop NFS hangs...most systems should be able to open a file in
+        * 3 seconds. -avalon (curtesy of wumpus)
+        */
+/* 
+ Remote. - Should this be replaced by a
+ find_conf_host(conf, "Remote", CONF_TLINE) ?
+  -Sts
+*/
+       if (!MyConnect(sptr)) 
+#ifndef TLINE_Remote
+               fd = open(MOTD, O_RDONLY);
+#else
+               {
+                       motdconf = find_tline("Remote");
+                       if (motdconf == NULL) /* no match found*/
+                               fd = open(MOTD, O_RDONLY);
+                       else  {
+                               fd = open(motdconf->passwd, O_RDONLY);
+                               if (fd == -1)
+                               {
+                                       /* Actually there is a T:Line but not a MOTD.. */
+                                       /* I choose to use default MOTD instead */
+#ifndef TLINE_REPORT_MISSING
+                                       fd = open(MOTD, O_RDONLY);
+#endif
+                               }       
+                       }
+               }
+#endif
+       else {
+               motdconf = (aConfItem *) find_tline((char *)sptr->user->realhost);
+               if (motdconf == NULL) /* no match found*/
+                       fd = open(MOTD, O_RDONLY);
+               else {
+                       fd = open((char *)motdconf->passwd, O_RDONLY);
+                       if (fd == -1)
+                       {
+                               /* Actually there is a T:Line but not a MOTD.. */
+                               /* I choose to use default MOTD instead */
+#ifndef TLINE_REPORT_MISSING
+                               fd = open(MOTD, O_RDONLY);
+#endif
+                       }
+               }
+       }
+       if (fd == -1)
+           {
+               sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv[0]);
+               svsnofile = 1;
+               goto svsmotd;
+           }
+       (void)fstat(fd, &sb);
+       sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+       tm = localtime(&sb.st_mtime);
+       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);
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
+           {
+               line[nr]='\0';
+               if ((tmp = (char *)index(line,'\n')))
+                       *tmp = '\0';
+               if ((tmp = (char *)index(line,'\r')))
+                       *tmp = '\0';
+               sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
+           }
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       (void)close(fd);
+svsmotd:
+       /* SVSMOTD */
+       if ((fd = open(VPATH, O_RDONLY)) == -1) {
+       }
+        else
+       {
+               (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+               while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
+           {
+               line[nr]='\0';
+                       if ((tmp = (char *)index(line,'\n')))
+                               *tmp = '\0';
+                       if ((tmp = (char *)index(line,'\r')))
+                               *tmp = '\0';
+                       sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
+           }
+               (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+               (void)close(fd);
+               
+       }
+       if (svsnofile==0)
+               sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+
+       return 0;
+    }
+/*
+** m_opermotd
+**     parv[0] = sender prefix
+**     parv[1] = servername
+*/
+int    m_opermotd(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       int     fd, nr;
+       char    line[80];
+       Reg1    char     *tmp;
+       struct  stat    sb;
+       struct  tm      *tm;
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (!MyConnect(sptr))
+               return 0;
+       if (!IsAnOper(sptr))
+               return 0;
+       /*
+        * stop NFS hangs...most systems should be able to open a file in
+        * 3 seconds. -avalon (curtesy of wumpus)
+        */
+       
+       fd = open(OPATH, O_RDONLY);
+       if (fd == -1)
+           {
+               sendto_one(sptr, err_str(ERR_NOOPERMOTD), me.name, parv[0]);
+               return 0;
+           }
+       (void)fstat(fd, &sb);
+       sendto_one(sptr, rpl_str(RPL_MOTDSTART), me.name, parv[0], me.name);
+       tm = localtime(&sb.st_mtime);
+       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);
+       sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], "\2IRC Operator Message of the Day\2");
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
+           {
+               line[nr]='\0';
+               if ((tmp = (char *)index(line,'\n')))
+                       *tmp = '\0';
+               if ((tmp = (char *)index(line,'\r')))
+                       *tmp = '\0';
+               sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv[0], line);
+           }
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       sendto_one(sptr, rpl_str(RPL_ENDOFMOTD), me.name, parv[0]);
+       (void)close(fd);
+       return 0;
+    }
+
+/*
+** m_botmotd
+**  same as motd but is for bot specific rules, reads from bot.motd
+**  cloned from the origional m_motd in dream forge -- codemastr
+**     parv[0] = sender prefix
+**     parv[1] = servername
+*/
+int    m_botmotd(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       int     fd, nr;
+       char    line[80];
+       Reg1    char     *tmp;
+       struct  stat    sb;
+       struct  tm      *tm;
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (hunt_server(cptr, sptr, ":%s BOTMOTD :%s", 1,parc,parv)!=HUNTED_ISME)
+               return 0;
+       /*
+        * stop NFS hangs...most systems should be able to open a file in
+        * 3 seconds. -avalon (curtesy of wumpus)
+        */
+       fd = open("bot.motd", O_RDONLY);
+       if (fd == -1)
+           {
+               sendto_one(sptr, ":%s NOTICE AUTH :BOTMOTD File not found", me.name);
+               return 0;
+           }
+       (void)fstat(fd, &sb);
+       sendto_one(sptr, ":%s NOTICE AUTH :- %s Bot Message of the Day - ", me.name, me.name);
+               tm = localtime(&sb.st_mtime);
+       sendto_one(sptr, ":%s NOTICE AUTH :- %d/%d/%d %d:%02d", me.name, tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+                  tm->tm_hour, tm->tm_min);
+          
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
+           {
+               line[nr]='\0';
+               if ((tmp = (char *)index(line,'\n')))
+                       *tmp = '\0';
+               if ((tmp = (char *)index(line,'\r')))
+                       *tmp = '\0';
+               sendto_one(sptr, ":%s NOTICE AUTH :- %s", me.name, line);
+                  }
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       sendto_one(sptr, ":%s NOTICE AUTH :End of /BOTMOTD command.", me.name);
+       (void)close(fd);
+       return 0;
+    }
+
+
+/*
+** m_rules
+**     parv[0] = sender prefix
+**     parv[1] = servername
+** Modified for T:Lines by Codemastr (cloned from m_motd)
+** Included in unrealircd by stskeeps
+*/
+int    m_rules(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       int     fd, nr;
+       char    line[80];
+       Reg1    char     *tmp;
+       struct  stat    sb;
+       struct  tm      *tm;
+       aConfItem *rulesconf;
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (hunt_server(cptr, sptr, ":%s RULES :%s", 1,parc,parv)!=HUNTED_ISME)
+               return 0;
+       /*
+        * stop NFS hangs...most systems should be able to open a file in
+        * 3 seconds. -avalon (curtesy of wumpus)
+        */
+/* 
+ Remote. - Should this be replaced by a
+ find_conf_host(conf, "Remote", CONF_TLINE) ?
+  -Sts
+*/
+       if (!MyConnect(sptr)) 
+#ifndef TLINE_Remote
+               fd = open(RPATH, O_RDONLY);
+#else
+               {
+                       rulesconf = (aConfItem *) find_tline("Remote");
+                       if (rulesconf == NULL) /* no match found*/
+                               fd = open(RPATH, O_RDONLY);
+                       else {
+                               fd = open(rulesconf->name, O_RDONLY);
+                               if (fd == -1)
+                               {
+                                       /* Actually there is a T:Line but not a MOTD.. */
+                                       /* I choose to use default MOTD instead */
+#ifndef TLINE_REPORT_MISSING
+                                       fd = open(RPATH, O_RDONLY);
+#endif
+                               }       
+                       }
+               }
+#endif
+       else {
+               rulesconf = (aConfItem *) find_tline(sptr->user->realhost);
+               if (rulesconf == NULL) /* no match found*/
+                       fd = open(RPATH, O_RDONLY);
+               else {
+                       fd = open((char *)rulesconf->name, O_RDONLY);
+                       if (fd == -1)
+                       {
+                               /* Actually there is a T:Line but not a MOTD.. */
+                               /* I choose to use default MOTD instead */
+#ifndef TLINE_REPORT_MISSING
+                               fd = open(RPATH, O_RDONLY);
+#endif
+                       }
+               }
+       }
+       if (fd == -1)
+           {
+               sendto_one(sptr, err_str(ERR_NORULES), me.name, parv[0]);
+               return 0;
+           }
+       (void)fstat(fd, &sb);
+       sendto_one(sptr, rpl_str(RPL_RULESSTART), me.name, parv[0], me.name);
+       tm = localtime(&sb.st_mtime);
+       sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", me.name, RPL_RULES,
+                  parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
+                  tm->tm_hour, tm->tm_min);
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
+           {
+               line[nr]='\0';
+               if ((tmp = (char *)index(line,'\n')))
+                       *tmp = '\0';
+               if ((tmp = (char *)index(line,'\r')))
+                       *tmp = '\0';
+               sendto_one(sptr, rpl_str(RPL_RULES), me.name, parv[0], line);
+           }
+       (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+       (void)close(fd);
+       /* SVSMOTD */
+#ifndef SVSRULES
+       if ((fd = open(VPATH, O_RDONLY)) == -1) {
+       }
+        else
+       {
+               (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+               while ((nr=dgets(fd, line, sizeof(line)-1)) > 0)
+           {
+               line[nr]='\0';
+                       if ((tmp = (char *)index(line,'\n')))
+                               *tmp = '\0';
+                       if ((tmp = (char *)index(line,'\r')))
+                               *tmp = '\0';
+                       sendto_one(sptr, rpl_str(RPL_RULES), me.name, parv[0], line);
+           }
+               (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
+               (void)close(fd);
+               
+       }
+#endif
+       sendto_one(sptr, rpl_str(RPL_ENDOFRULES), me.name, parv[0]);
+
+       return 0;
+    }
+
+/*
+** m_close - added by Darren Reed Jul 13 1992.
+*/
+int    m_close(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    aClient *acptr;
+       Reg2    int     i;
+       int     closed = 0;
+
+       if (check_registered(sptr))
+          return 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 = local[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, TRUE), acptr->status);
+               (void)exit_client(acptr, acptr, acptr, "Oper Closing");
+               closed++;
+           }
+       sendto_one(sptr, rpl_str(RPL_CLOSEEND), me.name, parv[0], closed);
+       sendto_ops("%s!%s@%s closed %d unknown connections", sptr->name, sptr->user->username, sptr->user->realhost, closed);
+
+       return 0;
+}
+
+/* m_die, this terminates the server, and it intentionally does not
+ * have a reason. If you use it you should first do a GLOBOPS and 
+ * then a server notice to let everyone know what is going down...
+ */
+int    m_die(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    aClient *acptr;
+       Reg2    int     i;
+       char *pass = NULL;
+
+        if (check_registered(sptr))
+                 return 0; 
+          
+       if (!MyClient(sptr) || !OPCanDie(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }       
+       
+       if ((pass = find_diepass()))    /* See if we have and DIE/RESTART password */
+           {   
+               if (parc < 2)           /* And if so, require a password :) */
+                   {
+                       sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS), me.name, parv[0], "DIE");
+                       return 0;
+                   }
+           
+           if (strcmp(pass, parv[1])) 
+               {
+                   sendto_one(sptr, err_str(ERR_PASSWDMISMATCH), me.name, parv[0]);
+                   return 0;
+               }    
+           }
+       
+       /* Let the +s know what is going on */
+       sendto_ops("Server Terminating by request of %s", parv[0]);
+       
+       for (i = 0; i <= highest_fd; i++)
+           {
+               if (!(acptr = local[i]))
+                       continue;
+               if (IsClient(acptr))
+                       sendto_one(acptr,
+                                  ":%s NOTICE %s :Server Terminating. %s",
+                                  me.name, acptr->name,
+                                  get_client_name(sptr, TRUE));
+               else if (IsServer(acptr))
+                       sendto_one(acptr, ":%s ERROR :Terminated by %s",
+                                  me.name, get_client_name(sptr, TRUE));
+           }
+       (void)s_die();
+       return 0;
+}
+
+char servername[128][128];
+int  server_usercount[128];
+int  numservers=0;
+
+/*
+ * New /MAP format -Potvin
+ * dump_map function.
+ */
+void dump_map(cptr, server, mask, prompt_length, length)
+aClient *cptr, *server;
+char *mask;
+register int prompt_length;
+int length;
+{
+        static char prompt[64];
+        register char *p = &prompt[prompt_length];
+        register int cnt = 0, local = 0;
+        aClient *acptr;
+
+        *p='\0';
+
+        if (prompt_length > 60)
+                sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name, prompt, server->name);
+        else
+            {
+                for (acptr = client; acptr; acptr = acptr->next)
+                {
+                    if (IsPerson(acptr))
+                    {
+                                ++cnt;                       /* == */
+                                if (!strcmp(acptr->user->server, server->name)) ++local;
+                    }
+                }
+
+                sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name, prompt, length, server->name, local, (local*100)/cnt );
+                cnt = 0;
+            }
+
+        if (prompt_length > 0)
+        {
+                p[-1] = ' ';
+                if (p[-2] == '`') p[-2] = ' ';
+        }
+        if (prompt_length > 60) return;
+
+        strcpy(p, "|-");
+
+
+        for (acptr = client; acptr ; acptr = acptr->next)
+        {
+#ifdef HIDE_ULINES
+                               if (IsServer(acptr) && IsULine(acptr, acptr) && !IsAnOper(cptr))
+                                       continue; 
+#endif
+                if ( !IsServer (acptr) || strcmp(acptr->serv->up, server->name)) continue;
+
+                if ( match(mask, acptr->name) )
+                        acptr->flags &= ~FLAGS_MAP;
+                else
+                {
+                        acptr->flags |= FLAGS_MAP;
+                        cnt++;
+                }
+        }
+
+        for (acptr = client; acptr ; acptr = acptr->next)
+        {
+                if ( ! (acptr->flags & FLAGS_MAP) ||          /* != */
+                     !IsServer (acptr) || strcmp(acptr->serv->up, server->name)) continue;
+                if (--cnt == 0) *p = '`';
+                dump_map (cptr, acptr, mask, prompt_length+2, length-2);
+        }
+
+        if (prompt_length > 0) p[-1] = '-';
+}
+
+/*
+** New /MAP format. -Potvin
+** m_map (NEW)
+**
+**      parv[0] = sender prefix
+**      parv[1] = server mask
+**/
+int m_map(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+aClient *acptr;
+int     longest=strlen(me.name);
+
+        if (check_registered(sptr))
+                 return 0;
+
+        if (parc < 2) 
+               parv[1]="*";
+        for (acptr = client; acptr; acptr = acptr->next)
+            if (IsServer(acptr) && ( strlen(acptr->name) + acptr->hopcount*2 ) > longest) longest = strlen(acptr->name) + acptr->hopcount*2;
+
+        if (longest > 60) longest = 60;
+        longest += 2;
+        dump_map(sptr, &me, "*", 0, longest);
+        sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]);
+
+        return 0;
+}
+
+
+#ifdef _WIN32
+/*
+ * Added to let the local console shutdown the server without just
+ * calling exit(-1), in Windows mode.  -Cabal95
+ */
+int    localdie(void)
+{
+       Reg1    aClient *acptr;
+       Reg2    int     i;
+
+       for (i = 0; i <= highest_fd; i++)
+           {
+               if (!(acptr = local[i]))
+                       continue;
+               if (IsClient(acptr))
+                       sendto_one(acptr,
+                ":%s NOTICE %s :Server Terminated by local console",
+                me.name, acptr->name);
+               else if (IsServer(acptr))
+                       sendto_one(acptr, ":%s ERROR :Terminated by local console",
+                me.name);
+           }
+       (void)s_die();
+       return 0;
+}
+#endif
diff --git a/src/s_socks.c b/src/s_socks.c
new file mode 100644 (file)
index 0000000..9446c25
--- /dev/null
@@ -0,0 +1,296 @@
+/*   UltimateIRCd - Ultimate Internet Relay Chat Daemon, src/s_socks.c
+**
+**   Written for UltimateIRCd by ShadowRealm Creations.
+**   Copyright (C) 1997-1999 Infomedia Inc.
+**
+**   This program is free software; you can redistribute it and/or modify
+**   it under the terms of the GNU General Public License as published by
+**   the Free Software Foundation; either version 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.
+*/
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_socks.c 1.0 28/9/98 (C) 1998 InfoMedia Inc.";
+#endif
+
+
+/* All these includes are copied from auth.c because we are
+   just doing something very similar */
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "version.h"
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#ifdef UNIXPORT
+# include <sys/un.h>
+#endif
+#if defined(__hpux)
+# include "inet.h"
+#endif
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "sock.h"      /* If FD_ZERO isn't define up to this point,  */
+                       /* define it (BSD4.2 needs this) */
+#include "h.h"
+#ifdef SOCKSPORT
+
+static unsigned char socksid[12];
+
+#define HICHAR(s)      (((unsigned short) s) >> 8)
+#define LOCHAR(s)      (((unsigned short) s) & 0xFF)
+
+
+/* init_socks
+ * Set up socksid, simply.
+ */
+
+void init_socks(aClient *cptr)
+{
+       unsigned short sport = SOCKSPORT;
+       struct sockaddr_in sin;
+
+       socksid[0] = 4;
+       socksid[1] = 1;
+       socksid[2] = HICHAR(sport);
+       socksid[3] = LOCHAR(sport);
+       socksid[8] = 0;
+
+       if ((cptr->socksfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+               return;
+
+       set_non_blocking(cptr->socksfd, cptr);
+
+       sin.sin_addr.s_addr = INADDR_ANY;
+       sin.sin_port = htons(sport);
+       sin.sin_family = AF_INET;
+
+       if(bind(cptr->socksfd, (struct sockaddr *)&sin, sizeof(sin)))
+       {
+#ifdef _WIN32
+               closesocket(cptr->socksfd);
+#else
+               close(cptr->socksfd);
+#endif
+               cptr->socksfd = -1;
+               return;
+       }
+
+       listen(cptr->socksfd, LISTEN_SIZE);
+
+       /* Socks lietening port is now set up */
+       /* Similar to discard port */ 
+}
+
+/*
+ * start_socks
+ *
+ * attempts to connect to a socks server on port 1080 of the host.
+ * if the connect fails, the user passes the socks check
+ * otherwise, the connection is checked to see if it is a "secure"
+ * socks4+ server
+ */
+void   start_socks(cptr)
+aClient        *cptr;
+{
+       struct sockaddr_in sin;
+       int sinlen = sizeof(struct sockaddr_in);
+
+       if ((cptr->socksfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+       {
+                Debug((DEBUG_ERROR, "Unable to create socks socket for %s:%s",
+                        get_client_name(cptr, TRUE),
+                        strerror(get_sockerr(cptr))));
+               return;
+       }
+#ifndef _WIN32 /* this is here in s_auth.c, so I guess it breaks win */
+       if (cptr->socksfd >= (MAXCONNECTIONS - 3))
+           {
+               sendto_ops("Can't allocate fd for socks on %s",
+                          get_client_name(cptr, TRUE));
+               close(cptr->socksfd);
+               cptr->socksfd = -1;
+               return;
+          }
+#endif
+       if (find_socksexcept((char *)inetntoa((char *) &cptr->ip)))
+               goto skip_socks;
+       
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+       write(cptr->fd, REPORT_DO_SOCKS, R_do_socks);
+#else
+       send(cptr->fd, REPORT_DO_SOCKS, R_do_socks,0);
+#endif
+#endif
+
+       set_non_blocking(cptr->socksfd, cptr);
+
+       sin.sin_port = htons(1080);
+       sin.sin_family = AF_INET;
+       bcopy((char *)&cptr->ip, (char *)&sin.sin_addr,
+               sizeof(struct in_addr));
+
+       if (connect(cptr->socksfd, (struct sockaddr *)&sin,
+#ifndef _WIN32
+                   sinlen) == -1 && errno != EINPROGRESS)
+#else
+                   sinlen) == -1 && (WSAGetLastError() !=
+               WSAEINPROGRESS && WSAGetLastError() != WSAEWOULDBLOCK))
+#endif
+       {
+               /* we have no socks server! */
+#ifndef _WIN32
+               close(cptr->socksfd);
+#else
+               closesocket(cptr->socksfd);
+#endif
+               cptr->socksfd = -1;
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+               write(cptr->fd, REPORT_NO_SOCKS, R_no_socks);
+#else
+               send(cptr->fd, REPORT_NO_SOCKS, R_no_socks,0);
+#endif
+#endif
+               return;
+           }
+       cptr->flags |= (FLAGS_WRSOCKS|FLAGS_SOCKS);
+       if (cptr->socksfd > highest_fd)
+               highest_fd = cptr->socksfd;
+       return;
+
+skip_socks:
+#ifndef _WIN32
+       close(cptr->socksfd);
+#else
+       closesocket(cptr->socksfd);
+#endif
+       cptr->socksfd = -1;
+       cptr->socksfd = -1;
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+       write(cptr->fd, REPORT_NO_SOCKS, R_no_socks);
+#else
+       send(cptr->fd, REPORT_NO_SOCKS, R_no_socks,0);
+#endif
+#endif
+       return;
+}
+
+/*
+ * send_socksquery
+ *
+ * send the socks server a query to see if it's open.
+ */
+void   send_socksquery(cptr)
+aClient        *cptr;
+{
+       struct sockaddr_in sin;
+       int sinlen = sizeof(struct sockaddr_in);
+       unsigned char socksbuf[12];
+       unsigned long theip;
+
+       bcopy((char *)&socksid, (char *)&socksbuf, 9);
+
+       getsockname(cptr->fd, (struct sockaddr *)&sin, &sinlen);
+
+       theip = htonl(sin.sin_addr.s_addr);
+       
+       socksbuf[4] = (theip >> 24);
+       socksbuf[5] = (theip >> 16) & 0xFF;
+       socksbuf[6] = (theip >> 8) & 0xFF;
+       socksbuf[7] = theip & 0xFF;
+
+       if (send(cptr->socksfd, socksbuf, 9, 0) != 9)
+       {
+#ifndef _WIN32
+               close(cptr->socksfd);
+#else
+               closesocket(cptr->socksfd);
+#endif
+               if (cptr->socksfd == highest_fd)
+                       while (!local[highest_fd])
+                               highest_fd--;
+               cptr->socksfd = -1;
+               cptr->flags &= ~FLAGS_SOCKS;
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+               write(cptr->fd, REPORT_NO_SOCKS, R_no_socks);
+#else
+               send(cptr->fd, REPORT_NO_SOCKS, R_no_socks,0);
+#endif
+#endif
+       }
+       cptr->flags &= ~FLAGS_WRSOCKS;
+       return;
+}
+
+/*
+ * read_socks
+ *
+ * process the socks reply.
+ */
+
+void   read_socks(cptr)
+aClient        *cptr;
+{
+       unsigned char socksbuf[12];
+       int len;
+
+       len = recv(cptr->socksfd, socksbuf, 9, 0);
+
+#ifndef _WIN32
+       (void)close(cptr->socksfd);
+#else
+       (void)closesocket(cptr->socksfd);
+#endif
+       if (cptr->socksfd == highest_fd)
+               while (!local[highest_fd])
+                       highest_fd--;
+       cptr->socksfd = -1;
+       ClearSocks(cptr);
+
+       if(len < 4)
+       {
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+               write(cptr->fd, REPORT_NO_SOCKS, R_no_socks);
+#else
+               send(cptr->fd, REPORT_NO_SOCKS, R_no_socks,0);
+#endif
+#endif
+               return;
+       }
+
+       if(socksbuf[1] == 90)
+       {
+               cptr->flags |= FLAGS_GOTSOCKS;
+               return;
+       }
+
+#ifdef SHOWCONNECTINFO
+#ifndef _WIN32
+       write(cptr->fd, REPORT_GOOD_SOCKS, R_good_socks);
+#else
+       send(cptr->fd, REPORT_GOOD_SOCKS, R_good_socks,0);
+#endif
+#endif
+       return;
+}
+#endif
\ No newline at end of file
diff --git a/src/s_unreal.c b/src/s_unreal.c
new file mode 100644 (file)
index 0000000..5674c17
--- /dev/null
@@ -0,0 +1,1210 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, s_unreal.c
+ *   (C) 1999 Carsten Munk (Techie/Stskeeps) <cmunk@toybox.flirt.org>
+ *
+ *   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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include "version.h"
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <utmp.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "h.h"
+
+ID_CVS("$Id$");
+ID_Copyright("(C) Carsten Munk 1999");
+
+time_t TSoffset = 0;
+
+#ifndef NO_FDLIST
+extern float currentrate;
+extern float currentrate2;
+extern float highest_rate;
+extern float highest_rate2;
+extern int   lifesux;
+#endif
+/*
+   m_sethost() added by Stskeeps (30/04/1999)
+               (modified at 15/05/1999) by Stskeeps | Potvin
+   :prefix SETHOST newhost
+   parv[0] - sender
+   parv[1] - newhost
+   D: this performs a mode +x function to set hostname
+      to whatever you want to (if you are IRCop) **efg**
+      Very experimental currently
+   A: Remember to see server_etabl ;)))))
+      *evil fucking grin*
+*/
+int     m_sethost(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       char    *vhost, *s;
+       int     permit = 0; // 0 = opers(glob/locop) 1 = global oper 2 = not MY clients.. 
+       int     donotice = 0; /* send out notices if local connect ( 0 = NOT 1 = yes ) */
+       int     legalhost = 1; /* is legal characters? */
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (!MyConnect(sptr))
+               goto have_permit1;
+       switch (permit) {
+               case 0: if (!IsAnOper(sptr)) {
+                                       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                                       return 0;
+                       }
+                       break;
+               case 1: if (!IsOper(sptr)) {
+                               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                               return 0;
+                       }
+                       break;
+               case 2: if (MyConnect(sptr)) {
+                               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                               return 0;
+                       }
+               default:
+                       sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
+                              ":%s WALLOPS :[SETHOST] Somebody fixing this corrupted server? !(0|1) !!!", me.name); 
+                               break;                                                          
+       }
+
+       have_permit1:   
+       if (parc < 2)
+               vhost = NULL;
+       else
+               vhost = parv[1];
+
+       /* bad bad bad boys .. ;p */    
+       if (vhost == NULL) {
+               if (MyConnect(sptr)) {
+                       sendto_one(sptr, ":%s NOTICE %s :*** Syntax: /SetHost <new host>", me.name, parv[0]);           
+               }
+               return;
+       }
+       /* uh uh .. too small */
+       if (strlen(parv[1]) < 1) {
+               if (MyConnect(sptr))
+                       sendto_one(sptr, ":%s NOTICE %s :*** /SetHost Error: Atleast write SOMETHING that makes sense (':' string)",
+                               me.name, sptr->name);
+       }
+       /* too large huh? */
+       if (strlen(parv[1]) > (HOSTLEN - 1) ) {
+               /* ignore us as well if we're not a child of 3k */
+               if (MyConnect(sptr))
+                       sendto_one(sptr, ":%s NOTICE %s :*** /SetHost Error: Hostnames are limited to %i characters.", me.name, sptr->name, HOSTLEN);
+               return;
+       }
+       
+       /* illegal?! */
+       for (s = vhost; *s; s++) {
+               if (!isallowed(*s)) {
+                       legalhost = 0;
+               }
+       }
+       
+       if (legalhost == 0) {
+               sendto_one(sptr, ":%s NOTICE %s :*** /SetHost Error: A hostname may contain a-z, A-Z, 0-9, '-' & '.' - Please only use them", me.name, parv[0]);
+               return 0;
+       }
+
+    /* hide it */
+    sptr->umodes |= UMODE_HIDE;
+    sptr->umodes |= UMODE_SETHOST;
+    /* get it in */
+    sprintf(sptr->user->virthost, "%s", vhost);
+    /* spread it out */
+    sendto_serv_butone(cptr, ":%s SETHOST %s", sptr->name, parv[1]);
+    
+    if (MyConnect(sptr)) {
+       sendto_one(sptr, ":%s MODE %s :+xt", sptr->name, sptr->name);
+       sendto_one(sptr, ":%s NOTICE %s :Your nick!user@host-mask is now (%s!%s@%s) - To disable it type /mode %s -x", me.name, parv[0], 
+                                       parv[0], sptr->user->username, vhost, parv[0]);
+    }
+       return 0;
+}
+
+/* 
+ * m_chghost - 12/07/1999 (two months after I made SETIDENT) - Stskeeps
+ * :prefix CHGHOST <nick> <new hostname>
+ * parv[0] - sender
+ * parv[1] - nickname
+ * parv[2] - hostname
+ *
+*/
+
+int     m_chghost(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       aClient *acptr;
+       char    *s;
+       int             legalhost = 1;
+
+    if (check_registered(sptr))
+         return 0;
+
+         
+       if (MyClient(sptr))
+               if (!IsAnOper(sptr))
+               {
+                               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                       return 0;
+
+               }
+
+       if (parc < 3) {
+               sendto_one(sptr, ":%s NOTICE %s :*** /ChgHost syntax is /ChgHost <nick> <newhost>", me.name, sptr->name);
+               return 0;
+       }
+       
+       if (strlen(parv[2]) < 1) {
+               sendto_one(sptr, ":%s NOTICE %s :*** Write atleast something to change the host to!", me.name, sptr->name);
+               return 0;
+       }
+       
+       if (strlen(parv[2]) > (HOSTLEN - 1)) {
+               sendto_one(sptr, ":%s NOTICE %s :*** ChgHost Error: Too long hostname!!", me.name, sptr->name);
+       }
+
+       /* illegal?! */
+       for (s = parv[2]; *s; s++) {
+               if (!isallowed(*s)) {
+                       legalhost = 0;
+               }
+       }
+       
+       if (legalhost == 0) {
+               sendto_one(sptr, ":%s NOTICE %s :*** /ChgHost Error: A hostname may contain a-z, A-Z, 0-9, '-' & '.' - Please only use them", me.name, parv[0]);
+               return 0;
+       }
+
+       if ((acptr = find_person(parv[1], NULL))) {
+               if (!IsULine(cptr, sptr)) {
+                       sendto_umode(UMODE_EYES, "%s changed the virtual hostname of %s (%s@%s) to be %s",
+                                               sptr->name, acptr->name, acptr->user->username,
+                                               (acptr->umodes & UMODE_HIDE ? acptr->user->virthost : acptr->user->realhost),
+                                               parv[2]);
+               }
+               acptr->umodes |= UMODE_HIDE;                            
+               acptr->umodes |= UMODE_SETHOST;
+               sendto_serv_butone(cptr, ":%s CHGHOST %s %s",
+                                       sptr->name,
+                                       acptr->name,
+                                       parv[2]);
+               sprintf(acptr->user->virthost, "%s", parv[2]);
+               return 0;
+       }
+        else
+       {
+               sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, parv[1]);
+               return 0;
+       }
+       return 0;
+}
+
+/* 
+ * m_chgident - 12/07/1999 (two months after I made SETIDENT) - Stskeeps
+ * :prefix CHGHOST <nick> <new identname>
+ * parv[0] - sender
+ * parv[1] - nickname
+ * parv[2] - identname
+ *
+*/
+
+int     m_chgident(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       aClient *acptr;
+       char    *s;
+       int             legalident = 1;
+
+    if (check_registered(sptr))
+         return 0;
+
+         
+       if (MyClient(sptr))
+               if (!IsAnOper(sptr))
+               {
+                               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                       return 0;
+
+               }
+
+       if (parc < 3) {
+               sendto_one(sptr, ":%s NOTICE %s :*** /ChgIdent syntax is /ChgIdent <nick> <newident>", me.name, sptr->name);
+               return 0;
+       }
+       
+       if (strlen(parv[2]) < 1) {
+               sendto_one(sptr, ":%s NOTICE %s :*** Write atleast something to change the ident to!", me.name, sptr->name);
+               return 0;
+       }
+       
+       if (strlen(parv[2]) > (HOSTLEN - 1)) {
+               sendto_one(sptr, ":%s NOTICE %s :*** ChgIdent Error: Too long ident!!", me.name, sptr->name);
+       }
+
+       /* illegal?! */
+       for (s = parv[2]; *s; s++) {
+               if (!isallowed(*s)) {
+                       legalident = 0;
+               }
+       }
+       
+       if (legalident == 0) {
+               sendto_one(sptr, ":%s NOTICE %s :*** /ChgIdent Error: A ident may contain a-z, A-Z, 0-9, '-' & '.' - Please only use them", me.name, parv[0]);
+               return 0;
+       }
+
+       if ((acptr = find_person(parv[1], NULL))) {
+               if (!IsULine(cptr, sptr)) {
+                       sendto_umode(UMODE_EYES, "%s changed the virtual ident of %s (%s@%s) to be %s",
+                                               sptr->name, acptr->name, acptr->user->username,
+                                               (acptr->umodes & UMODE_HIDE ? acptr->user->realhost : acptr->user->realhost),
+                                               parv[2]);
+               }
+               sendto_serv_butone(cptr, ":%s CHGIDENT %s %s",
+                                       sptr->name,
+                                       acptr->name,
+                                       parv[2]);
+               sprintf(acptr->user->username, "%s", parv[2]);
+               return 0;
+       }
+        else
+       {
+               sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, sptr->name, parv[1]);
+               return 0;
+       }
+       return 0;
+}
+
+/* m_setident - 12/05/1999 - Stskeeps
+ *  :prefix SETIDENT newident
+ *  parv[0] - sender
+ *  parv[1] - newident
+ *  D: This will set your username to be <x> (like (/setident Root))
+ *     (if you are IRCop) **efg*
+ *     Very experimental currently
+ *        Cloning of m_sethost at some points - so same authors ;P
+*/
+
+int     m_setident(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+
+       char    *vident, *s;
+       int             permit = 0; /* 0 = opers(glob/locop) 1 = global oper */
+       int             donotice = 0; /* send out notices if local connect ( 0 = NOT 1 = yes )*/
+       int             legalident = 1; /* is legal characters? */
+    if (check_registered(sptr))
+         return 0;
+       if (!MyConnect(sptr))
+               goto permit_2;
+       switch (permit) {
+               case 0: if (!IsAnOper(sptr)) {
+                                       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                                       return 0;
+                               }
+                               break;
+               case 1: if (!IsOper(sptr)) {
+                                       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                                       return 0;
+                               }
+                               break;
+               case 2: if (MyConnect(sptr)) {
+                                       sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                                       return 0;                                       
+                               }
+                               break;
+               default:
+                               sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr,
+                                      ":%s WALLOPS :[SETIDENT] Somebody fixing this corrupted server? !(0|1) !!!", me.name); 
+                               break;                                                          
+       }
+       permit_2:       
+       if (parc < 2)
+               vident = NULL;
+       else
+               vident = parv[1];
+
+       /* bad bad bad boys .. ;p */    
+       if (vident == NULL) {
+               if (MyConnect(sptr)) {
+                       sendto_one(sptr, ":%s NOTICE %s :*** Syntax: /SetIdent <new host>", me.name, parv[0]);          
+               }
+               return;
+       }
+       if (strlen(parv[1]) < 1) {
+               if (MyConnect(sptr))
+                       sendto_one(sptr, ":%s NOTICE %s :*** /SetIdent Error: Atleast write SOMETHING that makes sense (':' string)",
+                               me.name, sptr->name);
+       }
+
+       /* too large huh? */
+       if (strlen(vident) > ( USERLEN - 1)) {
+               /* ignore us as well if we're not a child of 3k */
+               if (MyConnect(sptr))
+                       sendto_one(sptr, ":%s NOTICE %s :*** /SetIdent Error: Usernames are limited to %i characters.", me.name, sptr->name, USERLEN);
+               return;
+       }
+       
+       /* illegal?! */
+       for (s = vident; *s; s++) {
+               if (!isallowed(*s)) {
+                       legalident = 0;
+               }
+               if (*s == '~')
+                       legalident = 1; 
+
+       }
+       
+       if (legalident == 0) {
+               sendto_one(sptr, ":%s NOTICE %s :*** /SetIdent Error: A username may contain a-z, A-Z, 0-9, '-', '~' & '.' - Please only use them", me.name, parv[0]);
+               return 0;
+       }
+   
+    /* get it in */
+    sprintf(sptr->user->username, "%s", vident);
+    /* spread it out */
+    sendto_serv_butone(cptr, ":%s SETIDENT %s", sptr->name, parv[1]);
+    
+    if (MyConnect(sptr)) {
+       sendto_one(sptr, ":%s NOTICE %s :Your nick!user@host-mask is now (%s!%s@%s) - To disable ident set change it manually by /setident'ing again", me.name, parv[0], 
+                                       parv[0], sptr->user->username, 
+                                       IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+       }
+    return;
+}
+/* m_setname - 12/05/1999 - Stskeeps
+ *  :prefix SETNAME :gecos
+ *  parv[0] - sender
+ *  parv[1] - gecos
+ *  D: This will set your gecos to be <x> (like (/setname :The lonely wanderer))
+   yes it is experimental but anyways ;P
+    FREEDOM TO THE USERS! ;)
+*/
+
+int     m_setname(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       if (parc < 2)
+               return;
+       if (strlen(parv[1]) > (REALLEN - 2)) {
+               if (MyConnect(sptr)) {
+                       sendto_one(sptr, ":%s NOTICE %s :*** /SetName Error: \"Real names\" may maximum be %i characters of length", me.name, sptr->name, REALLEN);
+               }
+               return 0;
+       }
+       
+       if (strlen(parv[1]) < 1) {
+               sendto_one(sptr, ":%s NOTICE %s :Couldn't change realname - Nothing in parameter",
+                       me.name, sptr->name);
+               return 0;
+       }
+               else 
+                       sprintf(sptr->info, "%s", parv[1]);
+       
+
+    sendto_serv_butone(&me, ":%s SETNAME :%s", parv[0], parv[1]);
+       if (MyConnect(sptr))
+                        sendto_one(sptr, ":%s NOTICE %s :Your \"real name\" is now set to be %s - you have to set it manually to undo it", me.name, parv[0], parv[1]);      
+          return 0;
+//     sendto_serv_butone(cptr, ":%s SETNAME %s", parv[0], parv[1]);
+       return 0;
+}
+
+/* m_sdesc - 15/05/1999 - Stskeeps
+ *  :prefix SDESC
+ *  parv[0] - sender
+ *  parv[1] - description
+ *  D: Sets server info if you are Server Admin (ONLINE)
+*/
+
+int     m_sdesc(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       if (IsCoAdmin(sptr)) 
+               goto sdescok;
+       /* ignoring */
+       if (!IsAdmin(sptr)) 
+               return;
+sdescok:
+
+       if (parc < 2)
+               return;
+       if (strlen(parv[1]) < 1) {
+               if (MyConnect(sptr)) {
+                       sendto_one(sptr, ":%s NOTICE %s :*** Nothing to change to (SDESC)", me.name, sptr->name);
+               }               
+       }
+       if (strlen(parv[1]) > (REALLEN - 1)) {
+               if (MyConnect(sptr)) {
+                       sendto_one(sptr, ":%s NOTICE %s :*** /SDESC Error: \"Server info\" may maximum be %i characters of length", me.name, sptr->name, REALLEN);
+               }
+               return 0;
+       }
+
+       sprintf(sptr->srvptr->info, "%s", parv[1]);
+       
+    sendto_serv_butone(&me, ":%s SDESC :%s", parv[0], parv[1]);
+       
+       if (MyConnect(sptr))
+        sendto_one(sptr, ":%s NOTICE %s :Your \"server description\" is now set to be %s - you have to set it manually to undo it", me.name, parv[0], parv[1]);      
+        return 0;
+
+       sendto_ops("Server description for %s is now '%s' changed by %s", sptr->srvptr->name, sptr->srvptr->info, parv[0]);
+}
+
+
+/*
+** m_admins (Admin chat only) -Potvin
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_admins(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+
+        message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "ADCHAT");
+                return 0;
+            }
+#ifdef ADMINCHAT
+        if (MyClient(sptr) && !IsAdmin(sptr))
+#else
+        if (MyClient(sptr))
+#endif
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+        sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                        ":%s ADCHAT :%s", parv[0], message);
+#ifdef ADMINCHAT
+       sendto_umode(UMODE_ADMIN, "*** AdminChat -- from %s: %s",
+                       parv[0], message);
+       sendto_umode(UMODE_COADMIN, "*** AdminChat -- from %s: %s",
+                       parv[0], message);
+#endif
+        return 0;
+    }
+/*
+** m_techat (Techadmin chat only) -Potvin (cloned by --sts)
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_techat(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+
+        message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "TECHAT");
+                return 0;
+            }
+#ifdef ADMINCHAT
+        if (MyClient(sptr))
+           if  (!(IsTechAdmin(sptr) || IsNetAdmin(sptr)))
+#else
+        if (MyClient(sptr))
+#endif
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+        sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                        ":%s TECHAT :%s", parv[0], message);
+#ifdef ADMINCHAT
+       sendto_umode(UMODE_TECHADMIN, "*** Te-chat -- from %s: %s",
+                       parv[0], message);
+//        sendto_techat("from %s: %s", parv[0], message);
+//             sendto_achat(1,"from %s: %s", parv[0], message);
+#endif
+        return 0;
+    }
+/*
+** m_nachat (netAdmin chat only) -Potvin - another sts cloning
+**      parv[0] = sender prefix
+**      parv[1] = message text
+*/
+int     m_nachat(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+
+         if (check_registered(sptr))
+                 return 0;
+
+        message = parc > 1 ? parv[1] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "NACHAT");
+                return 0;
+            }
+#ifdef ADMINCHAT
+        if (MyClient(sptr))
+               if (!(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+#else
+        if (MyClient(sptr))
+#endif
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+
+        sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                        ":%s NACHAT :%s", parv[0], message);
+#ifdef ADMINCHAT
+       sendto_umode(UMODE_NETADMIN, "*** NetAdmin.Chat -- from %s: %s",
+                               parv[0], message);
+       sendto_umode(UMODE_TECHADMIN, "*** NetAdmin.Chat -- from %s: %s",
+                               parv[0], message);      
+#endif
+        return 0;
+    }
+
+/* m_lag (lag measure) - Stskeeps
+ * parv[0] = prefix
+ * parv[1] = server to query
+*/
+
+int m_lag(cptr, sptr, parc, parv) 
+aClient *cptr, *sptr;
+int parc;
+char *parv[];
+{
+       int i;
+       if (check_registered_user(sptr))
+       return 0;
+    
+    if (MyClient(sptr))
+               if (!IsAnOper(sptr)) {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+               }
+       
+       if (parc < 2) {
+         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                     me.name, parv[0], "LAG");
+         return 0;
+       }
+       if (*parv[1] == '\0') {
+         sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                     me.name, parv[0], "LAG");
+         return 0;
+       }
+       if (hunt_server(cptr, sptr, ":%s LAG :%s", 1, parc, parv) == HUNTED_NOSUCH) {
+               return 0;
+       }
+       
+       sendto_one(sptr, ":%s NOTICE %s :Lag reply -- %s %s %li",
+               me.name, sptr->name,
+               me.name, parv[1],
+               TStime());
+
+       return 0;
+}
+
+/*
+ * m_dusers (dump users) (not passed on to other servers - Stskeeps
+ * /DUSERS <mask>
+ * parv[0] = prefix
+ * parv[1] = mask
+ * parv[2] = (optional) options
+*/
+#define DOPT_OPS 0x0001
+#define DOPT_BOTS 0x0002
+#define DOPT_MINE 0x0004
+
+int     m_dusers(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+       aClient *acptr;
+       long    ccount = 0;     
+       int             opt = 0; /* 1 */
+       char    *op;
+
+       if (!IsAnOper(sptr)) {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+         return 0;
+       }
+/* Will now say it is not available in what ever version it is */
+       sendto_one(sptr, ":%s NOTICE %s :*** /Dusers is disabled in %s%s - sorry", me.name, sptr->name, BASE_VERSION, VERSIONONLY);
+       return 0;
+
+       if (parc < 2) {       
+            sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                      me.name, parv[0], "DUSERS");
+         return 0;
+       }
+       
+       if (*parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                       me.name, parv[0], "DUSERS");
+            return 0;
+       }
+               
+       if (parc < 4) { /* we got options .. */
+               op = parv[2];
+               while (*op != '\0') {
+                       switch (*op) {
+                               case '+': break;
+                               case 'o': opt |= DOPT_OPS; break;
+                               case 'B': opt |= DOPT_BOTS; break;
+                               case 'l': opt |= DOPT_MINE; break;
+                               default: sendto_one(sptr, ":%s NOTICE %s :Unknown /DUSERS option flag (%c)", me.name, sptr->name, *op);
+                       }
+                       op++;
+               }               
+       }
+       sendto_one(sptr, rpl_str(RPL_DUMPING), me.name, parv[0], parv[1]);
+
+       for (acptr = client; acptr; acptr = acptr->next) {
+               if (IsClient(acptr)) {
+                       if (IsOper(acptr) && !(opt & DOPT_OPS))                 
+                               continue;
+                       if (!(acptr->umodes & UMODE_BOT) && (opt & DOPT_BOTS))
+                               continue;
+                       if (!MyConnect(acptr) && (opt & DOPT_MINE))
+                               continue;       
+                               
+                       /* Complicated. */
+                       sendto_one(sptr, rpl_str(RPL_DUMPRPL), me.name, parv[0],
+                               acptr->name, acptr->user->username, 
+                               (IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost),
+                               acptr->user->serv->name,
+                               (IsOper(acptr) ? "o" : ""),
+                               ((acptr->umodes & UMODE_BOT) ? "b" : ""),
+                               (IsServices(acptr) ? "s" : ""),
+(!(IsOper(acptr) || (acptr->umodes & UMODE_BOT) || IsServices(acptr)) ? "n" : ""));
+                       ccount++;
+               }
+       }       
+       sendto_one(sptr, rpl_str(RPL_EODUMP), me.name, parv[0], ccount);
+}
+
+/*
+  Help.c interface for command line :)
+*/
+void   unrealmanual(void) {
+       char    *str;
+       int             x = 0;  
+
+       str = MyMalloc(1024);   
+       printf("Starting UnrealIRCD Interactive help system\n");
+       printf("Use 'QUIT' as topic name to get out of help system\n");
+       x = parse_help(NULL, NULL, NULL);
+       if (x == 0) {
+               printf("*** Couldn't find main help topic!!\n");
+               return;
+       }       
+       while (myncmp(str, "QUIT", 8)) {
+               printf("Topic?> ");
+               str = fgets(str, 1023, stdin);
+               printf("\n");
+               if (myncmp(str, "QUIT", 8))             
+                 x = parse_help(NULL, NULL, str);
+             if (x == 0) {
+                        printf("*** Couldn't find help topic '%s'\n", str);
+                 }
+       }
+       MyFree(str);
+}      
+
+static char *militime(char *sec, char *usec)
+{
+  struct timeval tv;
+  static char timebuf[18];
+#ifndef _WIN32  
+  gettimeofday(&tv, NULL);
+#else
+       /* win32 unreal cannot fix gettimeofday - therefore only 90% precise */
+       tv.tv_sec = TStime();
+       tv.tv_usec = 0;
+#endif
+  if (sec && usec)
+    sprintf(timebuf, "%ld",
+       (tv.tv_sec - atoi(sec)) * 1000 + (tv.tv_usec - atoi(usec)) / 1000);
+  else
+    sprintf(timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
+
+  return timebuf;
+}
+
+aClient *find_match_server(char *mask)
+{
+  aClient *acptr;
+
+  if (BadPtr(mask))
+    return NULL;
+  for (acptr = client, collapse(mask); acptr; acptr = acptr->next)
+  {
+    if (!IsServer(acptr) && !IsMe(acptr))
+      continue;
+    if (!match(mask, acptr->name))
+      break;
+    continue;
+  }
+  return acptr;
+}
+
+/*
+ * 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 (MyClient(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(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;
+    }
+      sendto_one(acptr, ":%s RPING %s %s %s :%s",
+         me.name, acptr->name, sptr->name, militime(NULL, NULL), parv[3]);
+  }
+  else
+  {
+    if (hunt_server(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 *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;
+  }
+  /* rping blowbug */
+  if (!(acptr = find_client(parv[1], (aClient *)NULL)))
+      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 = find_person(parv[1], (aClient *)NULL)))
+      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;
+}
+/*
+ * m_swhois
+ * parv[1] = nickname
+ * parv[2] = new swhois
+ *
+*/
+
+int     m_swhois(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+       aClient *acptr;
+       
+/*     if (!IsServer(sptr) && !IsULine(cptr, sptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+       {
+               return 0;
+       }*/
+       if (!IsServer(sptr) && !IsULine(cptr, sptr))
+               return 0;
+       if (parc < 3) 
+               return 0;
+               
+       acptr = find_person(parv[1], (aClient *) NULL);
+       if (!acptr)
+               return 0;
+       
+       if (acptr->user->swhois)
+               MyFree(acptr->user->swhois);
+       acptr->user->swhois = MyMalloc(strlen(parv[2]) + 1);
+       sprintf(acptr->user->swhois, "%s", parv[2]);
+       sendto_serv_butone(cptr, ":%s SWHOIS %s :%s", sptr->name, parv[1], parv[2]);
+       return 0;       
+}
+/*
+** m_sendumode - Stskeeps
+**      parv[0] = sender prefix
+**      parv[1] = target
+**      parv[2] = message text
+** Pretty handy proc.. 
+** Servers can use this to f.x:
+**   :server.unreal.net SENDUMODE F :Client connecting at server server.unreal.net port 4141 usw..
+** or for sending msgs to locops.. :P
+*/
+int     m_sendumode(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+        char    *message, *pv[4];
+       char *p;
+         if (check_registered(sptr))
+                 return 0;
+
+        message = parc > 2 ? parv[2] : NULL;
+
+        if (BadPtr(message))
+            {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "SENDUMODE");
+                return 0;
+            }
+
+        if (!IsServer(sptr))
+            {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+            }
+
+        sendto_serv_butone(IsServer(cptr) ? cptr : NULL,
+                        ":%s SMO %s :%s", parv[0], parv[1], message);
+       
+       
+       for (p = parv[1]; *p; p++)
+       {
+               switch (*p)
+               {
+                       case 'e': sendto_umode(UMODE_EYES, "%s", parv[2]); break;
+                       case 'F':
+                               {
+                                       if (*parv[2] != 'C' && *(parv[2]+1) != 'l')
+                                                sendto_umode(UMODE_FCLIENT, "%s", parv[2]); break;
+                               }
+                       case 'o': sendto_umode(UMODE_OPER, "%s", parv[2]); break;
+                       case 'O': sendto_umode(UMODE_LOCOP, "%s", parv[2]); break;
+                       case 'h': sendto_umode(UMODE_HELPOP, "%s", parv[2]); break;
+                       case 'N': sendto_umode(UMODE_NETADMIN|UMODE_TECHADMIN, "%s", parv[2]); break;
+                       case 'A': sendto_umode(UMODE_ADMIN, "%s", parv[2]); break;
+                       case '1': sendto_umode(UMODE_CODER, "%s", parv[2]); break;
+                       case 'I': sendto_umode(UMODE_HIDING, "%s", parv[2]); break;
+                       case 'w': sendto_umode(UMODE_WALLOP, "%s", parv[2]); break;
+                       case 's': sendto_umode(UMODE_SERVNOTICE, "%s", parv[2]); break;
+                       case 'T': sendto_umode(UMODE_TECHADMIN, "%s", parv[2]); break;
+               }
+       }
+        return 0;
+    }
+
+
+/*
+** m_tsctl - Stskeeps
+**      parv[0] = sender prefix
+**      parv[1] = command
+**      parv[2] = options
+*/
+
+int     m_tsctl(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+       time_t  timediff;
+       
+       if (check_registered(sptr))
+                 return 0;
+
+       if (!MyClient(sptr)) 
+               goto doit;
+       if (!IsAdmin(sptr) && !IsCoAdmin(sptr))
+       {
+                sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+                return 0;
+       }
+       doit:
+       if (parv[1])
+       {
+               if (*parv[1] == '\0' )
+               {
+                       sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                                  me.name, parv[0], "TSCTL");
+                       return 0;
+               }
+
+               if (strcmp(parv[1], "offset")==0) {
+                       if (!parv[3])
+                       {
+                               sendto_one(sptr, ":%s NOTICE %s :*** TSCTL OFFSET: /tsctl offset <+|-> <time>", me.name, sptr->name);
+                               return 0;
+                       }
+                       if (*parv[2] == '\0' || *parv[3] == '\0')
+                       {
+                               sendto_one(sptr, ":%s NOTICE %s :*** TSCTL OFFSET: /tsctl offset <+|-> <time>", me.name, sptr->name);
+                               return 0;
+                       }                               
+                       if (!(*parv[2] == '+' || *parv[2] == '-'))
+                       {
+                               sendto_one(sptr, ":%s NOTICE %s :*** TSCTL OFFSET: /tsctl offset <+|-> <time>", me.name, sptr->name);
+                               return 0;
+
+                       }
+                       
+                       switch (*parv[2])
+                       {
+                               case '+' :
+                                               timediff = atol(parv[3]);
+                                               TSoffset = timediff;
+                                               sendto_ops("TS Control - %s set TStime() to be diffed +%li", sptr->name, timediff);                                     
+                                               sendto_serv_butone(&me, ":%s GLOBOPS :TS Control - %s set TStime to be diffed +%li", me.name, sptr->name, timediff);
+                                               break;                                          
+                               case '-' :
+                                               timediff = atol(parv[3]);
+                                               TSoffset = -timediff;
+                                               sendto_ops("TS Control - %s set TStime() to be diffed -%li", sptr->name, timediff);                                     
+                                               sendto_serv_butone(&me, ":%s GLOBOPS :TS Control - %s set TStime to be diffed -%li", me.name, sptr->name, timediff);
+                                               break;                                          
+                       }
+                       return 0;
+               }
+               if (strcmp(parv[1], "time")==0)
+               {
+                       sendto_one(sptr, ":%s NOTICE %s :*** TStime=%li time()=%li TSoffset=%li", me.name,
+                               sptr->name, TStime(), time(NULL), TSoffset);
+                       return 0;
+               }
+               if (strcmp(parv[1], "alltime")==0)
+               {
+                       sendto_one(sptr, ":%s NOTICE %s :*** Server=%s TStime=%li time()=%li TSoffset=%li", me.name,
+                               sptr->name, me.name, TStime(), time(NULL), TSoffset);
+                       sendto_serv_butone(cptr, ":%s TSCTL alltime", sptr->name);
+                       return 0;
+                       
+               }
+               if (strcmp(parv[1], "svstime")==0)
+               {
+                       if (parc < 3 || *parv[3] == '\0')
+                       {
+                               return 0;
+                       }
+                       if (!IsULine(cptr, sptr))
+                       {
+                               return 0;
+                       }
+                       
+                       timediff = atol(parv[3]);
+                       timediff = timediff - time(NULL);
+                       TSoffset = timediff;
+                       sendto_ops("TS Control - U:line set time to be %li (timediff: %li)", atol(parv[3]), timediff);
+                       sendto_serv_butone(cptr, ":%s TSCTL svstime %li", sptr->name, atol(parv[3]));
+                       return 0;
+               }               
+       }       
+}
+
+
+/*
+** m_svso - Stskeeps
+**      parv[0] = sender prefix
+**      parv[1] = nick
+**      parv[2] = options
+*/
+
+int     m_svso(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+       aClient *acptr;
+       long    fLag;
+       
+       if (check_registered(sptr))
+                 return 0;
+       if (!IsULine(cptr, sptr))
+               return 0;
+               
+       if (parc < 3)
+               return 0;
+               
+       if (!(acptr = find_client(parv[1], (aClient *)NULL)))
+           return 0;
+
+       if (!MyClient(acptr))
+       {
+               sendto_one(acptr, ":%s SVSO %s %s", parv[0], parv[1], parv[2]);
+               return 0;
+       }
+       
+       if (*parv[2] == '-') 
+       {
+               fLag = acptr->umodes;
+               acptr->umodes &= ~(UMODE_OPER|UMODE_LOCOP|UMODE_HELPOP|UMODE_SERVICES|UMODE_SADMIN|UMODE_ADMIN);
+               acptr->umodes &= ~(UMODE_NETADMIN|UMODE_TECHADMIN|UMODE_CLIENT|UMODE_FLOOD|UMODE_EYES|UMODE_CHATOP|UMODE_WHOIS);
+               acptr->umodes &= ~(UMODE_KIX|UMODE_FCLIENT|UMODE_HIDING|UMODE_AGENT|UMODE_CODER|UMODE_DEAF);            
+               acptr->oflag = 0;
+               send_umode_out(acptr, acptr, fLag);
+       }       
+}
+
+int    m_shun(cptr, sptr, parc,parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+}
+
+int    m_htm(cptr, sptr, parc,parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       if (!IsOper(sptr))
+               return 0;
+
+#ifndef NO_FDLIST              
+       sendto_one(sptr, ":%s NOTICE %s :*** Current incoming rate: %0.2f kb/s", me.name, sptr->name, currentrate);
+       sendto_one(sptr, ":%s NOTICE %s :*** Current outgoing rate: %0.2f kb/s", me.name, sptr->name, currentrate2);
+       sendto_one(sptr, ":%s NOTICE %s :*** Highest incoming rate: %0.2f kb/s", me.name, sptr->name, highest_rate);
+       sendto_one(sptr, ":%s NOTICE %s :*** Highest outgoing rate: %0.2f kb/s", me.name, sptr->name, highest_rate2);
+       sendto_one(sptr, ":%s NOTICE %s :*** High traffic mode is currently \2%s\2", me.name, sptr->name, (lifesux ? "ON" : "OFF"));
+       sendto_one(sptr, ":%s NOTICE %s :*** HTM will be activated if incoming > %i kb/s", me.name, sptr->name, LOADRECV);
+#else
+       sendto_one(sptr, ":%s NOTICE %s :*** High traffic mode and fdlists are not enabled on this server", me.name, sptr->name);
+#endif
+}
+
+
diff --git a/src/s_user.c b/src/s_user.c
new file mode 100644 (file)
index 0000000..aaa24af
--- /dev/null
@@ -0,0 +1,4789 @@
+/*
+ *   IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.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.
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)s_user.c  2.74 2/8/94 (C) 1988 University of Oulu, \
+Computing Center and Jarkko Oikarinen";
+#endif
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <utmp.h>
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "h.h"
+
+ID_CVS("$Id$");
+void   send_umode_out PROTO((aClient*, aClient *, int));
+void   send_umode_out_nickv2 PROTO((aClient*, aClient *, int));
+void   send_svsmode_out PROTO((aClient*, aClient *, aClient *, int));
+void   send_umode PROTO((aClient *, aClient *, int, int, char *));
+static is_silenced PROTO((aClient *, aClient *));
+/* static  Link    *is_banned PROTO((aClient *, aChannel *)); */
+
+int    sendanyways = 0;
+int    dontspread = 0;
+
+static char buf[BUFSIZE], buf2[BUFSIZE];
+static int user_modes[]      = { UMODE_OPER, 'o',
+                                 UMODE_LOCOP, 'O',
+                                 UMODE_INVISIBLE, 'i',
+                                 UMODE_WALLOP, 'w',
+                                 UMODE_FAILOP, 'g',
+                                 UMODE_HELPOP, 'h',
+                                 UMODE_SERVNOTICE, 's',
+                                 UMODE_KILLS, 'k',
+                                 UMODE_SERVICES, 'S',
+                                 UMODE_SADMIN, 'a',
+                                UMODE_HIDEOPER, 'H',
+                                 UMODE_ADMIN, 'A',
+                                 UMODE_NETADMIN, 'N',
+                                UMODE_TECHADMIN, 'T',
+                                 UMODE_CLIENT, 'c',
+                                UMODE_COADMIN, 'C',
+                                 UMODE_FLOOD, 'f',
+                                 UMODE_REGNICK, 'r',
+                                 UMODE_HIDE,    'x',
+                                UMODE_EYES,    'e',
+                                 UMODE_CHATOP, 'b',
+                                UMODE_WHOIS, 'W',
+                                UMODE_KIX, 'q',                
+                                UMODE_BOT, 'B',
+                                UMODE_FCLIENT, 'F',
+#ifndef OPER_NO_HIDING
+                                UMODE_HIDING,  'I',
+#endif
+                                UMODE_AGENT,   'Z',
+                                UMODE_CODER, '1',
+                                UMODE_DEAF,    'd',
+                                UMODE_VICTIM,  'v',
+                                UMODE_SETHOST, 't',
+                                 0, 0 };
+
+/* annoying but tricky function..  */
+#define iNAH_host(x, y) strncpyzt((x)->user->virthost, (y), HOSTLEN); \
+       if (MyConnect(x)) \
+             sendto_serv_butone(&me, ":%s SETHOST %s", (x)->name, (x)->user->virthost); \
+       sptr->umodes |= UMODE_SETHOST
+       
+
+/*
+** 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.
+*/
+
+#ifndef NO_FDLIST
+extern fdlist oper_fdlist;
+#endif
+
+/* Recoded to be alot more accurate
+ * not based on netgod's (net@lite.net)
+ * StripColors, but it was used as a 
+ * reference and some of his code was 
+ * used, all in all this is still a 
+ * messy function, but it should be
+ * more accurate (and faster?)
+ * -- codemastr 
+ */
+
+static char *StripColors(char *buffer)
+{
+static char tmp[512], out[512];
+register int i = 0, j = 0, hascomma = 0;
+
+/* If there isn't any color in the string, just return */
+if (!strchr(buffer, '\003'))
+return buffer;
+bzero((char *)out, sizeof(out));
+memcpy(tmp, buffer, 512);
+
+while (tmp[i])
+{
+       /* Color code found, so parse */
+       if (tmp[i] == '\003') {
+               hascomma = 0;
+
+               /* Increase it by 1 so we can see if it is valid */
+               i++;
+               /* It's fake, so continue */
+               if (!isdigit(tmp[i])) 
+                        continue;
+               
+               while(isdigit(tmp[i]) || (isdigit(tmp[i-1]) && tmp[i] == ',' && isdigit(tmp[i+1]) && hascomma == 0))
+               {
+                       if (tmp[i] == ',' && hascomma == 1)
+                               break;
+
+                       if (tmp[i] == ',' && hascomma == 0)
+                               hascomma = 1;
+                       i++;
+               }
+               continue;
+       }
+out[j] = tmp[i];
+i++;
+j++;
+       }
+return out;
+
+}
+
+char   umodestring[512];
+
+void   make_umodestr(void)
+{
+       char    *p;
+       char    *q;
+       
+        Reg1    int     flag;
+        Reg2    int     *s;
+        Reg3    char    *m;
+
+       m = umodestring;
+       
+       for (s = user_modes; *s; s += 2)
+       {
+               *m++ = (char) (*(s + 1));       
+       }
+       
+        *m = '\0';
+}
+
+/*
+** next_client
+**     Local function to find the next matching client. The search
+**     can be continued from the specified client entry. Normal
+**     usage loop is:
+**
+**     for (x = client; x = next_client(x,mask); x = x->next)
+**             HandleMatchingClient;
+**           
+*/
+aClient *next_client(next, ch)
+Reg1   aClient *next;  /* First client to check */
+Reg2   char    *ch;    /* search string (may include wilds) */
+{
+       Reg3    aClient *tmp = next;
+
+       next = find_client(ch, tmp);
+       if (tmp && tmp->prev == next)
+               return NULL;
+       if (next != tmp)
+               return next;
+       for ( ; next; next = next->next)
+           {
+               if (IsService(next))
+                       continue;
+               if (!match(ch, next->name) || !match(next->name, ch))
+                       break;
+           }
+       return next;
+}
+
+/*
+** hunt_server
+**
+**     Do the basic thing in delivering the message (command)
+**     across the relays to the specific server (server) for
+**     actions.
+**
+**     Note:   The command is a format string and *MUST* be
+**             of prefixed style (e.g. ":%s COMMAND %s ...").
+**             Command can have only max 8 parameters.
+**
+**     server  parv[server] is the parameter identifying the
+**             target server.
+**
+**     *WARNING*
+**             parv[server] is replaced with the pointer to the
+**             real servername from the matched client (I'm lazy
+**             now --msa).
+**
+**     returns: (see #defines)
+*/
+int    hunt_server(cptr, sptr, command, server, parc, parv)
+aClient        *cptr, *sptr;
+char   *command, *parv[];
+int    server, parc;
+    {
+       aClient *acptr;
+
+       /*
+       ** Assume it's me, if no server
+       */
+       if (parc <= server || BadPtr(parv[server]) ||
+           match(me.name, parv[server]) == 0 ||
+           match(parv[server], me.name) == 0)
+               return (HUNTED_ISME);
+       /*
+       ** These are to pickup matches that would cause the following
+       ** message to go in the wrong direction while doing quick fast
+       ** non-matching lookups.
+       */
+       if ((acptr = find_client(parv[server], NULL)))
+               if (acptr->from == sptr->from && !MyConnect(acptr))
+                       acptr = NULL;
+       if (!acptr && (acptr = find_server(parv[server], NULL)))
+               if (acptr->from == sptr->from && !MyConnect(acptr))
+                       acptr = NULL;
+       if (!acptr)
+               for (acptr = client, (void)collapse(parv[server]);
+                    (acptr = next_client(acptr, parv[server]));
+                    acptr = acptr->next)
+                   {
+                       if (acptr->from == sptr->from && !MyConnect(acptr))
+                               continue;
+                       /*
+                        * Fix to prevent looping in case the parameter for
+                        * some reason happens to match someone from the from
+                        * link --jto
+                        */
+                       if (IsRegistered(acptr) && (acptr != cptr))
+                               break;
+                   }
+        if (acptr)
+           {
+               if (IsMe(acptr) || MyClient(acptr))
+                       return HUNTED_ISME;
+               if (match(acptr->name, parv[server]))
+                       parv[server] = acptr->name;
+               sendto_one(acptr, command, parv[0],
+                          parv[1], parv[2], parv[3], parv[4],
+                          parv[5], parv[6], parv[7], parv[8]);
+               return(HUNTED_PASS);
+           } 
+       sendto_one(sptr, err_str(ERR_NOSUCHSERVER), me.name,
+                  parv[0], parv[server]);
+       return(HUNTED_NOSUCH);
+    }
+
+
+/*
+** check_for_target_limit
+**
+** Return Values:
+** True(1) == too many targets are addressed
+** False(0) == ok to send message
+**
+*/
+int check_for_target_limit(aClient *sptr, void *target, const char *name)
+{
+#ifndef _WIN32 /* This is not windows compatible */
+       register u_char *p;
+#ifndef LINUX_ALPHA
+       register u_int tmp = ((u_int)target & 0xffff00) >> 8;
+#else
+       register u_int tmp = ((u_long)target & 0xffff00) >> 8;
+#endif
+       u_char hash = (tmp * tmp) >> 12;
+
+       if(IsAnOper(sptr))
+               return 0;
+       if (sptr->targets[0] == hash)
+               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;
+               }
+
+       if (now < sptr->nexttarget) {
+               if (sptr->nexttarget - now < TARGET_DELAY + 8) {
+                       sptr->nexttarget += 2;
+                       sendto_one(sptr, err_str(ERR_TARGETTOOFAST),
+                               me.name, sptr->name, name, sptr->nexttarget - now);
+               }
+       return 1;
+       } else {
+               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;   
+#endif
+       return 0;
+}
+
+
+    
+
+/*
+** 'do_nick_name' ensures that the given parameter (nick) is
+** really a proper string for a nickname (note, the 'nick'
+** may be modified in the process...)
+**
+**     RETURNS the length of the final NICKNAME (0, if
+**     nickname is illegal)
+**
+**  Nickname characters are in range
+**     'A'..'}', '_', '-', '0'..'9'
+**  anything outside the above set will terminate nickname.
+**  In addition, the first character cannot be '-'
+**  or a Digit.
+**
+**  Note:
+**     '~'-character should be allowed, but
+**     a change should be global, some confusion would
+**     result if only few servers allowed it...
+*/
+
+int    do_nick_name(nick)
+char   *nick;
+{
+       Reg1 char *ch;
+
+       if (*nick == '-' || isdigit(*nick)) /* first character in [0..9-] */
+               return 0;
+
+       for (ch = nick; *ch && (ch - nick) < NICKLEN; ch++)
+               if (!isvalid(*ch) || isspace(*ch))
+                       break;
+
+       *ch = '\0';
+
+       return (ch - nick);
+}
+
+
+/*
+** canonize
+**
+** reduce a string of duplicate list entries to contain only the unique
+** items.  Unavoidably O(n^2).
+*/
+char   *canonize(buffer)
+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)
+                   {
+                       for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
+                            t = strtoken(&p2, NULL, ","))
+                               if (!mycmp(s, t))
+                                       break;
+                               else if (p2)
+                                       p2[-1] = ',';
+                   }
+               else
+                       t = NULL;
+               if (!t)
+                   {
+                       if (l)
+                               *(cp-1) = ',';
+                       else
+                               l = 1;
+                       (void)strcpy(cp, s);
+                       if (p)
+                               cp += (p - s);
+                   }
+               else if (p2)
+                       p2[-1] = ',';
+           }
+       return cbuf;
+}
+
+int m_remgline (aClient *cptr, aClient *sptr, int parc, char *parv[])
+{
+       if (!IsOper(sptr))
+               return 0;
+               
+       sendto_one(sptr, ":%s NOTICE %s :*** Please use /gline -mask instead of /Remgline", me.name, sptr->name);
+}
+
+extern char    cmodestring[512];
+
+/*
+** register_user
+**     This function is called when both NICK and USER messages
+**     have been accepted for the client, in whatever order. Only
+**     after this the USER message is propagated.
+**
+**     NICK's must be propagated at once when received, although
+**     it would be better to delay them too until full info is
+**     available. Doing it is not so simple though, would have
+**     to implement the following:
+**
+**     1) user telnets in and gives only "NICK foobar" and waits
+**     2) another user far away logs in normally with the nick
+**        "foobar" (quite legal, as this server didn't propagate
+**        it).
+**     3) now this server gets nick "foobar" from outside, but
+**        has already the same defined locally. Current server
+**        would just issue "KILL foobar" to clean out dups. But,
+**        this is not fair. It should actually request another
+**        nick from local user or kill him/her...
+*/
+extern aTKline *tklines;
+
+static int     register_user(cptr, sptr, nick, username, umode,virthost)
+aClient        *cptr;
+aClient        *sptr;
+char   *nick, *username,*virthost, *umode;
+{
+       Reg1    aConfItem *aconf;
+    char        *parv[3], *tmpstr, c;
+#ifdef HOSTILENAME
+       char    stripuser[USERLEN+1], *u1=stripuser, *u2, olduser[USERLEN+1],
+               userbad[USERLEN*2+1], *ubad=userbad, noident=0;
+#endif
+        short   oldstatus = sptr->status, upper = 0, lower = 0, special = 0;
+       int             xx;
+       anUser  *user = sptr->user;
+       aClient *nsptr;
+       int     i;
+#ifdef OWNLOGON
+       FILE*   ownlog;
+#endif
+       char    mo[256], mo2[256];
+       char    *tmpx;
+        char    *tkllayer[9] =
+                {
+                        me.name,        /*0  server.name*/
+                        "+",           /*1  +|- */
+                        "z",            /*2  G   */
+                        "*",           /*3  user */
+                        NULL,           /*4  host */
+                        NULL,
+                        NULL,           /*6  expire_at */
+                        NULL,           /*7  set_at */
+                        NULL            /*8  reason */
+                };
+       user->last = TStime();
+       parv[0] = sptr->name;
+       parv[1] = parv[2] = NULL;
+
+       if (MyConnect(sptr))
+       {
+               sptr->iown = 1;
+       }
+       else
+       {
+               sptr->iown = 0;
+       }
+#ifdef OWNLOGON
+       ownlog = fopen ("iown.log", "a");
+       if (ownlog != NULL)
+       {
+               fprintf (ownlog, "%s connected, (iown=%d)\n",nick,sptr->iown);
+               fclose (ownlog);
+       }
+#endif
+
+       if (MyConnect(sptr))
+           {
+#ifdef SOCKSPORT
+               if (sptr->flags & FLAGS_GOTSOCKS)
+               {
+                  char hostip[128];
+
+                  strcpy(hostip, inetntoa((char *) &sptr->ip));
+               
+                 sendto_one(sptr, ":%s NOTICE AUTH :*** Found open SOCKS server (bad)", me.name);
+                 
+                  sendto_umode(UMODE_EYES, "Open SOCKS server from client %s",
+                      get_client_host(sptr));
+                 
+                 
+               
+                  i = exit_client(cptr, sptr, &me, iConf.socksquitmessage);
+
+                 tkllayer[4] = hostip; 
+                 tkllayer[5] = me.name;
+                 sprintf(mo, "%li", iConf.socksbantime+TStime());
+                 sprintf(mo2, "%li", TStime());
+                 tkllayer[6] = mo;
+                 tkllayer[7] = mo2;
+                 tkllayer[8] = iConf.socksbanmessage;
+                 m_tkl(&me, &me, 9, tkllayer);
+                 return i;
+               }
+
+#endif /* SOCKSPORT */
+
+               if ((i = check_client(sptr)))
+                   {
+                       sendto_umode(UMODE_OPER|UMODE_CLIENT,
+                                  "*** Notice -- %s from %s.",
+                                  i == -3 ? "Too many connections" :
+                                            "Unauthorized connection",
+                                  get_client_host(sptr));
+                       ircstp->is_ref++;
+                       tmpx = MyMalloc(1024);
+                       sprintf(tmpx, "This server is full. Please try %s", defserv);
+                       xx = exit_client(cptr, sptr, &me, i == -3 ? 
+                               tmpx : "You are not authorized to connect to this server");
+                       MyFree(tmpx);
+                       return xx;
+                     } 
+               if (IsUnixSocket(sptr))
+                       strncpyzt(user->realhost, me.sockhost, sizeof(user->realhost));
+               else if (sptr->hostp) {
+                       /* No control-chars or ip-like dns replies... I cheat :)
+                          -- OnyxDragon */
+                       for (tmpstr = sptr->sockhost; *tmpstr > ' ' &&
+                               *tmpstr < 127; tmpstr++);
+                       if (*tmpstr || !*user->realhost || isdigit(*(tmpstr-1)))
+                               strncpyzt(sptr->sockhost, (char *)inetntoa((char *)&sptr->ip), sizeof(sptr->sockhost)); /* Fix the sockhost for debug jic */
+                       strncpyzt(user->realhost, sptr->sockhost, sizeof(sptr->sockhost));
+               }
+               else /* Failsafe point, don't let the user define their
+                       own hostname via the USER command --Cabal95 */
+                       strncpyzt(user->realhost, sptr->sockhost, HOSTLEN+1);
+               strncpyzt(user->realhost, user->realhost, sizeof(user->realhost));
+               aconf = sptr->confs->value.aconf;
+               /*
+                * I do not consider *, ~ or ! 'hostile' in usernames,
+                * as it is easy to differentiate them (Use \*, \? and \\)
+                * with the possible?
+                * exception of !. With mIRC etc. ident is easy to fake
+                * to contain @ though, so if that is found use non-ident
+                * username. -Donwulff
+                *
+                * I do, We only allow a-z A-Z 0-9 _ - and . now so the
+                * !strchr(sptr->username, '@') check is out of date. -Cabal95
+                *
+                * Moved the noident stuff here. -OnyxDragon
+                */
+               if (!(sptr->flags & FLAGS_DOID))
+                       strncpyzt(user->username, username, USERLEN+1);
+               else if (sptr->flags & FLAGS_GOTID)
+                       strncpyzt(user->username, sptr->username, USERLEN+1);
+               else
+                   {
+                       /* because username may point to user->username */
+                       char    temp[USERLEN+1];
+
+                       strncpyzt(temp, username, USERLEN+1);
+                       *user->username = '~';
+                       (void)strncpy(&user->username[1], temp, USERLEN);
+                       user->username[USERLEN] = '\0';
+#ifdef HOSTILENAME
+                       noident = 1;
+#endif
+                   }
+#ifdef HOSTILENAME
+               /*
+                * Limit usernames to just 0-9 a-z A-Z _ - and .
+                * It strips the "bad" chars out, and if nothing is left
+                * changes the username to the first 8 characters of their
+                * nickname. After the MOTD is displayed it sends numeric
+                * 455 to the user telling them what(if anything) happened.
+                * -Cabal95
+                *
+                * Moved the noident thing to the right place - see above
+                * -OnyxDragon
+                */
+               for (u2 = user->username+noident; *u2; u2++)
+                   {
+                       if (isallowed(*u2))
+                               *u1++ = *u2;
+                       else if (*u2 < 32)
+                           {
+                               /*
+                                * Make sure they can read what control
+                                * characters were in their username.
+                                */
+                               *ubad++ = '^';
+                               *ubad++ = *u2+'@';
+                           }
+                       else
+                               *ubad++ = *u2;
+                   }
+               *u1 = '\0';
+               *ubad = '\0';
+               if (strlen(stripuser) != strlen(user->username+noident))
+                   {
+                       if (stripuser[0] == '\0')
+                           {
+                               strncpy(stripuser, cptr->name, 8);
+                               stripuser[8] = '\0';
+                           }
+
+                       strcpy(olduser, user->username+noident);
+                       strncpy(user->username+1, stripuser, USERLEN-1);
+                       user->username[0] = '~';
+                       user->username[USERLEN] = '\0';
+                   }
+               else
+                       u1 = NULL;
+#endif
+
+               if (!BadPtr(aconf->passwd) && !StrEq("ONE", aconf->passwd)) {
+                       if (!StrEq(sptr->passwd, aconf->passwd)) {
+                               ircstp->is_ref++;
+                               sendto_one(sptr, err_str(ERR_PASSWDMISMATCH),
+                                          me.name, parv[0]);
+                               return exit_client(cptr, sptr, &me, "Bad Password");
+                       }
+                       /* .. Else password check was successful, clear the pass
+                        * so it doesn't get sent to NickServ.
+                        * - Wizzu
+                        */
+                       else sptr->passwd[0] = '\0';
+               }
+
+               /*
+                * following block for the benefit of time-dependent K:-lines
+                */
+               if (find_kill(sptr))
+                   {
+                               ircstp->is_ref++;
+                               tmpx = MyMalloc(1024);
+                               sprintf(tmpx, "[%s] You are banned from using this server", ircnetwork);
+                               xx = exit_client(cptr, sptr, &me, "You are banned from using this server");
+                               MyFree(tmpx);
+                               return xx;
+                   }
+               tkl_check_expire();
+               if ((xx = find_tkline_match(sptr, 0)) != -1)
+               {
+                       ircstp->is_ref++;
+                       return xx;
+               }
+
+#ifdef                DISALLOW_MIXED_CASE
+/* check for mixed case usernames, meaning probably hacked   Jon2 3-94
+*/
+#ifdef        IGNORE_CASE_FIRST_CHAR
+              tmpstr = (username[0] == '~' ? &username[2] : &username[1]);
+#else
+              tmpstr = (username[0] == '~' ? &username[1] : username);
+#endif        /* IGNORE_CASE_FIRST_CHAR */
+             while (*tmpstr && !(lower && upper || special)) {
+               c = *tmpstr;
+               tmpstr++;
+               if (islower(c)) {
+                 lower++;
+                 continue; /* bypass rest of tests */
+               }
+               if (isupper(c)) {
+                 upper++;
+                 continue;
+               }
+               if (c == '-' || c == '_' || c == '.' || isdigit(c))
+                 continue;
+               special++;
+             }
+             if (lower && upper || special) {
+                   sendto_ops("Invalid username: %s",
+                              get_client_name(sptr,FALSE));
+                   ircstp->is_ref++;
+                   return exit_client(cptr, sptr, sptr , "Invalid username");
+             }
+
+#endif                /* DISALLOW_MIXED_CASE */
+
+               if (oldstatus == STAT_MASTER && MyConnect(sptr))
+                       (void)m_oper(&me, sptr, 1, parv);
+           }
+       else
+       {
+               strncpyzt(user->username, username, USERLEN+1);
+       }
+       SetClient(sptr);
+       make_virthost(user->realhost, user->virthost);
+       if (MyConnect(sptr))
+           {
+               sendto_one(sptr, rpl_str(RPL_WELCOME), me.name, nick, 
+                               ircnetwork, nick,
+                          user->username, user->realhost);
+               /* This is a duplicate of the NOTICE but see below...*/
+               sendto_one(sptr, rpl_str(RPL_YOURHOST), me.name, nick,
+                          me.name, version);
+#ifdef IRCII_KLUDGE
+               /*
+               ** Don't mess with this one - IRCII needs it! -Avalon
+               */
+               sendto_one(sptr,
+                       "NOTICE %s :*** Your host is %s, running version %s",
+                       nick, get_client_name(&me, FALSE), version);
+#endif
+               sendto_one(sptr, rpl_str(RPL_CREATED),me.name,nick,creation);
+#ifdef CONFROOM_JAVA_PORT
+               if (!(sptr->acpt->port == CONFROOM_JAVA_PORT))
+#endif
+                       sendto_one(sptr, rpl_str(RPL_MYINFO), me.name, parv[0],
+                                  me.name, version,umodestring, cmodestring);
+               sendto_one(sptr, rpl_str(RPL_PROTOCTL), me.name,nick, PROTOCTL_CLIENT);
+               (void)m_lusers(sptr, sptr, 1, parv);
+               update_load();
+               (void)m_motd(sptr, sptr, 1, parv);
+               
+#ifdef HOSTILENAME
+               /*
+                * Now send a numeric to the user telling them what, if
+                * anything, happened.
+                */
+               if (u1)
+                       sendto_one(sptr, err_str(ERR_HOSTILENAME), me.name,
+                                  sptr->name, olduser, userbad, stripuser);
+#endif
+               nextping = TStime();
+               sendto_connectnotice(nick, user, sptr);
+/*             sendto_umode(UMODE_OPER|UMODE_CLIENT,"*** Notice -- Client connecting on port %d: %s (%s@%s)", 
+                              sptr->acpt->port, nick, user->username,
+                              user->realhost);
+               sendto_conn_hcn("*** Notice -- Client connecting: %s (%s@%s) [%s] {%d}",
+                       nick,user->username, user->realhost, sptr->sockhost, get_client_class(sptr));
+*/
+/* This is a huge bastard of bandwidth use --sts */
+#ifdef BASTARDFCONNECTNOTICES
+               sendto_serv_butone(&me, ":%s SMO F :Client connecting at %s port %d: %s (%s@%s)",
+                       me.name, me.name, sptr->acpt->port, nick, user->username, user->realhost);
+#endif
+    }
+       else if (IsServer(cptr))
+           {
+               aClient *acptr;
+
+               if (!(acptr = find_server(user->server, NULL)))
+               {
+                 sendto_ops("Bad USER [%s] :%s USER %s %s : No such server",
+                     cptr->name, nick, user->username, user->server);
+                 sendto_one(cptr, ":%s KILL %s :%s (No such server: %s)",
+                     me.name, sptr->name, me.name, user->server);
+                 sptr->flags |= FLAGS_KILLED;
+                 return exit_client(sptr, sptr, &me,
+                     "USER without prefix(2.8) or wrong prefix");
+                }
+                else if (acptr->from != sptr->from)
+                  {
+                       sendto_ops("Bad User [%s] :%s USER %s %s, != %s[%s]",
+                               cptr->name, nick, user->username, user->server,
+                               acptr->name, acptr->from->name);
+                       sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])",
+                                  me.name, sptr->name, me.name, user->server,
+                                  acptr->from->name, acptr->from->sockhost);
+                       sptr->flags |= FLAGS_KILLED;
+                       return exit_client(sptr, sptr, &me,
+                                          "USER server wrong direction");
+                  }
+               else sptr->flags|=(acptr->flags & FLAGS_TS8);
+               /* *FINALL* this gets in ircd... -- Barubary */
+               if (find_conf_host(cptr->confs, sptr->name, CONF_UWORLD)
+                   || (sptr->user && find_conf_host(cptr->confs,
+                   sptr->user->server, CONF_UWORLD)))
+                       sptr->flags |= FLAGS_ULINE;
+           }
+
+       if (virthost && umode)
+        {
+               tkllayer[0] = nick;
+               tkllayer[1] = nick;
+               tkllayer[2] = umode;
+               dontspread = 1;
+               m_mode(cptr,sptr, 3, tkllayer);
+               dontspread = 0;
+               if (virthost && *virthost != '*')
+                       sprintf(sptr->user->virthost, virthost);
+        }      
+       hash_check_notify(sptr, RPL_LOGON);     /* Uglier hack */
+       sendto_serv_butone_nickv2(cptr, "NICK %s %d %d %s %s %s %lu :%s", nick,
+         sptr->hopcount+1, sptr->lastnick, user->username, user->realhost,
+         user->server, sptr->user->servicestamp, sptr->info);
+       if (virthost && *virthost != '*')
+               sendto_serv_butone_nickv2(cptr, ":%s SETHOST %s", sptr->name, sptr->user->virthost);
+       send_umode(NULL, sptr, 0, SEND_UMODES, buf);
+       sendto_serv_nickv2(cptr, "NICK %s %d %d %s %s %s %lu %s %s :%s", nick,
+                         sptr->hopcount+1, sptr->lastnick, user->username, user->realhost,
+                         user->server, sptr->user->servicestamp, 
+                               (!buf || *buf == '\0' ? "+" : buf),
+                               ((IsHidden(sptr) && (sptr->umodes & UMODE_SETHOST)) ? sptr->user->virthost : "*"),
+                               sptr->info);
+
+       /* Send password from sptr->passwd to NickServ for identification,
+        * if passwd given and if NickServ is online.
+        * - by taz, modified by Wizzu
+        */
+       if (MyConnect(sptr)) {
+           send_umode_out_nickv2(cptr, sptr, 0);
+           if (sptr->passwd[0] && (nsptr = find_person(NickServ, NULL)))
+               sendto_one(nsptr,":%s PRIVMSG %s@%s :IDENTIFY %s",
+                 sptr->name, NickServ, SERVICES_NAME, sptr->passwd);
+       }
+
+       if(MyConnect(sptr) && !BadPtr(sptr->passwd))
+               bzero(sptr->passwd, sizeof(sptr->passwd));
+
+
+       return 0;
+    }
+
+/*
+** m_svsnick
+**     parv[0] = sender
+**     parv[1] = old nickname
+**     parv[2] = new nickname
+**     parv[3] = timestamp
+*/
+int    m_svsnick(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+
+       if (!IsULine(cptr, sptr) || parc < 4 || (strlen(parv[2]) > NICKLEN))
+               return -1; /* This looks like an error anyway -Studded */
+
+       if (!hunt_server(cptr, sptr, ":%s SVSNICK %s %s :%s", 1, parc, parv) != HUNTED_ISME) {
+               if ((acptr = find_person(parv[1], NULL))) {
+                       if(find_client(parv[2], NULL)) /* Collision */
+                               return exit_client(cptr, acptr, sptr,
+                                 "Nickname collision due to Services enforced "
+                                 "nickname change, your nick was overruled");
+                       if (strchr(parv[2], '.'))
+                               return exit_client(cptr, acptr, sptr,
+                               "SVSNICK Collide (nick changed to be server)");
+                       acptr->umodes &= ~UMODE_REGNICK;
+                       acptr->lastnick = atoi(parv[3]);
+                       sendto_common_channels(acptr, ":%s NICK :%s", parv[1], parv[2]);
+                       if (IsPerson(acptr))
+                               add_history(acptr);
+                       sendto_serv_butone(NULL, ":%s NICK %s :%i", parv[1], parv[2], atoi(parv[3]));
+                       if(acptr->name[0]) {
+                               (void)del_from_client_hash_table(acptr->name, acptr);
+                               if(IsPerson(acptr)) hash_check_notify(acptr, RPL_LOGOFF);
+                       }
+                       (void)strcpy(acptr->name, parv[2]);
+                       (void)add_to_client_hash_table(parv[2], acptr);
+                       if (IsPerson(acptr)) hash_check_notify(acptr, RPL_LOGON);
+               }
+       }
+  return 0;
+}
+
+/*
+** m_nick
+**     parv[0] = sender prefix
+**     parv[1] = nickname
+**  if from new client  -taz
+**     parv[2] = nick password
+**  if from server:
+**      parv[2] = hopcount
+**      parv[3] = timestamp
+**      parv[4] = username
+**      parv[5] = hostname
+**      parv[6] = servername
+**  if NICK version 1:
+**      parv[7] = servicestamp
+**     parv[8] = info
+**  if NICK version 2:
+**     parv[7] = servicestamp
+**      parv[8] = umodes
+**     parv[9] = virthost, * if none
+**     parv[10] = info
+*/
+int    m_nick(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aConfItem *aconf;
+       aSqlineItem *asqline;
+       aClient *acptr, *serv;
+       char    nick[NICKLEN+2], *s;
+       Link    *lp;
+       time_t  lastnick = (time_t)0;
+       int     differ = 1;
+
+        static int firstnsrun=0;
+       u_int32_t     md5data[16];
+       static u_int32_t     md5hash[4];
+
+       /*
+        * If the user didn't specify a nickname, complain
+        */
+       if (parc < 2)
+       {
+               sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
+                       me.name, parv[0]);
+               return 0;
+       }
+
+       if (MyConnect(sptr) && (s = (char *)index(parv[1], '~')))
+               *s = '\0';
+
+       strncpyzt(nick, parv[1], NICKLEN+1);
+       /*
+        * 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], "Illegal characters");
+
+               if (IsServer(cptr))
+               {
+                       ircstp->is_kill++;
+                       sendto_failops("Bad Nick: %s From: %s %s",
+                                  parv[1], parv[0],
+                                  get_client_name(cptr, FALSE));
+                       sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])",
+                                  me.name, parv[1], me.name, parv[1],
+                                  nick, cptr->name);
+                       if (sptr != cptr)
+                       { /* bad nick change */
+                               sendto_serv_butone(cptr,
+                                       ":%s KILL %s :%s (%s <- %s!%s@%s)",
+                                       me.name, parv[0], me.name,
+                                       get_client_name(cptr, FALSE),
+                                       parv[0],
+                                       sptr->user ? sptr->username : "",
+                                       sptr->user ? sptr->user->server :
+                                                    cptr->name);
+                               sptr->flags |= FLAGS_KILLED;
+                               return exit_client(cptr,sptr,&me,"BadNick");
+                       }
+               }
+               return 0;
+       }
+
+       /*
+       ** Protocol 4 doesn't send the server as prefix, so it is possible
+       ** the server doesn't exist (a lagged net.burst), in which case
+       ** we simply need to ignore the NICK. Also when we got that server
+       ** name (again) but from another direction. --Run
+       */
+       /* 
+       ** We should really only deal with this for msgs from servers.
+       ** -- Aeto
+       */
+       if (IsServer(cptr) && 
+           (parc > 7 && (!(serv = find_server(parv[6], NULL)) ||
+                         serv->from != cptr->from)))
+         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 = find_server(nick, NULL)))
+       {
+               if (MyConnect(sptr))
+               {
+                       sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
+                                  BadPtr(parv[0]) ? "*" : parv[0], nick);
+                       return 0; /* NICK message ignored */
+               }
+       }
+
+       /*
+       ** Check for a Q-lined nickname. If we find it, and it's our
+       ** client, just reject it. -Lefler
+       ** Allow opers to use Q-lined nicknames. -Russell
+       */
+#ifdef WEBTV_IRCUSER
+       if (!match("irc", nick))
+       {
+                sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
+                  BadPtr(parv[0]) ? "*" : parv[0], nick,
+                   "Reserved for internal IRCd purposes");
+                return 0;
+       }
+#endif
+       if (!IsULine(cptr, sptr) && ((aconf = find_conf_name(nick, CONF_QUARANTINED_NICK)) || 
+               (asqline = find_sqline_match(nick))))
+       {
+               sendto_realops ("Q-lined nick %s from %s on %s.", nick,
+                     (*sptr->name!=0 && !IsServer(sptr)) ? sptr->name :
+                      "<unregistered>",
+                     (sptr->user==NULL) ? ((IsServer(sptr)) ? parv[6] : me.name) :
+                                          sptr->user->server);
+               if ((!IsServer(cptr)) && (!IsOper(cptr)))
+               {
+
+                       if(aconf)
+                        sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
+                          BadPtr(parv[0]) ? "*" : parv[0], nick,
+                          BadPtr(aconf->passwd) ? "reason unspecified" :
+                          aconf->passwd);
+                       else if(asqline)
+                        sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name,
+                          BadPtr(parv[0]) ? "*" : parv[0], nick,
+                          BadPtr(asqline->reason) ? "reason unspecified" :
+                          asqline->reason);
+
+                       sendto_realops("Forbidding Q-lined nick %s from %s.",
+                               nick, get_client_name(cptr, FALSE));
+                       return 0; /* NICK message ignored */
+               }
+       }
+
+       /*
+       ** acptr already has result from previous find_server()
+       */
+       if (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_failops("Nick collision on %s(%s <- %s)",
+                          sptr->name, acptr->from->name,
+                          get_client_name(cptr, FALSE));
+               ircstp->is_kill++;
+               sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)",
+                          me.name, sptr->name, me.name, acptr->from->name,
+                          /* NOTE: Cannot use get_client_name
+                          ** twice here, it returns static
+                          ** string pointer--the other info
+                          ** would be lost
+                          */
+                          get_client_name(cptr, FALSE));
+               sptr->flags |= FLAGS_KILLED;
+               return exit_client(cptr, sptr, &me, "Nick/Server collision");
+       }
+
+       if (MyClient(cptr) && !IsOper(cptr))
+               cptr->since += 3; /* Nick-flood prot. -Donwulff */
+
+       if (!(acptr = find_client(nick, NULL)))
+               goto nickkilldone;  /* No collisions, all clear... */
+       /*
+       ** 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...
+       */
+       /* Moved before Lost User Field to fix some bugs... -- Barubary */
+       if (IsUnknown(acptr) && MyConnect(acptr))
+       {
+               /* This may help - copying code below */
+               if (acptr == cptr)
+                       return 0;
+               acptr->flags |= FLAGS_KILLED;
+               exit_client(NULL, acptr, &me, "Overridden");
+               goto nickkilldone;
+       }
+       /* A sanity check in the user field... */
+       if (acptr->user == NULL)
+       {
+         /* This is a Bad Thing */
+         sendto_failops("Lost user field for %s in change from %s",
+                    acptr->name, get_client_name(cptr,FALSE));
+         ircstp->is_kill++;
+         sendto_one(acptr, ":%s KILL %s :%s (Lost user field!)",
+                    me.name, acptr->name, me.name);
+         acptr->flags |= FLAGS_KILLED;
+         /* Here's the previous versions' desynch.  If the old one is
+            messed up, trash the old one and accept the new one.
+            Remember - at this point there is a new nick coming in!
+            Handle appropriately. -- Barubary */
+         exit_client (NULL, acptr, &me, "Lost user field");
+         goto nickkilldone;
+       }
+       /*
+       ** 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
+           /*
+           ** 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).
+       */
+       /*
+       ** 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),
+                          /* parv[0] is empty when connecting */
+                          me.name, 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 we have the old protocol (no TimeStamp and no user@host)
+       ** or if the TimeStamps are equal, we kill both (or only 'new'
+       ** if it was a "NICK new"). Otherwise we kill the youngest
+       ** when user@host differ, or the oldest when they are the same.
+       ** --Run
+       ** 
+       */
+       if (IsServer(sptr))
+       {           
+           /*
+           ** A new NICK being introduced by a neighbouring
+           ** server (e.g. message type "NICK new" received)
+           */
+           if (parc > 3)
+           {
+             lastnick = atoi(parv[3]);
+             if (parc > 5)
+               differ = (mycmp(acptr->user->username, parv[4]) ||
+                   mycmp(acptr->user->realhost, parv[5]));
+           }
+           sendto_failops("Nick collision on %s (%s %d <- %s %d)",
+                   acptr->name, acptr->from->name, acptr->lastnick, 
+                   get_client_name(cptr, FALSE), lastnick);
+           /*
+           **    I'm putting the KILL handling here just to make it easier
+           ** to read, it's hard to follow it the way it used to be.
+           ** Basically, this is what it will do.  It will kill both
+           ** users if no timestamp is given, or they are equal.  It will
+           ** kill the user on our side if the other server is "correct"
+           ** (user@host differ and their user is older, or user@host are
+           ** the same and their user is younger), otherwise just kill the
+           ** user an reintroduce our correct user.
+           **    The old code just sat there and "hoped" the other server
+           ** would kill their user.  Not anymore.
+           **                                          -- binary
+           */
+           if (!(parc > 3) || (acptr->lastnick == lastnick))
+           {
+               ircstp->is_kill++;
+               sendto_serv_butone(NULL,
+                       ":%s KILL %s :%s (Nick Collision: %s <- %s)",
+                       me.name, acptr->name, me.name, acptr->from->name,
+                       parc > 5 ? parv[5] : get_client_name(cptr, FALSE));
+               acptr->flags |= FLAGS_KILLED;
+               (void)exit_client(NULL, acptr, &me,
+                       "Nick collision with no timestamp/equal timestamps");
+               return 0; /* We killed both users, now stop the process. */
+           }
+                       
+           if ((differ && (acptr->lastnick > lastnick)) ||
+               (!differ && (acptr->lastnick < lastnick)) ||
+               acptr->from == cptr) /* we missed a QUIT somewhere ? */
+           {
+               ircstp->is_kill++;
+               sendto_serv_butone(cptr,
+                       ":%s KILL %s :%s (Nick Collision: %s <- %s)",
+                       me.name, acptr->name, me.name, acptr->from->name,
+                       parc > 5 ? parv[5] : get_client_name(cptr, FALSE));
+               acptr->flags |= FLAGS_KILLED;
+               (void)exit_client(NULL, acptr, &me,
+                       "Nick collision");
+               goto nickkilldone; /* OK, we got rid of the "wrong" user,
+                                  ** now we're going to add the user the
+                                  ** other server introduced.
+                                  */
+           }
+           
+           if ((differ && (acptr->lastnick < lastnick)) ||
+               (!differ && (acptr->lastnick > lastnick)))
+           {
+               /* 
+                * Introduce our "correct" user to the other server
+                */
+               
+               sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)",
+                 me.name, parv[1], me.name);
+                       sendto_one(cptr, "NICK %s %d %d %s %s %s :%s",
+                         acptr->name, acptr->hopcount + 1, acptr->lastnick,
+                         acptr->user->username, acptr->user->realhost,
+                         acptr->user->server, acptr->info);
+                       send_umode(cptr, acptr, 0, SEND_UMODES, buf);
+                       if (IsHidden(acptr)) {
+                               sendto_one(cptr, ":%s SETHOST %s", acptr->name, acptr->user->virthost);
+                       }
+               if (acptr->user->away)
+                 sendto_one(cptr, ":%s AWAY :%s", acptr->name,
+                   acptr->user->away);
+               send_user_joins(cptr, acptr);
+               return 0; /* Ignore the NICK */
+           }
+           return 0;
+       }
+       else
+       {
+           /*
+           ** A NICK change has collided (e.g. message type ":old NICK new").
+           */
+           if (parc > 2)
+                   lastnick = atoi(parv[2]);
+           differ = (mycmp(acptr->user->username, sptr->user->username) ||
+               mycmp(acptr->user->realhost, sptr->user->realhost));
+           sendto_failops(
+                   "Nick change collision from %s to %s (%s %d <- %s %d)",
+                   sptr->name, acptr->name, acptr->from->name,
+                   acptr->lastnick, sptr->from->name, lastnick);
+           if (!(parc > 2) ||  lastnick == acptr->lastnick)
+           {
+               ircstp->is_kill += 2;
+               sendto_serv_butone(NULL, /* First kill the new nick. */
+                       ":%s KILL %s :%s (Self Collision)",
+                       me.name, acptr->name, me.name);
+               sendto_serv_butone(cptr, /* Tell my servers to kill the old */
+                       ":%s KILL %s :%s (Self Collision)",
+                       me.name, sptr->name, me.name);
+               sptr->flags |= FLAGS_KILLED;
+               acptr->flags |= FLAGS_KILLED;
+               (void)exit_client(NULL, sptr, &me, "Self Collision");
+               (void)exit_client(NULL, acptr, &me, "Self Collision");
+               return 0; /* Now that I killed them both, ignore the NICK */
+           }           
+           if ((differ && (acptr->lastnick > lastnick)) ||
+               (!differ && (acptr->lastnick < lastnick)))
+           {
+               /* sptr (their user) won, let's kill acptr (our user) */
+               ircstp->is_kill++;
+               sendto_serv_butone(cptr,
+                       ":%s KILL %s :%s (Nick collision: %s <- %s)",
+                       me.name, acptr->name, me.name,
+                       acptr->from->name, sptr->from->name);
+               acptr->flags |= FLAGS_KILLED;
+               (void)exit_client(NULL, acptr, &me, "Nick collision");
+               goto nickkilldone; /* their user won, introduce new nick */
+           }
+           if ((differ && (acptr->lastnick < lastnick)) ||
+               (!differ && (acptr->lastnick > lastnick)))
+           {
+               /* acptr (our user) won, let's kill sptr (their user),
+               ** and reintroduce our "correct" user
+               */
+               ircstp->is_kill++;
+               /* Kill the user trying to change their nick. */
+               sendto_serv_butone(cptr,
+                       ":%s KILL %s :%s (Nick collision: %s <- %s)",
+                       me.name, sptr->name, me.name,
+                       sptr->from->name, acptr->from->name);
+               sptr->flags |= FLAGS_KILLED;
+               (void)exit_client(NULL, sptr, &me, "Nick collision");
+               /* 
+                * Introduce our "correct" user to the other server
+                */
+               /* Kill their user. */
+               sendto_one(cptr, ":%s KILL %s :%s (Nick Collision)",
+                 me.name, parv[1], me.name);
+               sendto_one(cptr, "NICK %s %d %d %s %s %s :%s",
+                 acptr->name, acptr->hopcount + 1, acptr->lastnick,
+                 acptr->user->username, acptr->user->realhost,
+                 acptr->user->server, acptr->info);
+               send_umode(cptr, acptr, 0, SEND_UMODES, buf);
+               if (acptr->user->away)
+                 sendto_one(cptr, ":%s AWAY :%s", acptr->name,
+                   acptr->user->away);
+               if (IsHidden(acptr)) {
+                               sendto_one(cptr, ":%s SETHOST %s", acptr->name, acptr->user->virthost);
+               }
+
+               send_user_joins(cptr, acptr);
+               return 0; /* their user lost, ignore the NICK */
+           }
+           
+       }
+       return 0; /* just in case */    
+nickkilldone:
+       if (IsServer(sptr)) {
+         /* A server introducing a new client, change source */
+
+         sptr = make_client(cptr, serv);
+         add_client_to_list(sptr);
+         if (parc > 2)
+           sptr->hopcount = atoi(parv[2]);
+         if (parc > 3)
+           sptr->lastnick = atoi(parv[3]);
+         else /* Little bit better, as long as not all upgraded */
+           sptr->lastnick = TStime();
+       } else if (sptr->name[0]&&IsPerson(sptr)) {
+         /*
+         ** If the client belongs to me, then check to see
+         ** if client is currently on any channels where it
+         ** is currently banned.  If so, do not allow the nick
+         ** change to occur.
+         ** Also set 'lastnick' to current time, if changed.
+         */
+         if (MyClient(sptr))
+           for (lp = cptr->user->channel; lp; lp = lp->next)
+             if (is_banned(cptr, &me, lp->value.chptr)) {
+               sendto_one(cptr,
+                          err_str(ERR_BANNICKCHANGE),
+                          me.name, parv[0],
+                          lp->value.chptr->chname);
+               return 0;
+             }
+         
+         /*
+          * 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 (mycmp(parv[0], nick) ||
+             /* Next line can be removed when all upgraded  --Run */
+             !MyClient(sptr) && parc>2 && atoi(parv[2])<sptr->lastnick)
+           sptr->lastnick = (MyClient(sptr) || parc < 3) ?
+             TStime():atoi(parv[2]);
+         SetRegNick(sptr);
+         add_history(sptr);
+         sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
+         sendto_serv_butone(cptr, ":%s NICK %s :%d",
+                            parv[0], nick, sptr->lastnick);
+       } else if(!sptr->name[0])
+       {
+#ifdef NOSPOOF
+         /*
+          * Client setting NICK the first time.
+          *
+          * Generate a random string for them to pong with.
+          *
+          * The first two are server specific.  The intent is to randomize
+          * things well.
+          *
+          * We use lots of junk here, but only "low cost" things.
+          */
+         md5data[0] = NOSPOOF_SEED01;
+         md5data[1] = NOSPOOF_SEED02;
+         md5data[2] = TStime();
+         md5data[3] = me.sendM;
+         md5data[4] = me.receiveM;
+         md5data[5] = 0;
+         md5data[6] = getpid();
+         md5data[7] = sptr->ip.s_addr;
+         md5data[8] = sptr->fd;
+         md5data[9] = 0;
+         md5data[10] = 0;
+         md5data[11] = 0;
+         md5data[12] = md5hash[0];  /* previous runs... */
+         md5data[13] = md5hash[1];
+         md5data[14] = md5hash[2];
+         md5data[15] = md5hash[3];
+         
+         /*
+          * initialize the md5 buffer to known values
+          */
+         MD5Init(md5hash);
+
+         /*
+          * transform the above information into gibberish
+          */
+         MD5Transform(md5hash, md5data);
+
+         /*
+          * Never release any internal state of our generator.  Instead,
+          * use two parts of the returned hash and xor them to hide
+          * both values.
+          */
+         sptr->nospoof = (md5hash[0] ^ md5hash[1]);
+
+         /*
+          * If on the odd chance it comes out zero, make it something
+          * non-zero.
+          */
+         if (sptr->nospoof == 0)
+           sptr->nospoof = 0xdeadbeef;
+         sendto_one(sptr, "NOTICE %s :*** If you are having problems"
+                    " connecting due to ping timeouts, please"
+                    " type /notice %X nospoof now.",
+                    nick, sptr->nospoof, sptr->nospoof);
+         sendto_one(sptr, "PING :%X", sptr->nospoof);
+#endif /* NOSPOOF */
+         
+#ifdef CONTACT_EMAIL
+         sendto_one(sptr, ":%s NOTICE %s :*** If you need assistance with a"
+                    " connection problem, please email " CONTACT_EMAIL
+                    " with the name and version of the client you are"
+                    " using, and the server you tried to connect to: %s",
+                    me.name, nick, me.name);
+#endif /* CONTACT_EMAIL */
+#ifdef CONTACT_URL
+         sendto_one(sptr, ":%s NOTICE %s :*** If you need assistance with"
+                    " connecting to this server, %s, please refer to: "
+                    CONTACT_URL, me.name, nick, me.name);
+#endif /* CONTACT_URL */
+         
+         /* Copy password to the passwd field if it's given after NICK
+          * - originally by taz, modified by Wizzu
+          */
+         if((parc > 2) && (strlen(parv[2]) < sizeof(sptr->passwd)))
+          (void)strcpy(sptr->passwd,parv[2]);
+
+         /* This had to be copied here to avoid problems.. */
+         (void)strcpy(sptr->name, nick);
+         if (sptr->user && IsNotSpoof(sptr)) {
+           /*
+           ** USER already received, now we have NICK.
+           ** *NOTE* For servers "NICK" *must* precede the
+           ** user message (giving USER before NICK is possible
+           ** only for local client connection!). 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, NULL, NULL)
+                             
+               == FLUSH_BUFFER)
+             return FLUSH_BUFFER; }
+       }
+       /*
+        *  Finally set new nick name.
+        */
+       if (sptr->name[0]) {
+         (void)del_from_client_hash_table(sptr->name, sptr);
+         if (IsPerson(sptr))
+           hash_check_notify(sptr, RPL_LOGOFF);
+       }
+       (void)strcpy(sptr->name, nick);
+       (void)add_to_client_hash_table(nick, sptr);
+       if (IsServer(cptr) && parc>7) {
+         parv[3]=nick;
+         m_user(cptr, sptr, parc-3, &parv[3]);
+         if (GotNetInfo(cptr))
+                 sendto_umode(UMODE_FCLIENT, "*** Notice -- Client connecting at %s: %s (%s@%s)",
+                       sptr->user->server, sptr->name, sptr->user->username, sptr->user->realhost); 
+       }
+       else if (IsPerson(sptr))
+         hash_check_notify(sptr, RPL_LOGON);
+
+       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[2] = message text
+**
+** massive cleanup
+** rev argv 6/91
+**
+*/
+
+static int     m_message(cptr, sptr, parc, parv, notice)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+int    notice;
+{
+       Reg1    aClient *acptr;
+       Reg2    char    *s;
+       aChannel *chptr;
+       char    *nick, *server, *p, *cmd, *host, *ctcp;
+       int     cansend = 0;
+#ifdef REMOVE_ADVERTISING
+       /* patch by ice (ircadmin@fornet.net.tr) */
+       char *reklam,*reklam1,*reklam2, *sonuc;
+       char bas[200];  
+       int b;
+#endif
+
+        /*
+         * Reasons why someone can't send to a channel
+         */
+        static  char *err_cantsend[] = {
+          "You need voice (+v)",
+          "No external channel messages",
+          "Colour is not permitted in this channel",
+          "You are banned",
+          NULL
+        };
+        
+       if (IsHandshake(sptr))
+               return 0;
+       
+       if (notice)
+           {
+               if (check_registered(sptr))
+                       return 0;
+           }
+       else if (check_registered_user(sptr))
+               return 0;
+
+       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[2] == '\0')
+           {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+           }
+
+#ifdef WEBTV_NONOTICE
+       if (*parv[2] != '\1')
+       {
+               cmd = MSG_PRIVATE;
+       }
+#endif
+       if (MyConnect(sptr))
+               parv[1] = canonize(parv[1]);
+       for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
+            nick = strtoken(&p, NULL, ","))
+           {
+               /*
+               ** nickname addressed?
+               */
+#ifdef WEBTV_IRCUSER
+               if (!strcasecmp(nick, "irc") && MyClient(sptr))
+               {
+                       parse(sptr, parv[2], (parv[2] + strlen(parv[2])), msgtab);
+                       continue;
+               }
+#endif
+               if ((acptr = find_person(nick, NULL)))
+               {
+                       /* F:Line stuff by _Jozeph_ added by Stskeeps with comments */
+                       if (*parv[2] == 1 && MyClient(sptr) && !IsOper(sptr)) 
+                       /* somekinda ctcp thing
+                          and i don't want to waste cpu on what others already checked.. 
+                       (should this be checked ??) --Sts
+                       */
+                       {
+                               ctcp = &parv[2][1];
+                               /* Most likely a DCC send .. */
+                               if (!myncmp(ctcp, "DCC SEND ", 9))
+                               {
+                                       aFline   *fl;
+                                       char      *end, file[BUFSIZE];
+                                       int       size_string = 0;
+                       
+                                       ctcp = &parv[2][10];
+                                       end  = (char *)index(ctcp, ' ');
+                       
+                                       /* check if it was fake.. just pass it along then .. */
+                                       if (!end || (end < ctcp))
+                                       goto dcc_was_ok;        
+
+                                       size_string=(int)(end - ctcp);
+                       
+                                       if (!size_string || (size_string>(BUFSIZE-1)))
+                                                        goto dcc_was_ok;
+                       
+                                       strncpy(file, ctcp, size_string);
+                                               file[size_string] = '\0';
+                       
+                                       if ((fl = (aFline *) dcc_isforbidden(cptr,sptr,acptr, file)))
+                                         {
+                                               sendto_one(sptr, ":%s %d %s :Cannot DCC SEND file %s to %s (%s)",
+                                                       me.name, RPL_TEXT, sptr->name,
+                                                       file, acptr->name, fl->reason ? fl->reason :
+                                                       "Possible infected virus file");
+                                                       /* Alert +e's too so preventive measure can be taken */
+                                               sendto_umode(UMODE_EYES, "%s tried to send forbidden file %s (%s) to %s", sptr->name, file, fl->reason, acptr->name);
+                                               sendto_umode(UMODE_VICTIM, "%s tried to send forbidden file %s (%s) to %s", sptr->name, file, fl->reason, acptr->name);
+                                               continue;
+                                       }
+                                       /* if it went here it was a legal send .. */
+                               }
+                       }
+dcc_was_ok:
+#ifdef REMOVE_ADVERTISING
+                       /* remove advertisment patch by ice - a bit ugly but it works? :P*/
+                       reklam=strstr(parv[2],"irc.");
+                       if (!reklam) reklam=strstr(parv[2],"IRC.");
+                       if (!reklam) reklam=strstr(parv[2],"Irc.");
+                       if (!reklam) reklam=strstr(parv[2],"IRc.");
+                       if (!reklam) reklam=strstr(parv[2],"irC.");
+                       if (!reklam) reklam=strstr(parv[2],"iRc.");
+                       if (!reklam) reklam=strstr(parv[2],"iRC.");
+                       if (!reklam) reklam=strstr(parv[2],"IrC.");
+                       if (reklam) {
+                         b=strlen(parv[2])-strlen(reklam);
+                         while (reklam) {
+                         reklam1=reklam;
+                         reklam=strstr(reklam1,".");
+                         reklam2=reklam;
+                         reklam=strstr(reklam2,"irc.");
+                         if (!reklam) reklam=strstr(reklam2,"IRC.");
+                       if (!reklam) reklam=strstr(reklam2,"Irc.");
+                       if (!reklam) reklam=strstr(reklam2,"IRc.");
+                       if (!reklam) reklam=strstr(reklam2,"IrC.");
+                       if (!reklam) reklam=strstr(reklam2,"iRC.");
+                       if (!reklam) reklam=strstr(reklam2,"iRc.");
+                       if (!reklam) reklam=strstr(reklam2,"irC.");
+                       }
+                         strcpy(bas,"");
+                         if (b <= 150) strncat(bas,parv[2],b);
+                         sonuc=strstr(reklam1,".com");
+                         if (!sonuc) sonuc=strstr(reklam1,".net");
+                         if (!sonuc) sonuc=strstr(reklam1,".COM");
+                         if (!sonuc) sonuc=strstr(reklam1,".NET");
+                         if (!sonuc) sonuc=strstr(reklam1,".gen");
+                         if (!sonuc) sonuc=strstr(reklam1,".GEN");
+                         if (!sonuc) sonuc=strstr(reklam1,".ORG");
+                         if (!sonuc) sonuc=strstr(reklam1,".org");
+                         if (!sonuc) sonuc=strstr(reklam1,".EDU");
+                         if (!sonuc) sonuc=strstr(reklam1,".edu");
+                         if (!sonuc) sonuc=strstr(reklam1,".");
+                         if (!sonuc) sonuc=strstr(reklam1," ");
+                         strcat(bas,"irc.*****");
+                         if ((strlen(sonuc)+strlen(bas)) <=150) strcat(bas,sonuc);
+                         parv[2]=bas;
+                       }                   
+#endif
+                       
+                   if (MyClient(sptr) && check_for_target_limit(sptr, acptr, acptr->name))
+                       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);
+                       sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
+                                         parv[0], cmd, nick, parv[2]);
+                   }
+                   continue;
+                }
+
+                if (nick[0] == '@')
+                {
+
+               /*   
+                * If its a message for all Channel OPs call the function
+                * sendto_channelops_butone() to handle it.  -Cabal95
+                */
+                       if ( nick[1] == '#' )
+                   {
+                        if (chptr = find_channel(nick+1, NullChn))
+                                {
+                                       cansend = can_send(sptr, chptr, parv[2]);
+                                       if (cansend == 0)
+                                               if (check_for_chan_flood(cptr, sptr, chptr) == 1)
+                                                       continue;
+                                       if (cansend == 0 || IsULine(cptr,sptr))
+                                               if (!(chptr->mode.mode & MODE_STRIP))
+                                               {
+                                                       sendto_channelops_butone(cptr, sptr, chptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]);
+                                               }
+                                               else
+                                               {
+                                                       sendto_channelops_butone(cptr, sptr, chptr, ":%s %s %s :%s", parv[0], cmd, nick, StripColors(parv[2]));                                                         
+                                                       }
+                                               else if (!notice)
+                                               sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick+1, err_cantsend[cansend-1]);
+                       }
+                      else
+                               sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick+1);
+               }
+
+                       /*   
+                        * If its a message for all Channel ops and voices call the function
+                        * sendto_channelvoice_butone() to handle it.  -DuffJ
+                        */
+                       else if (nick[1] == '+' && nick[2] == '#')
+                   {
+               if (chptr = find_channel(nick+2, NullChn))
+                {
+                                       cansend = can_send(sptr, chptr, parv[2]);
+                                       if (cansend == 0)
+                                               if (check_for_chan_flood(cptr, sptr, chptr) == 1)
+                                                       continue;
+
+                               if (cansend == 0 || IsULine(cptr,sptr))
+                                               if (!(chptr->mode.mode & MODE_STRIP))
+                                                       sendto_channelvoice_butone(cptr, sptr, chptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]);
+                                                       else
+                                                       sendto_channelvoice_butone(cptr, sptr, chptr, ":%s %s %s :%s", parv[0], cmd, nick, StripColors(parv[2]));
+                                       else if (!notice)
+                                               sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick+2, err_cantsend[cansend-1]);
+                }
+                               else sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick+2);
+                        }
+                       /*   
+                        * If its a message for all Channel ops and halfops call the function
+                        * sendto_channelhalfop_butone() to handle it.  -Stskeeps
+                        */
+                       else if ( nick[1] == '%' && nick[2] == '#' )
+                           {
+                                if (chptr = find_channel(nick+2, NullChn))
+                                    {
+                                       cansend = can_send(sptr, chptr, parv[2]);
+                                       if (cansend == 0)
+                                               if (check_for_chan_flood(cptr, sptr, chptr) == 1)
+                                                       continue;
+
+                                       if (cansend == 0 || IsULine(cptr,sptr))
+                                               if (!(chptr->mode.mode & MODE_STRIP))
+                                                       sendto_channelhalfop_butone(cptr, sptr, chptr, ":%s %s %s :%s", parv[0], cmd, nick, parv[2]);
+                                                       else
+                                                       sendto_channelhalfop_butone(cptr, sptr, chptr, ":%s %s %s :%s", parv[0], cmd, nick, StripColors(parv[2]));
+                                                       
+                                       else if (!notice)
+                                               sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN), me.name, parv[0], nick+2, err_cantsend[cansend-1]);
+                                    }
+                               else sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], nick+2);
+                           }
+                       continue;
+        }
+                       
+               /*
+               ** channel msg?
+               ** Now allows U-lined users to send to channel no problemo
+               ** -- Barubary
+               */
+               if ((chptr = find_channel(nick, NullChn)))
+                   {
+                       cansend = can_send(sptr, chptr, parv[2]);
+                       if (cansend == 0)
+                               if (check_for_chan_flood(cptr, sptr, chptr) == 1)
+                                       continue;
+
+                       if (cansend == 0) {
+                               if(MyClient(sptr) && check_for_target_limit(sptr, chptr, chptr->chname))
+                                       continue;
+                               if (parv[2][0] == '`')
+                               {
+                                       sendanyways = 1;
+                               }
+                                       else sendanyways = 0;
+                               if (!(chptr->mode.mode & MODE_STRIP))
+                                       sendto_channel_butone(cptr, sptr, chptr,
+                                                     ":%s %s %s :%s",
+                                                     parv[0], cmd, nick,
+                                                     parv[2]);
+                               else
+                                       sendto_channel_butone(cptr, sptr, chptr,
+                                                     ":%s %s %s :%s",
+                                                     parv[0], cmd, nick,
+                                                     StripColors(parv[2]));
+                               
+                               sendanyways = 0;
+                       }
+                       else if (!notice)
+                               sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN),
+                                          me.name, parv[0], nick, err_cantsend[cansend-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 (!(s = (char *)rindex(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[2]);
+                       continue;
+                   }
+       
+               /*
+               ** user[%host]@server addressed?
+               */
+               if ((server = (char *)index(nick, '@')) &&
+                   (acptr = find_server(server + 1, NULL)))
+                   {
+                       /*
+                       ** Not destined for a user on me :-(
+                       */
+                       if (!IsMe(acptr))
+                           {
+                               sendto_one(acptr,":%s %s %s :%s", parv[0],
+                                          cmd, nick, parv[2]);
+                               continue;
+                           }
+
+                       /*
+                       ** Find the nick@server using hash.
+                       */
+                       acptr = find_nickserv(nick, (aClient *)NULL);
+                       if (acptr) {
+                               sendto_prefix_one(acptr, sptr,
+                                                 ":%s %s %s :%s",
+                                                 parv[0], cmd,
+                                                 acptr->name,
+                                                 parv[2]);
+                               continue;
+                       }
+                   }
+               if (server && strncasecmp(server+1, SERVICES_NAME, 
+                   strlen(SERVICES_NAME))==0)
+                       sendto_one(sptr, err_str(ERR_SERVICESDOWN), 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[2] = message text
+*/
+
+int    m_private(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       return m_message(cptr, sptr, parc, parv, 0);
+}
+
+
+/*
+ * Built in services aliasing for ChanServ, Memoserv, NickServ and
+ * OperServ. This not only is an alias, but is also a security measure,
+ * because PRIVMSG's arent sent to 'ChanServ' they are now sent to
+ * 'ChanServ@Services.Network.Org' so nobody can snoop /cs commands :)
+ */
+
+int    m_chanserv(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2 || *parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+       }
+
+       if ((acptr = find_person(ChanServ, NULL)))
+               sendto_one(acptr,":%s PRIVMSG %s@%s :%s", parv[0], 
+                       ChanServ, SERVICES_NAME, parv[1]);
+       else
+               sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                       parv[0], ChanServ);
+}
+
+int    m_memoserv(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2 || *parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+       }
+
+       if ((acptr = find_person(MemoServ, NULL)))
+               sendto_one(acptr,":%s PRIVMSG %s@%s :%s", parv[0], 
+                       MemoServ, SERVICES_NAME, parv[1]);
+       else
+               sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                       parv[0], MemoServ);
+}
+
+int    m_nickserv(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2 || *parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+       }
+
+       if ((acptr = find_person(NickServ, NULL)))
+               sendto_one(acptr,":%s PRIVMSG %s@%s :%s", parv[0], 
+                       NickServ, SERVICES_NAME, parv[1]);
+       else
+               sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                       parv[0], NickServ);
+}
+
+int    m_operserv(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2 || *parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+       }
+       if ((acptr = find_person(OperServ, NULL)))
+               sendto_one(acptr,":%s PRIVMSG %s@%s :%s", parv[0], 
+                       OperServ, SERVICES_NAME, parv[1]);
+       else
+               sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                       parv[0], OperServ);
+}
+
+int     m_helpserv(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        aClient *acptr;
+
+        if (check_registered_user(sptr))
+                return 0;
+
+        if (parc < 2 || *parv[1] == '\0') {
+                sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+                return -1;
+        }
+
+        if ((acptr = find_person(HelpServ, NULL)))
+                sendto_one(acptr,":%s PRIVMSG %s@%s :%s", parv[0],
+                        HelpServ, SERVICES_NAME, parv[1]);
+        else
+                sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                        parv[0], HelpServ);
+}
+
+int     m_statserv(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+
+       aClient *acptr;
+        
+
+        if (check_registered_user(sptr))
+                return 0;
+
+        if (parc < 2 || *parv[1] == '\0') {
+                sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+                return -1;
+        }
+
+        if ((acptr = find_person(StatServ, NULL)))
+#ifndef STATSERV_ABSOLUTE
+                       if (!strncmp(acptr->srvptr->name, STATS_SERVER, strlen(STATS_SERVER)))
+                       {
+                           sendto_one(acptr,":%s PRIVMSG %s :%s", parv[0],
+                        StatServ, parv[1]);
+                       }
+                               else
+                       {
+                               sendto_one(sptr, ":%s NOTICE %s :*** Couldn't send to %s due to my setting of StatServ is not equal to what server it is on", me.name, sptr->name,
+                                       StatServ);
+                               return;
+                       }
+#else
+                sendto_one(acptr,":%s PRIVMSG %s@%s :%s", parv[0],
+                        StatServ, STATS_SERVER, parv[1]);
+#endif
+        else
+                sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                        parv[0], StatServ);
+}
+
+
+/* 
+ * Automatic NickServ/ChanServ direction for the identify command
+ * -taz
+ */
+int    m_identify(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2 || *parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+       }
+
+       if (*parv[1]) {
+               if((*parv[1] == '#') && ((char *)index(parv[1], ' '))) {
+                       if ((acptr = find_person(ChanServ, NULL)))
+                               sendto_one(acptr,":%s PRIVMSG %s@%s :IDENTIFY %s", parv[0], 
+                                       ChanServ, SERVICES_NAME, parv[1]);
+                       else
+                               sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                                       parv[0], ChanServ);
+               } else {
+                       if ((acptr = find_person(NickServ, NULL)))
+                               sendto_one(acptr,":%s PRIVMSG %s@%s :IDENTIFY %s", parv[0],
+                                       NickServ, SERVICES_NAME, parv[1]);
+                       else
+                               sendto_one(sptr, err_str(ERR_SERVICESDOWN), me.name,
+                                       parv[0], NickServ);
+               }
+       }
+}
+
+/*
+ * Automatic NickServ/ChanServ parsing. If the second word of parv[1]
+ * starts with a '#' this message goes to ChanServ. If it starts with 
+ * anything else, it goes to NickServ. If there is no second word in 
+ * parv[1], the message defaultly goes to NickServ. If parv[1] == 'help'
+ * the user in instructed to /cs, /ns or /ms HELP for the help they need.
+ * -taz
+ */
+
+int    m_services(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       char *tmps;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2 || *parv[1] == '\0') {
+               sendto_one(sptr, err_str(ERR_NOTEXTTOSEND), me.name, parv[0]);
+               return -1;
+       }
+
+       if ((strlen(parv[1])>=4) && (!strncmp(parv[1], "help", 4))) {
+               sendto_one(sptr, ":Services!Services@%s NOTICE %s :For ChanServ help use: /chanserv help", SERVICES_NAME, sptr->name);
+               sendto_one(sptr, ":Services!Services@%s NOTICE %s :For NickServ help use: /nickserv help", SERVICES_NAME, sptr->name);
+               sendto_one(sptr, ":Services!Services@%s NOTICE %s :For MemoServ help use: /memoserv help", SERVICES_NAME, sptr->name);
+                sendto_one(sptr, ":Services!Services@%s NOTICE %s :For HelpServ help use: /helpserv help", SERVICES_NAME, sptr->name);
+
+               return;
+       }
+
+       if ((tmps = (char *)index(parv[1], ' '))) {
+               tmps++;
+               if(*tmps == '#')
+                       return m_chanserv(cptr, sptr, parc, parv);
+               else
+                       return m_nickserv(cptr, sptr, parc, parv);
+       }
+
+       return m_nickserv(cptr, sptr, parc, parv);
+
+}
+
+/*
+** m_notice
+**     parv[0] = sender prefix
+**     parv[1] = receiver list
+**     parv[2] = notice text
+*/
+
+int    m_notice(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       if (!IsRegistered(cptr) && (cptr->name[0]) && !IsNotSpoof(cptr))
+       {
+               if (BadPtr(parv[1])) return 0;
+#ifdef NOSPOOF
+               if (strtoul(parv[1], NULL, 16) != cptr->nospoof)
+                       goto temp;
+               sptr->nospoof = 0;
+#endif
+               if (sptr->user && sptr->name[0])
+                       return register_user(cptr, sptr, sptr->name,
+                               sptr->user->username, NULL, NULL);
+               return 0;
+       }
+       temp:
+       return m_message(cptr, sptr, parc, parv, 1);
+}
+
+int channelwho = 0;
+
+static void    do_who(sptr, acptr, repchan)
+aClient *sptr, *acptr;
+aChannel *repchan;
+{
+       char    status[5];
+       int     i = 0;
+
+       if (acptr->user->away)
+               status[i++] = 'G';
+       else
+               status[i++] = 'H';
+       /* Check for +H here too -- codemastr */
+       if (IsAnOper(acptr) && !IsHideOper(acptr))
+               status[i++] = '*';
+       else if (IsInvisible(acptr) && sptr != acptr && IsAnOper(sptr))
+               status[i++] = '%';
+       if (repchan && is_chan_op(acptr, repchan))
+               status[i++] = '@';
+       else if (repchan && has_voice(acptr, repchan))
+               status[i++] = '+';
+       status[i] = '\0';
+       if (IsWhois(acptr) && channelwho == 0) {
+               sendto_one(acptr, ":%s NOTICE %s :*** %s either did a /who or a specific /who on you", me.name, acptr->name, sptr->name);
+       }
+       sendto_one(sptr, rpl_str(RPL_WHOREPLY), me.name, sptr->name,
+                  (repchan) ? (repchan->chname) : "*", acptr->user->username,
+                  IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost, acptr->user->server, acptr->name,
+                  status, acptr->hopcount, acptr->info);
+
+}
+
+
+/*
+** m_who
+**     parv[0] = sender prefix
+**     parv[1] = nickname mask list
+**     parv[2] = additional selection flag, only 'o' for now.
+*/
+int    m_who(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    aClient *acptr;
+       Reg2    char    *mask = parc > 1 ? parv[1] : NULL;
+       Reg3    Link    *lp;
+       aChannel *chptr;
+       aChannel *mychannel;
+       char    *channame = NULL, *s;
+       int     oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
+       int     member;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (!BadPtr(mask))
+           {
+               if ((s = (char *)index(mask, ',')))
+                   {
+                       parv[1] = ++s;
+                       (void)m_who(cptr, sptr, parc, parv);
+                   }
+               clean_channelname(mask);
+           }
+       channelwho = 0;
+       mychannel = NullChn;
+    if (oper) {
+       sendto_helpops("from %s: [Did a /who 0 o]", parv[0]);
+               sendto_serv_butone(&me, ":%s HELP :[Did a /who 0 o]", parv[0]);
+    }
+       if (sptr->user)
+               if ((lp = sptr->user->channel))
+                       mychannel = lp->value.chptr;
+
+       /* Allow use of m_who without registering */
+       
+       /*
+       **  Following code is some ugly hacking to preserve the
+       **  functions of the old implementation. (Also, people
+       **  will complain when they try to use masks like "12tes*"
+       **  and get people on channel 12 ;) --msa
+       */
+       if (!mask || *mask == '\0')
+               mask = NULL;
+       else if (mask[1] == '\0' && mask[0] == '*')
+           {
+               mask = NULL;
+               if (mychannel)
+                       channame = mychannel->chname;
+           }
+       else if (mask[1] == '\0' && mask[0] == '0') /* "WHO 0" for irc.el */
+               mask = NULL;
+       else
+               channame = mask;
+       (void)collapse(mask);
+
+       if (IsChannelName(channame))
+           {
+               /*
+                * List all users on a given channel
+                */
+               chptr = find_channel(channame, NULL);
+               if (chptr)
+                 {
+                   member = IsMember(sptr, chptr);
+                   if (member || !SecretChannel(chptr))
+                       for (lp = chptr->members; lp; lp = lp->next)
+                           {
+                               if (oper && (!IsAnOper(lp->value.cptr) || IsHideOper(lp->value.cptr)))
+                                       continue;
+                               if (IsHiding(lp->value.cptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+                                       continue;                               
+                               if (lp->value.cptr!=sptr && IsInvisible(lp->value.cptr) && !member)
+                                       continue;
+                               channelwho = 1;
+                               do_who(sptr, lp->value.cptr, chptr);
+                           }
+                 }
+           }
+       else for (acptr = client; acptr; acptr = acptr->next)
+           {
+               aChannel *ch2ptr = NULL;
+               int     showperson, isinvis;
+
+               if (!IsPerson(acptr))
+                       continue;
+               if (oper && (!IsAnOper(acptr) || IsHideOper(acptr)))
+                       continue;
+               showperson = 0;
+               /*
+                * Show user if they are on the same channel, or not
+                * invisible and on a non secret channel (if any).
+                * Do this before brute force match on all relevant fields
+                * since these are less cpu intensive (I hope :-) and should
+                * provide better/more shortcuts - avalon
+                */
+               isinvis = acptr!=sptr && IsInvisible(acptr) && !IsAnOper(sptr);
+               for (lp = acptr->user->channel; lp; lp = lp->next)
+                   {
+                       chptr = lp->value.chptr;
+                       member = IsMember(sptr, chptr);
+                       if (isinvis && !member)
+                               continue;
+                       if (IsAnOper(sptr)) showperson = 1;
+                       if (member || (!isinvis && 
+                               ShowChannel(sptr, chptr)))
+                           {
+                               ch2ptr = chptr;
+                               showperson = 1;
+                               break;
+                           }
+                       if (HiddenChannel(chptr) && !SecretChannel(chptr) &&
+                           !isinvis)
+                               showperson = 1;
+                   }
+               if (!acptr->user->channel && !isinvis)
+                       showperson = 1;
+               /*
+               ** This is brute force solution, not efficient...? ;( 
+               ** Show entry, if no mask or any of the fields match
+               ** the mask. --msa
+               */
+               if (showperson &&
+                   (!mask ||
+                    match(mask, acptr->name) == 0 ||
+                    match(mask, acptr->user->username) == 0 ||
+                    (!IsAnOper(sptr) || match(mask, acptr->user->realhost)) == 0 ||
+                    (!IsHidden(acptr) || match(mask, acptr->user->virthost)) == 0 ||
+                    (IsHidden(acptr) || match(mask, acptr->user->realhost)) == 0 ||
+                    match(mask, acptr->user->server) == 0 ||
+                    match(mask, acptr->info) == 0))
+                       do_who(sptr, acptr, ch2ptr);
+           }
+       sendto_one(sptr, rpl_str(RPL_ENDOFWHO), me.name, parv[0],
+                  BadPtr(mask) ?  "*" : mask);
+       return 0;
+}
+
+/*
+** get_mode_str
+** by vmlinuz
+** returns an ascii string of modes
+*/
+char *get_mode_str (aClient *acptr)
+{
+        Reg1    int     flag;
+        Reg2    int     *s;
+        Reg3    char    *m;
+
+               m = buf;
+                *m++ = '+';
+                for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4);
+                     s += 2)
+                        if ((acptr->umodes & flag))
+                                *m++ = (char)(*(s+1));
+                *m = '\0';
+       return buf;
+}
+
+/*
+** m_whois
+**     parv[0] = sender prefix
+**     parv[1] = nickname masklist
+*/
+int    m_whois(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       static anUser UnknownUser =
+           {
+               NULL,   /* nextu */
+               NULL,   /* channel */
+               NULL,   /* invited */
+               NULL,   /* silence */
+               NULL,   /* away */
+               0,      /* last */
+               0,      /* servicestamp */
+               1,      /* refcount */
+               0,      /* joined */
+               "<Unknown>",    /* username */
+               "<Unknown>",    /* host */
+               "<Unknown>"     /* server */
+           };
+       Reg2    Link    *lp;
+       Reg3    anUser  *user;
+       aClient *acptr, *a2cptr;
+       aChannel *chptr;
+       char    *nick, *tmp, *name, *temp;
+       char    *p = NULL;
+       int     found, len, mlen, t;
+
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       if (parc < 2)
+           {
+               sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
+                          me.name, parv[0]);
+               return 0;
+           }
+
+       if (parc > 2)
+           {
+               if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) !=
+                   HUNTED_ISME)
+                       return 0;
+               parv[1] = parv[2];
+           }
+
+       for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL)
+           {
+               int     invis, showperson, member, wilds;
+
+               found = 0;
+               (void)collapse(nick);
+               wilds = (index(nick, '?') || index(nick, '*'));
+               if (wilds) continue;
+               
+               for (acptr = client; (acptr = next_client(acptr, nick));
+                    acptr = acptr->next)
+                   {
+                       if (IsServer(acptr))
+                               continue;
+                       /*
+                        * I'm always last :-) and acptr->next == NULL!!
+                        */
+                       if (IsMe(acptr))
+                               break;
+                       /*
+                        * 'Rules' established for sending a WHOIS reply:
+                        *
+                        * - only allow a remote client to get replies for
+                        *   local clients if wildcards are being used;
+                        *
+                        * - 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;
+                        */
+                       if (!MyConnect(sptr) && !MyConnect(acptr) && wilds)
+                               continue;
+                       user = acptr->user ? acptr->user : &UnknownUser;
+                       name = (!*acptr->name) ? "?" : acptr->name;
+
+                       invis = acptr!=sptr && IsInvisible(acptr);
+                       member = (user->channel) ? 1 : 0;
+                       showperson = (wilds && !invis && !member) || !wilds;
+                       
+                       for (lp = user->channel; lp; lp = lp->next)
+                           {
+                               chptr = lp->value.chptr;
+                               member = IsMember(sptr, chptr);
+                               if (invis && !member)
+                                       continue;
+                               if (member || (!invis && PubChannel(chptr)))
+                                   {
+                                       showperson = 1;
+                                       break;
+                                   }
+                               if (!invis && HiddenChannel(chptr) &&
+                                   !SecretChannel(chptr))
+                                       showperson = 1;
+                           }
+                       if (!showperson)
+                               continue;
+                       a2cptr = find_server(user->server, NULL);
+
+                       if (!IsPerson(acptr))
+                               continue;
+                       
+                        if (IsWhois(acptr)) {
+                                sendto_one(acptr, ":%s NOTICE %s :*** %s (%s@%s) did a /whois on you.",
+                                        me.name, acptr->name,
+                                        sptr->name, sptr->user->username,
+                                        IsHidden(acptr) ? sptr->user->virthost : sptr->user->realhost);
+                                        }
+
+                        sendto_one(sptr, rpl_str(RPL_WHOISUSER), me.name,
+                                   parv[0], name,
+                                   user->username, IsHidden(acptr) ? user->virthost : user->realhost,
+                                   acptr->info);
+  
+                        if (IsEyes(sptr))
+                        {
+                                /* send the target user's modes */
+                                sendto_one(sptr, rpl_str(RPL_WHOISMODES),
+                                        me.name, parv[0], name,
+                                        get_mode_str(acptr));
+                        }
+                        if (IsAnOper(sptr) && IsHidden(acptr) || 
+                               acptr == sptr && IsHidden(sptr)) {
+                        sendto_one(sptr, rpl_str(RPL_WHOISHOST), me.name,
+                                   parv[0], acptr->name, acptr->user->realhost);
+                                                }
+                       if (IsARegNick(acptr))
+                               sendto_one(sptr, rpl_str(RPL_WHOISREGNICK),
+                                          me.name, parv[0], name);
+                       found = 1;
+                       mlen = strlen(me.name) + strlen(parv[0]) + 6 +
+                               strlen(name);
+                       for (len = 0, *buf = '\0', lp = user->channel; lp;
+                            lp = lp->next)
+                           {
+                               chptr = lp->value.chptr;
+                               if (ShowChannel(sptr, chptr) &&
+                                   (acptr==sptr || IsMember(acptr, chptr)))
+                                   {
+                                       if (len + strlen(chptr->chname)
+                                            > (size_t) BUFSIZE - 4 - mlen)
+                                           {
+                                               sendto_one(sptr,
+                                                          ":%s %d %s %s :%s",
+                                                          me.name,
+                                                          RPL_WHOISCHANNELS,
+                                                          parv[0], name, buf);
+                                               *buf = '\0';
+                                               len = 0;
+                                           }
+                                       if (is_chanowner(acptr, chptr))
+                                               *(buf + len++) = '*';
+                                       else if (is_chanprot(acptr, chptr))
+                                               *(buf + len++) = '^';
+                                       else if (is_chan_op(acptr, chptr))
+                                               *(buf + len++) = '@';
+                                       else if (has_voice(acptr, chptr))
+                                               *(buf + len++) = '+';
+                                       else if (is_half_op(acptr, chptr))
+                                               *(buf + len++) = '%';
+                                       if (len)
+                                               *(buf + len) = '\0';
+                                       (void)strcpy(buf + len, chptr->chname);
+                                       len += strlen(chptr->chname);
+                                       (void)strcat(buf + len, " ");
+                                       len++;
+                                   }
+                           }
+
+                        if (IsULine(acptr, acptr))
+                               goto next;
+                        
+                        if (IsHiding(acptr) && sptr != acptr && !IsNetAdmin(sptr) && !IsTechAdmin(sptr))
+                               goto next;
+                               
+                       if (buf[0] != '\0')
+                               sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS),
+                                          me.name, parv[0], name, buf);
+
+                       next:
+                       sendto_one(sptr, rpl_str(RPL_WHOISSERVER),
+                                  me.name, parv[0], name, user->server,
+                                  a2cptr?a2cptr->info:"*Not On This Net*");
+
+                       if (user->away)
+                               sendto_one(sptr, rpl_str(RPL_AWAY), me.name,
+                                          parv[0], name, user->away);
+               /* makesure they aren't +H (we'll also check 
+               before we display a helpop or IRCD Coder msg) 
+               -- codemastr */
+                        if ((IsAnOper(acptr) || IsServices(acptr)) && !IsHideOper(acptr)) {
+                        buf[0]='\0';
+                             if (IsNetAdmin(acptr))
+                               strcat(buf, "a Network Administrator");
+                             else if (IsTechAdmin(acptr))
+                               strcat(buf, "a Technical Administrator");
+                              else if (IsSAdmin(acptr))
+                                strcat(buf, "a Services Operator");
+                              else if (IsAdmin(acptr) && !IsCoAdmin(acptr))
+                                strcat(buf, "a Server Administrator");
+                              else if (IsCoAdmin(acptr))
+                                strcat(buf, "a Co Administrator");
+                              else if (IsServices(acptr))
+                                strcat(buf, "a Network Service");
+                              else if (IsOper(acptr))
+                                strcat(buf, "an IRC Operator");
+
+                                                     else
+                                                               strcat(buf, "a Local IRC Operator");
+                   if(buf[0])
+                         sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
+                                me.name, parv[0], name, buf, ircnetwork);
+                                        }
+
+                        if (IsHelpOp(acptr) && !IsHideOper(acptr))
+                          if (!acptr->user->away)
+                           sendto_one(sptr, rpl_str(RPL_WHOISHELPOP),
+                                       me.name, parv[0], name);
+
+                       if (acptr->umodes & UMODE_BOT) {
+                               sendto_one(sptr, rpl_str(RPL_WHOISBOT),
+                                       me.name, parv[0], name, ircnetwork);
+                       }
+                       if (acptr->umodes & UMODE_CODER && !IsHideOper(acptr)) {
+                               sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR),
+                                       me.name, parv[0], name, "a \2Coder\2", ircnetwork);
+                       }
+                       if (acptr->user->swhois)
+                       {
+                               if (*acptr->user->swhois != '\0')
+                                       sendto_one(sptr, ":%s %d %s %s :%s", me.name, 
+                                               RPL_WHOISSPECIAL,
+                                               parv[0], name,
+                                               acptr->user->swhois);
+                       }
+
+                       if (acptr->user && MyConnect(acptr))
+                               sendto_one(sptr, rpl_str(RPL_WHOISIDLE),
+                                          me.name, parv[0], name,
+                                          TStime() - user->last,
+                                          acptr->firsttime);
+                   }
+               if (!found)
+                       sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+                                  me.name, parv[0], nick);
+               if (p)
+                       p[-1] = ',';
+           }
+       sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS), me.name, parv[0], parv[1]);
+
+       return 0;
+}
+
+/*
+** m_user
+**     parv[0] = sender prefix
+**     parv[1] = username (login name, account)
+**     parv[2] = client host name (used only from other servers)
+**     parv[3] = server host name (used only from other servers)
+**     parv[4] = users real name info
+*/
+int    m_user(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+#define        UFLAGS  (UMODE_INVISIBLE|UMODE_WALLOP|UMODE_SERVNOTICE)
+       char    *username, *host, *server, *realname, *umodex = NULL, *virthost = NULL;
+       u_int32_t sstamp = 0;
+       anUser  *user;
+       char    *mparv[] = {sptr->name, sptr->name, NULL};
+       if (IsServer(cptr) && !IsUnknown(sptr))
+               return 0;
+
+       if (parc > 2 && (username = (char *)index(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");
+               if (IsServer(cptr))
+                       sendto_ops("bad USER param count for %s from %s",
+                                  parv[0], get_client_name(cptr, FALSE));
+               else
+                       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];
+
+       /* This we can remove as soon as all servers have upgraded. */
+
+       if (parc == 6 && IsServer(cptr)) {
+               if (isdigit(*parv[4]))
+                       sstamp = atol(parv[4]);
+               realname = (BadPtr(parv[5])) ? "<bad-realname>" : parv[5];
+               umodex = NULL;
+       } else if (parc == 8 && IsServer(cptr))
+       {
+               if (isdigit(*parv[4]))
+                       sstamp = atol(parv[4]);
+               realname = (BadPtr(parv[7])) ? "<bad-realname>" : parv[7];
+               umodex = parv[5];
+               virthost = parv[6];
+       } else
+       {
+               realname = (BadPtr(parv[4])) ? "<bad-realname>" : parv[4];
+       }
+       user = make_user(sptr);
+
+       if (!MyConnect(sptr))
+           {
+               if (sptr->srvptr == NULL)
+                       sendto_ops("WARNING, User %s introduced as being "
+                               "on non-existant server %s.", sptr->name,
+                               server);
+               strncpyzt(user->server, server, sizeof(user->server));
+               strncpyzt(user->realhost, host, sizeof(user->realhost));
+               strncpyzt(user->realhost, host, sizeof(user->realhost));
+               goto user_finish;
+           }
+
+       if (!IsUnknown(sptr))
+           {
+               sendto_one(sptr, err_str(ERR_ALREADYREGISTRED),
+                          me.name, parv[0]);
+               return 0;
+           }
+       if (!IsServer(cptr))
+       {
+               if (MODE_I == 1)
+                       sptr->umodes |= UMODE_INVISIBLE;
+               if (MODE_X == 1) {
+                       sptr->umodes |= (UMODE_HIDE);
+                       SetHidden(sptr);
+               }
+       }
+       
+       sptr->umodes |= (UFLAGS & atoi(host));
+
+       strncpyzt(user->realhost, host, sizeof(user->realhost));
+       strncpyzt(user->realhost, host, sizeof(user->realhost));
+       strncpyzt(user->server, me.name, sizeof(user->server));
+user_finish:
+       user->servicestamp = sstamp;
+       strncpyzt(sptr->info, realname, sizeof(sptr->info));
+       if (sptr->name[0] && (IsServer(cptr) ? 1 : IsNotSpoof(sptr)))
+       /* NICK and no-spoof already received, now we have USER... */
+       {
+               int xx;
+
+               xx = register_user(cptr, sptr, sptr->name, username, umodex, virthost);
+               return xx;
+       }
+       else
+               strncpyzt(sptr->user->username, username, USERLEN+1);
+
+       return 0;
+}
+
+/*
+** m_quit
+**     parv[0] = sender prefix
+**     parv[1] = comment
+*/
+int    m_quit(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       char *ocomment = (parc > 1 && parv[1]) ? parv[1] : parv[0];
+       static char comment[TOPICLEN];
+
+       if (!IsServer(cptr)) {
+               sprintf(comment, "Quit: ");
+               strncpy(comment+6,ocomment,TOPICLEN-7);
+               comment[TOPICLEN] = '\0';
+               return exit_client(cptr, sptr, sptr, comment);
+       } else
+               return exit_client(cptr, sptr, sptr, ocomment);
+    }
+
+
+/*
+** m_kill
+**     parv[0] = sender prefix
+**     parv[1] = kill victim(s) - comma separated list
+**     parv[2] = kill path
+*/
+int    m_kill(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       static anUser UnknownUser =
+           {
+               NULL,   /* nextu */
+               NULL,   /* channel */
+               NULL,   /* invited */
+               NULL,   /* silence */
+               NULL,   /* away */
+               0,      /* last */
+               0,      /* servicestamp */
+               1,      /* refcount */
+               0,      /* joined */
+               "<Unknown>",    /* username */
+               "<Unknown>",    /* host */
+               "<Unknown>"     /* server */
+           };
+       aClient *acptr;
+       anUser  *auser;
+        char    inpath[HOSTLEN * 2 + USERLEN + 5];
+       char    *oinpath = get_client_name(cptr,FALSE);
+       char    *user, *path, *killer, *nick, *p, *s;
+       int     chasing = 0, kcount = 0;
+
+
+        if (check_registered(sptr))
+                return 0;
+
+       if (parc < 2 || *parv[1] == '\0')
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "KILL");
+               return 0;
+           }
+
+       user = parv[1];
+       path = parv[2]; /* Either defined or NULL (parc >= 2!!) */
+
+        strcpy(inpath, oinpath);
+
+#ifndef ROXnet
+       if (IsServer(cptr) && (s = (char *)index(inpath, '.')) != NULL)
+               *s = '\0';      /* Truncate at first "." */
+#endif
+
+       if (!IsPrivileged(cptr))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               return 0;
+           }
+       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 (MyClient(sptr))
+               user = canonize(user);
+
+       for (p = NULL, nick = strtoken(&p, user, ","); nick;
+               nick = strtoken(&p, NULL, ","))
+       {
+
+       chasing = 0;
+
+       if (!(acptr = find_client(nick, NULL)))
+           {
+               /*
+               ** 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(nick, (long)KILLCHASETIMELIMIT)))
+                   {
+                       sendto_one(sptr, err_str(ERR_NOSUCHNICK),
+                                  me.name, parv[0], nick);
+                       continue;
+                   }
+               sendto_one(sptr,":%s NOTICE %s :KILL changed from %s to %s",
+                          me.name, parv[0], nick, acptr->name);
+               chasing = 1;
+           }
+       if ((!MyConnect(acptr) && MyClient(cptr) && !OPCanGKill(cptr)) ||
+           (MyConnect(acptr) && MyClient(cptr) && !OPCanLKill(cptr)))
+           {
+               sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
+               continue;
+           }
+       if (IsServer(acptr) || IsMe(acptr))
+           {
+               sendto_one(sptr, err_str(ERR_CANTKILLSERVER),
+                          me.name, parv[0]);
+               continue;
+           }
+
+       if (IsServices(acptr) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr) || IsULine(cptr, sptr)))
+       {
+                       sendto_one(sptr, err_str(ERR_KILLDENY), me.name, parv[0], parv[1]);
+                       return 0;
+       }
+/*        if (IsULine(cptr, sptr) || (IsSAdmin(sptr) && !IsSAdmin(acptr)) || (IsNetAdmin(sptr)) || (IsTechAdmin(sptr) || (IsCoAdmin(sptr)))) {
+        goto aftermath;
+        } else if (IsULine(cptr, acptr)) {
+                goto error;
+        } else {
+                goto aftermath;
+        }
+
+        error:
+
+                return 0;
+*/
+        aftermath:
+
+       /* From here on, the kill is probably going to be successful. */
+
+       kcount++;
+
+       if (!IsServer(sptr) && (kcount > MAXKILLS))
+       {
+         sendto_one(sptr,":%s NOTICE %s :Too many targets, kill list was truncated. Maximum is %d.",me.name, parv[0], MAXKILLS);
+         break;
+       }
+       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)
+               */
+               if (IsUnixSocket(cptr)) /* Don't use get_client_name syntax */
+                        strcpy(inpath, me.name);
+                else
+                        strcpy(inpath, IsHidden(cptr) ? cptr->user->virthost : cptr->user->realhost);
+               if (kcount < 2) /* Only check the path the first time 
+                                  around, or it gets appended to itself. */
+                if (!BadPtr(path))
+                   {
+                       (void)sprintf(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.
+       */
+
+       auser = acptr->user ? acptr->user : &UnknownUser;
+
+        if (index(parv[0], '.'))
+                sendto_umode(UMODE_KILLS, "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s",
+                        acptr->name, auser->username, 
+                        IsHidden(acptr) ? auser->virthost : auser->realhost,
+                        parv[0], inpath, path);
+#ifdef SHOWREALHOSTATKILL
+                               sendto_umode(UMODE_EYES, "*** /kill victim was %s!%s@%s", acptr->name, auser->username, auser->realhost);
+#endif
+        else
+                sendto_umode(UMODE_KILLS, "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s",
+                        acptr->name, auser->username,
+                                               IsHidden(acptr) ? auser->virthost : auser->realhost,                       
+                        parv[0], inpath, path);
+#if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
+       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_serv_butone(cptr, ":%s KILL %s :%s!%s",
+                                   parv[0], acptr->name, inpath, path);
+                if (chasing && IsServer(cptr))
+                        sendto_one(cptr, ":%s KILL %s :%s!%s",
+                                   me.name, acptr->name, 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))
+               (void)sprintf(buf2, "[%s] Local kill by %s (%s)", me.name, sptr->name,
+                       BadPtr(parv[2]) ? sptr->name : parv[2]);
+       else
+           {
+               if ((killer = index(path, ' ')))
+                   {
+                       while (*killer && *killer != '!')
+                               killer--;
+                       if (!*killer)
+                               killer = path;
+                       else
+                               killer++;
+                   }
+               else
+                       killer = path;
+               (void)sprintf(buf2, "Killed (%s)", killer);
+           }
+           if(exit_client(cptr, acptr, sptr, buf2) == FLUSH_BUFFER)
+               return FLUSH_BUFFER;
+       }
+       return 0;
+}
+
+/***********************************************************************
+ * m_away() - Added 14 Dec 1988 by jto. 
+ *            Not currently really working, I don't like this
+ *            call at all...
+ *
+ *            ...trying to make it work. I don't like it either,
+ *           but perhaps it's worth the load it causes to net.
+ *           This requires flooding of the whole net like NICK,
+ *           USER, MODE, etc messages...  --msa
+ ***********************************************************************/
+
+/*
+** m_away
+**     parv[0] = sender prefix
+**     parv[1] = away message
+*/
+int    m_away(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    char    *away, *awy2 = parv[1];
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       away = sptr->user->away;
+       if (parc < 2 || !*awy2)
+           {
+               /* Marking as not away */
+
+               if (away)
+                   {
+                       MyFree(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';
+
+       if (away)
+               if (strcmp(away, parv[1])==0)
+               {
+                       return 0;
+               }
+       sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2);
+
+       if (away)
+               away = (char *)MyRealloc(away, strlen(awy2)+1);
+       else
+               away = (char *)MyMalloc(strlen(awy2)+1);
+
+       sptr->user->away = away;
+       (void)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(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       char    *origin, *destination;
+
+        if (check_registered(sptr))
+                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]; /* Will get NULL or pointer (parc >= 2!!) */
+
+       acptr = find_client(origin, NULL);
+       if (!acptr)
+               acptr = find_server(origin, NULL);
+       if (acptr && acptr != sptr)
+               origin = cptr->name;
+       if (!BadPtr(destination) && mycmp(destination, me.name) != 0)
+           {
+               if ((acptr = find_server(destination, NULL)))
+                       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,
+                          (destination) ? destination : me.name, origin);
+       return 0;
+    }
+
+#ifdef NOSPOOF
+/*
+** m_nospoof - allows clients to respond to no spoofing patch
+**     parv[0] = prefix
+**     parv[1] = code
+*/
+int    m_nospoof(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+unsigned long result;
+
+       if (IsNotSpoof(cptr)) return 0;
+       if (IsRegistered(cptr)) return 0;
+       if (!*sptr->name) return 0;
+       if (BadPtr(parv[1])) goto temp;
+       result = strtoul(parv[1], NULL, 16);
+       /* Accept code in second parameter (ircserv) */
+       if (result != sptr->nospoof)
+       {
+               if (BadPtr(parv[2])) goto temp;
+               result = strtoul(parv[2], NULL, 16);
+               if (result != sptr->nospoof) goto temp;
+       }
+       sptr->nospoof = 0;
+       if (sptr->user && sptr->name[0])
+               return register_user(cptr, sptr, sptr->name,
+                       sptr->user->username, NULL, NULL);
+       return 0;
+       temp:
+       /* Homer compatibility */
+       sendto_one(cptr, ":%X!nospoof@%s PRIVMSG %s :%cVERSION%c",
+               cptr->nospoof, me.name, cptr->name, (char) 1, (char) 1);
+       return 0;
+}
+#endif /* NOSPOOF */
+
+/*
+** m_pong
+**     parv[0] = sender prefix
+**     parv[1] = origin
+**     parv[2] = destination
+*/
+int    m_pong(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       char    *origin, *destination;
+
+#ifdef NOSPOOF
+       if (!IsRegistered(cptr))
+               return m_nospoof(cptr, sptr, parc, parv);
+#endif
+
+       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) && mycmp(destination, me.name) != 0)
+           {
+               if ((acptr = find_client(destination, NULL)) ||
+                   (acptr = find_server(destination, NULL)))
+               {
+                       if (!IsServer(cptr) && !IsServer(acptr))
+                       {
+                               sendto_one(sptr, err_str(ERR_NOSUCHSERVER),
+                                       me.name, parv[0], destination);
+                               return 0;
+                       }
+                       else
+                       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;
+    }
+
+/*
+** m_mkpasswd
+**     parv[0] = sender prefix
+**     parv[1] = password to encrypt
+*/
+#ifndef _WIN32
+int     m_mkpasswd(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+  static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+  char salt[3];
+  extern  char *crypt();
+  int i;
+  int useable = 0;
+
+  if (!IsAnOper(sptr))
+       return -1;
+  if (parc > 1)
+       {
+               if (strlen(parv[1]) >= 1)
+                       useable = 1;
+       }
+
+  if (useable == 0)
+       {
+               sendto_one(sptr, ":%s NOTICE %s :*** Encryption's MUST be atleast 1 character in length", me.name, parv[0]);
+                return 0;
+       }
+    srandom(time(0));           
+    salt[0] = saltChars[random() % 64];
+    salt[1] = saltChars[random() % 64];
+    salt[2] = 0;
+
+    if ((strchr(saltChars, salt[0]) == NULL) || (strchr(saltChars, salt[1]) == NULL))
+       {
+       sendto_one(sptr, ":%s NOTICE %s :*** Illegal salt %s", me.name, parv[0], salt);
+               return 0;
+       }
+
+
+  sendto_one(sptr, ":%s NOTICE %s :*** Encryption for [%s] is %s", me.name, parv[0], parv[1], crypt(parv[1], salt));
+  return 0;
+}
+
+#else
+int     m_mkpasswd(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+    {
+            sendto_one(sptr, ":%s NOTICE %s :*** Encryption is disabled on UnrealIRCD-win32",
+                            me.name, parv[0]);
+            return 0;
+    }
+                                                
+#endif
+
+/*
+** m_oper
+**     parv[0] = sender prefix
+**     parv[1] = oper name
+**     parv[2] = oper password
+*/
+int    m_oper(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       aConfItem               *aconf;
+    aClient            *acptr;
+       char                    *name, *password, *encr;
+    anUser             *user = sptr->user;
+#ifdef CRYPT_OPER_PASSWORD
+       char                    salt[3];
+       extern char     *crypt();
+#endif /* CRYPT_OPER_PASSWORD */
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       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))
+       {
+               sptr->umodes |= UMODE_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 (IsOper(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((char *)&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);
+               sptr->since += 7;
+               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 && aconf->passwd[0] && aconf->passwd[1])
+       {
+       salt[0] = aconf->passwd[0];
+               salt[1] = aconf->passwd[1];
+               salt[2] = '\0';
+               encr = crypt(password, salt);
+       }
+               else
+       {
+               encr = "";
+       }
+#else /* CRYPT_OPER_PASSWORD */
+       encr = password;
+#endif  /* CRYPT_OPER_PASSWORD */
+
+       if ((aconf->status & CONF_OPS) && StrEq(encr, aconf->passwd)
+            && !attach_conf(sptr, aconf))
+       {
+               int old = (sptr->umodes & ALL_UMODES);
+               char *s;
+
+               s = index(aconf->host, '@');
+               *s++ = '\0';
+               if ((aconf->port & OFLAG_AGENT))
+                       sptr->umodes |= UMODE_AGENT;
+               if ((aconf->port & OFLAG_HELPOP))
+               {
+                       sptr->umodes |= UMODE_HELPOP;
+               }
+
+               if (!(aconf->port & OFLAG_ISGLOBAL))
+               {
+                       SetLocOp(sptr);
+               }
+                   else
+                       if (aconf->port & OFLAG_NETADMIN) {
+                       if (aconf->port & OFLAG_SADMIN) {
+                               sptr->umodes |= (UMODE_NETADMIN|UMODE_ADMIN|UMODE_SADMIN);
+                               SetNetAdmin(sptr);
+                               SetSAdmin(sptr);
+                               SetAdmin(sptr);
+                               SetOper(sptr);
+                       }
+                         else
+                       {
+                               sptr->umodes |= (UMODE_NETADMIN|UMODE_ADMIN);
+                               SetNetAdmin(sptr);
+                                       SetAdmin(sptr);
+                               SetOper(sptr);
+                               }  
+                       }
+                               else
+               if (aconf->port & OFLAG_COADMIN)
+               {
+                       if (aconf->port & OFLAG_SADMIN) {
+                               sptr->umodes |= (UMODE_COADMIN|UMODE_ADMIN|UMODE_SADMIN);
+                               SetCoAdmin(sptr);
+                               SetSAdmin(sptr);
+                                       SetAdmin(sptr);
+                               SetOper(sptr);
+                       }
+                               else
+                       {
+                               sptr->umodes |= (UMODE_COADMIN|UMODE_ADMIN);
+                               SetCoAdmin(sptr);
+                                       SetAdmin(sptr);
+                                       SetOper(sptr);
+                       }
+                       }
+                               else
+                       if (aconf->port & OFLAG_TECHADMIN)
+                       {
+                               if (aconf->port & OFLAG_SADMIN) {
+                               sptr->umodes |= (UMODE_TECHADMIN|UMODE_ADMIN|UMODE_SADMIN);
+                               SetTechAdmin(sptr);
+                               SetSAdmin(sptr);
+                               SetAdmin(sptr);
+                                       SetOper(sptr);
+                       }
+                               else
+                       {
+                               sptr->umodes |= (UMODE_TECHADMIN|UMODE_ADMIN);
+                                       SetTechAdmin(sptr);
+                                       SetAdmin(sptr);
+                               SetOper(sptr);
+                       }
+               }
+                       else
+               if (aconf->port & OFLAG_ADMIN && aconf->port & OFLAG_SADMIN) {
+                       sptr->umodes |= (UMODE_ADMIN|UMODE_SADMIN);
+                       SetAdmin(sptr);
+                       SetSAdmin(sptr);
+                       SetOper(sptr);
+               }
+                       else
+               if (aconf->port & OFLAG_SADMIN) {
+                       sptr->umodes |= (UMODE_SADMIN);
+                       SetSAdmin(sptr);
+                       SetOper(sptr);
+               } 
+                       else
+               if (aconf->port & OFLAG_ADMIN) {
+                       sptr->umodes |= (UMODE_ADMIN);
+                       SetAdmin(sptr);
+                       SetOper(sptr);
+               }
+                       else
+                       {
+                       if (aconf->port & OFLAG_SADMIN) {
+                       sptr->umodes |= (UMODE_OPER|UMODE_SADMIN);
+                               SetSAdmin(sptr);
+                       SetOper(sptr);
+               }
+                       else
+               {
+                       sptr->umodes |= (UMODE_OPER);
+                       SetOper(sptr);
+               }
+        }
+        
+        if (aconf->port & OFLAG_EYES)
+        {
+                       sptr->umodes |= (UMODE_EYES);
+                       SetEyes(sptr);
+       }
+               
+       if (aconf->port & OFLAG_WHOIS) {
+                       sptr->umodes |= (UMODE_WHOIS);
+       }
+               
+       if (aconf->port & OFLAG_HIDE) {
+                       sptr->umodes |= (UMODE_HIDE);
+       }
+               
+       sptr->oflag = aconf->port;
+               
+       *--s =  '@';
+               
+       sptr->umodes |= (UMODE_SERVNOTICE|UMODE_WALLOP|UMODE_FAILOP|UMODE_FLOOD|UMODE_CLIENT|UMODE_KILLS);
+       if (ALLOW_CHATOPS == 1)
+               sptr->umodes |= UMODE_CHATOP;
+
+       send_umode_out(cptr, sptr, old);
+#ifndef NO_FDLIST
+       addto_fdlist(sptr->fd, &oper_fdlist);
+#endif
+       sendto_one(sptr, rpl_str(RPL_YOUREOPER), me.name, parv[0]);
+
+        if (!(aconf->port & OFLAG_ISGLOBAL))
+        {
+                sendto_ops("%s (%s@%s) is now a local operator (o)", parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+               if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                       iNAH_host(sptr, locop_host);
+               sptr->umodes &= ~UMODE_OPER;
+        }
+               else
+        if ((aconf->port & OFLAG_AGENT))
+        {
+                       sendto_ops("%s (%s@%s) is now an IRCd Agent (S)", parv[0],
+                               sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+        }
+               else
+               if (aconf->port & OFLAG_NETADMIN)
+               {
+               sendto_ops("%s (%s@%s) is now a network administrator (N)", parv[0],
+               sptr->user->username, IsHidden(cptr) ? sptr->user->virthost : sptr->user->realhost);
+            if (MyClient (sptr))
+            {
+                sendto_serv_butone(&me, ":%s GLOBOPS :%s (%s@%s) is now a network administrator (N)", me.name, parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+                       }
+
+                       if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                               iNAH_host(sptr, netadmin_host);
+        }
+               else
+        if (aconf->port & OFLAG_COADMIN)
+        {
+                sendto_ops("%s (%s@%s) is now a co administrator (C)", parv[0],
+                          sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+                if (MyClient (sptr))
+                {
+          /*      sendto_serv_butone(&me, ":%s GLOBOPS :%s (%s@%s) is now a co administrator (C)", me.name, parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+            */
+                               }
+                               if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                                       iNAH_host(sptr, coadmin_host);
+         }
+               else
+         if (aconf->port & OFLAG_TECHADMIN) {
+               sendto_ops("%s (%s@%s) is now a technical administrator (T)", parv[0],
+                       sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+            if (MyClient (sptr))
+            {
+                sendto_serv_butone(&me, ":%s GLOBOPS :%s (%s@%s) is now a technical administrator (T)", me.name, parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+            }
+                       if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                               iNAH_host(sptr, techadmin_host);
+                 }
+               else
+             if (aconf->port & OFLAG_SADMIN)
+             {
+                 sendto_ops("%s (%s@%s) is now a services admin (a)", parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+              if (MyClient (sptr))
+              {
+                sendto_serv_butone(&me, ":%s GLOBOPS :%s (%s@%s) is now a services administrator (a)", me.name, parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+              }
+                         if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                               iNAH_host(sptr, sadmin_host);
+         }
+           else
+         if (aconf->port & OFLAG_ADMIN)
+         {
+                sendto_ops("%s (%s@%s) is now a server admin (A)", parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+                               if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                                       iNAH_host(sptr, admin_host);
+          }
+            else 
+          {
+                sendto_ops("%s (%s@%s) is now an operator (O)", parv[0],
+                           sptr->user->username, IsHidden(sptr) ? sptr->user->virthost : sptr->user->realhost);
+                               if (iNAH == 1 && (sptr->oflag & OFLAG_HIDE))
+                                       iNAH_host(sptr, oper_host);
+                       }
+               if (SHOWOPERMOTD == 1)
+                       m_opermotd(cptr, sptr, parc, parv);
+
+#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
+             {
+                int     logfile;
+
+                /*
+                 * This conditional makes the logfile active only after
+                 * it's been created - thus logging can be turned off by
+                 * removing the file.
+                 *
+                 * stop NFS hangs...most systems should be able to open a
+                 * file in 3 seconds. -avalon (curtesy of wumpus)
+                 */
+                if (IsPerson(sptr) &&
+                    (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND)) != -1)
+               {
+                        (void)sprintf(buf, "%s OPER (%s) (%s) by (%s!%s@%s)\n",
+                                     myctime(TStime()), name, encr,
+                                     parv[0], sptr->user->username,
+                                     sptr->sockhost);
+                 (void)write(logfile, buf, strlen(buf));
+                 (void)close(logfile);
+               }
+                /* Modification by pjg */
+             }
+#endif
+                  
+           }
+       else
+           {
+               (void)detach_conf(sptr, aconf);
+               sendto_one(sptr,err_str(ERR_PASSWDMISMATCH),me.name, parv[0]);
+#ifdef  FAILOPER_WARN
+               sendto_one(sptr,":%s NOTICE :*** Your attempt has been logged.",me.name);
+#endif
+                  sendto_realops("Failed OPER attempt by %s (%s@%s) using UID %s [NOPASSWORD]",
+                   parv[0], sptr->user->username, sptr->sockhost, name);
+                 sendto_serv_butone(&me, ":%s GLOBOPS :Failed OPER attempt by %s (%s@%s) using UID %s [---]",
+                   me.name, parv[0], sptr->user->username, sptr->sockhost, name);
+               sptr->since += 7;
+#ifdef FNAME_OPERLOG
+              {
+                int     logfile;
+
+                /*
+                 * This conditional makes the logfile active only after
+                 * it's been created - thus logging can be turned off by
+                 * removing the file.
+                 *
+                 * stop NFS hangs...most systems should be able to open a
+                 * file in 3 seconds. -avalon (curtesy of wumpus)
+                 */
+                if (IsPerson(sptr) &&
+                    (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND)) != -1)
+                {
+                        (void)sprintf(buf, "%s FAILED OPER (%s) (%s) by (%s!%s@%s)\n PASSWORD %s",
+                                      myctime(TStime()), name, encr,
+                                      parv[0], sptr->user->username,
+                                      sptr->sockhost, password);
+                  (void)write(logfile, buf, strlen(buf));
+                  (void)close(logfile);
+                }
+                /* Modification by pjg */
+              }
+#endif
+           }
+       return 0;
+    }
+
+/***************************************************************************
+ * m_pass() - Added Sat, 4 March 1989
+ ***************************************************************************/
+
+/*
+** m_pass
+**     parv[0] = sender prefix
+**     parv[1] = password
+*/
+int    m_pass(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+    {
+       char *password = parc > 1 ? parv[1] : NULL;
+
+       if (BadPtr(password))
+           {
+               sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "PASS");
+               return 0;
+           }
+       if (!MyConnect(sptr) || (!IsUnknown(cptr) && !IsHandshake(cptr)))
+           {
+               sendto_one(cptr, err_str(ERR_ALREADYREGISTRED),
+                          me.name, parv[0]);
+               return 0;
+           }
+       strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
+       return 0;
+    }
+
+/*
+ * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
+ * the need for complicated requests like WHOIS. It returns user/host
+ * information only (no spurious AWAY labels or channels).
+ */
+int    m_userhost(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+        int catsize;
+       char    *p = NULL;
+       aClient *acptr;
+       char    *s;
+       char    *curpos;
+       int     resid;
+
+       if (check_registered(sptr))
+               return 0;
+
+       if (parc > 2)
+               (void)m_userhost(cptr, sptr, parc-1, parv+1);
+
+       if (parc < 2)
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "USERHOST");
+               return 0;
+           }
+
+       /*
+        * use curpos to keep track of where we are in the output buffer,
+        * and use resid to keep track of the remaining space in the
+        * buffer
+        */
+       curpos = buf;
+       curpos += sprintf(curpos, rpl_str(RPL_USERHOST), me.name, parv[0]);
+       resid = sizeof(buf) - (curpos - buf) - 1;  /* remaining space */
+
+       /*
+        * for each user found, print an entry if it fits.
+        */
+       for (s = strtoken(&p, parv[1], " "); s;
+            s = strtoken(&p, (char *)NULL, " "))
+         if ((acptr = find_person(s, NULL))) {
+           catsize = strlen(acptr->name)
+             + (IsAnOper(acptr) ? 1 : 0)
+             + 3 
+              + strlen(acptr->user->username)
+              + strlen(acptr->user->realhost) + 1;
+           if (catsize <= resid) {
+             curpos += sprintf(curpos, "%s%s=%c%s@%s ",
+                               acptr->name,
+                               IsAnOper(acptr) ? "*" : "",
+                               (acptr->user->away) ? '-' : '+',
+                               acptr->user->username,
+                               ( (IsOper(sptr) || acptr == sptr) ? 
+                                acptr->user->realhost : 
+                                (IsHidden(acptr) ? acptr->user->virthost : acptr->user->realhost)
+                               )                                
+                               );
+             if (IsWhois(acptr) && IsOper(sptr))
+             {
+               sendto_one(acptr, ":%s NOTICE %s :*** %s did a /userhost on you.", me.name, sptr->name, sptr->name);
+                } 
+             resid -= catsize;
+           }
+         }
+       
+       /*
+        * because of some trickery here, we might have the string end in
+        * "...:" or "foo " (note the trailing space)
+        * If we have a trailing space, nuke it here.
+        */
+       curpos--;
+       if (*curpos != ':')
+         *curpos = '\0';
+       sendto_one(sptr, "%s", buf);
+       return 0;
+}
+
+/*
+ * 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
+ */
+
+int     m_ison(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{
+        char    namebuf[USERLEN+HOSTLEN+4];
+        Reg1    aClient *acptr;
+        Reg2    char    *s, **pav = parv, *user;
+        Reg3    int     len;
+        char    *p = NULL;
+        if (check_registered(sptr))
+                return 0;
+        if (parc < 2)
+         {
+                sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                           me.name, parv[0], "ISON");
+                return 0;
+         }
+        (void)sprintf(buf, rpl_str(RPL_ISON), me.name, *parv);
+        len = strlen(buf);
+#ifndef NO_FDLIST
+        cptr->priority +=30; /* this keeps it from moving to 'busy' list */
+#endif
+        for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " "))
+         {
+                if(user=index(s, '!')) *user++='\0';
+                if ((acptr = find_person(s, NULL)))
+                 {
+                   if (user) {
+                                strcpy(namebuf, acptr->user->username);
+                                strcat(namebuf, "@");
+                                strcat(namebuf, acptr->user->realhost);
+                                if(match(user, namebuf))
+                                        continue;
+                                *--user='!';
+                   }
+                        (void)strncat(buf, s, sizeof(buf) - len);
+                        len += strlen(s);
+                        (void)strncat(buf, " ", sizeof(buf) - len);
+                        len++;
+                 }
+         }
+        sendto_one(sptr, "%s", buf);
+        return 0;
+}
+
+/*
+ * m_umode() 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(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    int     flag;
+       Reg2    int     *s;
+       Reg3    char    **p, *m;
+       aClient *acptr;
+       anUser  *user = sptr->user;
+       aConfItem *aconf;
+       int     what, setflags;
+
+       if (check_registered_user(sptr))
+               return 0;
+
+       what = MODE_ADD;
+
+       if (parc < 2)
+           {
+               sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
+                          me.name, parv[0], "MODE");
+               return 0;
+           }
+
+       if (!(acptr = find_person(parv[1], NULL)))
+           {
+               if (MyConnect(sptr))
+                       sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL),
+                                  me.name, parv[0], parv[1]);
+               return 0;
+           }
+
+       if (parc < 3)
+           {
+               m = buf;
+               *m++ = '+';
+               for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4);
+                    s += 2)
+                       if ((sptr->umodes & flag))
+                               *m++ = (char)(*(s+1));
+               *m = '\0';
+               sendto_one(sptr, rpl_str(RPL_UMODEIS),
+                          me.name, parv[0], buf);
+               return 0;
+           }
+
+       /* find flags already set for user */
+       setflags = 0;
+       for (s = user_modes; (flag = *s); s += 2)
+               if ((sptr->umodes & flag))
+                       setflags |= flag;
+
+       /*
+        * parse mode change string(s)
+        */
+       for (p = &parv[2]; p && *p; p++ )
+               for (m = *p; *m; m++)
+                       switch(*m)
+                       {
+                       case '+' :
+                               what = MODE_ADD;
+                               break;
+                       case '-' :
+                               what = MODE_DEL;
+                               break;  
+
+                       /* we may not get these,
+                        * but they shouldnt be in default
+                        */
+                       case ' ' :
+                       case '\n' :
+                       case '\r' :
+                       case '\t' :
+                               break;
+                       case 'r'  :
+                       case 't'  :
+                               if (MyClient(sptr))
+                                       break;
+                       /* since we now use chatops define in unrealircd.conf, we have
+                        * to disallow it here */
+                       case 'b':
+                               if (ALLOW_CHATOPS == 0 && what == MODE_ADD && MyClient(sptr))
+                                       break;
+                               goto def;
+                       case 'B' :
+                               if (what == MODE_ADD && MyClient(sptr)) 
+                               (void)m_botmotd(sptr, sptr, 1, parv);
+            default :
+def:
+                               for (s = user_modes; (flag = *s); s += 2)
+                                       if (*m == (char)(*(s+1)))
+                                   {
+                                       if (what == MODE_ADD) {
+                                               sptr->umodes |= flag;
+                                        } else {
+                                               sptr->umodes &= ~flag;  
+                                               }
+
+                                       break;
+                                   }
+
+                               if (flag == 0 && MyConnect(sptr))
+                                       sendto_one(sptr,
+                                               err_str(ERR_UMODEUNKNOWNFLAG),
+                                               me.name, parv[0]);
+                               break;
+                       }
+       /*
+        * stop users making themselves operators too easily
+        */
+
+       if (!(setflags & UMODE_OPER) && IsOper(sptr) && !IsServer(cptr))
+               ClearOper(sptr);
+       if (!(setflags & UMODE_LOCOP) && IsLocOp(sptr) && !IsServer(cptr))
+               sptr->umodes &= ~UMODE_LOCOP;
+       /*
+        *  Let only operators set HelpOp
+        * Helpops get all /quote help <mess> globals -Donwulff
+        */
+               if (MyClient(sptr) && IsHelpOp(sptr) && !OPCanHelpOp(sptr))
+                       ClearHelpOp(sptr);
+       /*
+        * Let only operators set FloodF, ClientF; also
+        * remove those flags if they've gone -o/-O.
+        *  FloodF sends notices about possible flooding -Cabal95
+        *  ClientF sends notices about clients connecting or exiting
+        *  Admin is for server admins
+        */
+       if (!IsAnOper(sptr) && !IsServer(cptr))
+           {
+               if (IsWhois(sptr))
+                   sptr->umodes &= ~UMODE_WHOIS;
+               if (IsClientF(sptr))
+                       ClearClientF(sptr);
+               if (IsFloodF(sptr))
+                       ClearFloodF(sptr);
+               if (IsAdmin(sptr))
+                       ClearAdmin(sptr);
+                if (IsSAdmin(sptr))
+                       ClearSAdmin(sptr);
+               if (IsNetAdmin(sptr))
+                       ClearNetAdmin(sptr);
+               if (IsHideOper(sptr))
+                       ClearHideOper(sptr);
+               if (IsCoAdmin(sptr))
+                        ClearCoAdmin(sptr);
+               if (IsTechAdmin(sptr))
+                       ClearTechAdmin(sptr);
+                if (IsEyes(sptr))
+                        ClearEyes(sptr);
+                               if (ALLOW_CHATOPS == 1) {
+                                       if (SendChatops(sptr))
+                                               ClearChatops(sptr);
+                               }
+
+           }
+
+       /*
+        * New oper access flags - Only let them set certian usermodes on
+        * themselves IF they have access to set that specific mode in their
+        * O:Line.
+        */
+       if (MyClient(sptr) && IsAnOper(sptr))
+           {
+               if (IsClientF(sptr) && !OPCanUModeC(sptr))
+                       ClearClientF(sptr);
+               if (IsFloodF(sptr) && !OPCanUModeF(sptr))
+                       ClearFloodF(sptr);  
+               if (IsAdmin(sptr) && !OPIsAdmin(sptr))
+                       ClearAdmin(sptr);
+               if (IsSAdmin(sptr) && !OPIsSAdmin(sptr))
+                       ClearSAdmin(sptr);
+                if (IsNetAdmin(sptr) && !OPIsNetAdmin(sptr))
+                        ClearNetAdmin(sptr);
+                if (IsCoAdmin(sptr) && !OPIsCoAdmin(sptr))
+                        ClearCoAdmin(sptr);
+               if (IsTechAdmin(sptr) && !OPIsTechAdmin(sptr))
+                       ClearTechAdmin(sptr);
+               if ((sptr->umodes & UMODE_HIDING) && !(sptr->oflag & OFLAG_INVISIBLE))
+                       sptr->umodes &= ~UMODE_HIDING;
+               if (MyClient(sptr) && (sptr->umodes & UMODE_CODER) && !IsAnOper(sptr))
+                       sptr->umodes &= ~UMODE_CODER;
+       
+
+           }
+
+        /*
+         * For Services Protection...
+         */
+        if (!IsServer(cptr) && !IsULine(cptr,sptr))
+            {
+               if (IsServices(sptr))
+                       ClearServices(sptr);
+/*             if (IsDeaf(sptr))
+                       sptr->umodes &= ~UMODE_DEAF;
+*/
+            }
+       if ((setflags & UMODE_HIDE) && !IsHidden(sptr))
+                       sptr->umodes &= ~UMODE_SETHOST;
+        
+        if (IsHidden(sptr) && !(setflags & UMODE_HIDE))
+        {
+                       make_virthost(sptr->user->realhost, sptr->user->virthost);
+        }
+
+       /*
+         This is to remooove the kix bug.. and to protect some stuffie
+               -techie
+       */
+        if (MyConnect(sptr))
+        {      
+               if ((sptr->umodes & (UMODE_KIX)) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+                       sptr->umodes &= ~UMODE_KIX;
+               if ((sptr->umodes & (UMODE_FCLIENT)) && !(IsNetAdmin(sptr) || IsTechAdmin(sptr)))
+                       sptr->umodes &= ~UMODE_FCLIENT;
+
+               /* Agents */
+               if ((sptr->umodes & (UMODE_AGENT)) && !(sptr->oflag & OFLAG_AGENT))
+                       sptr->umodes &= ~UMODE_AGENT;
+               if ((sptr->umodes & UMODE_HIDING) && !IsAnOper(sptr))
+                       sptr->umodes &= ~UMODE_HIDING;
+                       
+               if ((sptr->umodes & UMODE_HIDING) && !(sptr->oflag & OFLAG_INVISIBLE))
+                       sptr->umodes &= ~UMODE_HIDING;
+               if (MyClient(sptr) && (sptr->umodes & UMODE_CODER) && !IsAnOper(sptr))
+                       sptr->umodes &= ~UMODE_CODER;
+
+               if ((sptr->umodes & (UMODE_HIDING)) && !(setflags & UMODE_HIDING)) {
+                       sendto_umode(UMODE_ADMIN, "[+I] Activated total invisibility mode on %s", sptr->name);
+                       sendto_serv_butone(cptr, ":%s SMO A :[+I] Activated total invisibility mode on %s",me.name, sptr->name);
+               }
+               if (!(sptr->umodes & (UMODE_HIDING))) {
+                       if (setflags & UMODE_HIDING) {
+                               sendto_umode(UMODE_ADMIN, "[+I] De-activated total invisibility mode on %s", sptr->name);
+                               sendto_serv_butone(cptr, ":%s SMO A :[+I] De-activated total invisibility mode on %s", me.name, sptr->name);
+                       }
+               }
+       }
+       /*
+        * If I understand what this code is doing correctly...
+        *   If the user WAS an operator and has now set themselves -o/-O
+        *   then remove their access, d'oh!
+        * In order to allow opers to do stuff like go +o, +h, -o and
+        * remain +h, I moved this code below those checks. It should be
+        * O.K. The above code just does normal access flag checks. This
+        * only changes the operflag access level.  -Cabal95
+        */
+       if ((setflags & (UMODE_OPER|UMODE_LOCOP)) && !IsAnOper(sptr) &&
+           MyConnect(sptr))
+           {
+#ifndef NO_FDLIST
+               delfrom_fdlist(sptr->fd, &oper_fdlist);
+#endif
+               det_confs_butmask(sptr, CONF_CLIENT & ~CONF_OPS);
+               sptr->oflag = 0;
+           }
+
+       /*
+        * compare new flags with old flags and send string which
+        * will cause servers to update correctly.
+        */
+       if (dontspread == 0)
+               send_umode_out(cptr, sptr, setflags);
+
+       return 0;
+}
+
+/*
+ * m_svs2mode() added by Potvin
+ * parv[0] - sender
+ * parv[1] - username to change mode for
+ * parv[2] - modes to change
+ * parv[3] - Service Stamp (if mode == d)
+ */
+int    m_svs2mode(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    int     flag;
+       Reg2    int     *s;
+       Reg3    char    **p, *m;
+       aClient *acptr;
+       int     what, setflags;
+
+       if (!IsULine(cptr, sptr))
+               return 0;
+
+       what = MODE_ADD;
+
+       if (parc < 3)
+               return 0;
+
+       if (!(acptr = find_person(parv[1], NULL)))
+               return 0;
+
+       setflags = 0;
+       for (s = user_modes; (flag = *s); s += 2)
+               if (acptr->umodes & flag)
+                       setflags |= flag;
+       /*
+        * parse mode change string(s)
+        */
+       for (p = &parv[2]; p && *p; p++ )
+               for (m = *p; *m; m++)
+                       switch(*m)
+                       {
+                       case '+' :
+                               what = MODE_ADD;
+                               break;
+                       case '-' :
+                               what = MODE_DEL;
+                               break;  
+                       /* we may not get these,
+                        * but they shouldnt be in default
+                        */
+                       case ' ' :
+                       case '\n' :
+                       case '\r' :
+                       case '\t' :
+                               break;
+                       case 'l' :
+                               if(parv[3] && isdigit(*parv[3]))
+                                       max_global_count = atoi(parv[3]);
+                               break;
+                       case 'd' :
+                               if(parv[3] && isdigit(*parv[3]))
+                                       acptr->user->servicestamp = atol(parv[3]);
+                               break;
+                       default :
+                               for (s = user_modes; (flag = *s); s += 2)
+                                       if (*m == (char)(*(s+1)))
+                                   {
+                                       if (what == MODE_ADD)
+                                               acptr->umodes |= flag;
+                                       else
+                                               acptr->umodes &= ~flag; 
+                                       break;
+                                   }
+                               break;
+                       }
+
+       if(parc > 3)
+               sendto_serv_butone(cptr, ":%s SVS2MODE %s %s %s",
+                       parv[0], parv[1], parv[2], parv[3]);
+       else
+               sendto_serv_butone(cptr, ":%s SVS2MODE %s %s", parv[0],
+                       parv[1], parv[2]);
+
+                        sendto_one(acptr, ":%s MODE %s :%s",
+                                   parv[0], parv[1], parv[2]);
+
+       return 0;
+}
+
+/*
+ * m_svsmode() added by taz
+ * parv[0] - sender
+ * parv[1] - username to change mode for
+ * parv[2] - modes to change
+ * parv[3] - Service Stamp (if mode == d)
+ */
+int    m_svsmode(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    int     flag;
+       Reg2    int     *s;
+       Reg3    char    **p, *m;
+       aClient *acptr;
+       int     what, setflags;
+
+       if (!IsULine(cptr, sptr))
+               return 0;
+
+       what = MODE_ADD;
+
+       if (parc < 3)
+               return 0;
+
+       if (!(acptr = find_person(parv[1], NULL)))
+               return 0;
+
+       setflags = 0;
+       for (s = user_modes; (flag = *s); s += 2)
+               if (acptr->umodes & flag)
+                       setflags |= flag;
+       /*
+        * parse mode change string(s)
+        */
+       for (p = &parv[2]; p && *p; p++ )
+               for (m = *p; *m; m++)
+                       switch(*m)
+                       {
+                       case '+' :
+                               what = MODE_ADD;
+                               break;
+                       case '-' :
+                               what = MODE_DEL;
+                               break;  
+                       /* we may not get these,
+                        * but they shouldnt be in default
+                        */
+                       case ' ' :
+                       case '\n' :
+                       case '\r' :
+                       case '\t' :
+                               break;
+                       case 'l' :
+                               if(parv[3] && isdigit(*parv[3]))
+                                       max_global_count = atoi(parv[3]);
+                               break;
+                       case 'd' :
+                               if(parv[3] && isdigit(*parv[3]))
+                                       acptr->user->servicestamp = atol(parv[3]);
+                               break;
+                       default :
+                               for (s = user_modes; (flag = *s); s += 2)
+                                       if (*m == (char)(*(s+1)))
+                                   {
+                                       if (what == MODE_ADD)
+                                               acptr->umodes |= flag;
+                                       else
+                                               acptr->umodes &= ~flag; 
+                                       break;
+                                   }
+                               break;
+                       }
+
+
+       if(parc > 3)
+               sendto_serv_butone(cptr, ":%s SVSMODE %s %s %s",
+                       parv[0], parv[1], parv[2], parv[3]);
+       else
+               sendto_serv_butone(cptr, ":%s SVSMODE %s %s", parv[0],
+                       parv[1], parv[2]);
+
+       return 0;
+}
+       
+/*
+ * send the MODE string for user (user) to connection cptr
+ * -avalon
+ */
+void   send_umode(cptr, sptr, old, sendmask, umode_buf)
+aClient *cptr, *sptr;
+int    old, sendmask;
+char   *umode_buf;
+{
+       Reg1    int     *s, flag;
+       Reg2    char    *m;
+       int     what = MODE_NULL;
+
+       /*
+        * build a string in umode_buf to represent the change in the user's
+        * mode between the new (sptr->flag) and 'old'.
+        */
+       m = umode_buf;
+       *m = '\0';
+       for (s = user_modes; (flag = *s); s += 2)
+           {
+               if (MyClient(sptr) && !(flag & sendmask))
+                       continue;
+               if ((flag & old) && !(sptr->umodes & flag))
+                   {
+                       if (what == MODE_DEL)
+                               *m++ = *(s+1);
+                       else
+                           {
+                               what = MODE_DEL;
+                               *m++ = '-';
+                               *m++ = *(s+1);
+                           }
+                   }
+               else if (!(flag & old) && (sptr->umodes & flag))
+                   {
+                       if (what == MODE_ADD)
+                               *m++ = *(s+1);
+                       else
+                           {
+                               what = MODE_ADD;
+                               *m++ = '+';
+                               *m++ = *(s+1);
+                           }
+                   }
+           }
+       *m = '\0';
+       if (*umode_buf && cptr)
+               sendto_one(cptr, ":%s %s %s :%s", sptr->name,
+                          (IsToken(cptr)?TOK_MODE:MSG_MODE),
+                          sptr->name, umode_buf);
+}
+
+/*
+ * added Sat Jul 25 07:30:42 EST 1992
+ */
+void   send_umode_out(cptr, sptr, old)
+aClient *cptr, *sptr;
+int    old;
+{
+       Reg1    int     i;
+       Reg2    aClient *acptr;
+
+       send_umode(NULL, sptr, old, SEND_UMODES, buf);
+
+       for (i = highest_fd; i >= 0; i--)
+               if ((acptr = local[i]) && IsServer(acptr) &&
+                   (acptr != cptr) && (acptr != sptr) && *buf)
+                       sendto_one(acptr, ":%s MODE %s :%s",
+                                  sptr->name, sptr->name, buf);
+
+       if (cptr && MyClient(cptr))
+               send_umode(cptr, sptr, old, ALL_UMODES, buf);
+
+}
+
+void   send_umode_out_nickv2(cptr, sptr, old)
+aClient *cptr, *sptr;
+int    old;
+{
+       Reg1    int     i;
+       Reg2    aClient *acptr;
+
+       send_umode(NULL, sptr, old, SEND_UMODES, buf);
+
+       for (i = highest_fd; i >= 0; i--)
+               if ((acptr = local[i]) && IsServer(acptr) && !SupportNICKv2(acptr) &&
+                   (acptr != cptr) && (acptr != sptr) && *buf)
+                       sendto_one(acptr, ":%s MODE %s :%s",
+                                  sptr->name, sptr->name, buf);
+
+       if (cptr && MyClient(cptr))
+               send_umode(cptr, sptr, old, ALL_UMODES, buf);
+
+}
+
+/*
+ * added by taz
+ */
+void   send_svsmode_out(cptr, sptr, bsptr, old)
+aClient *cptr, *sptr, *bsptr;
+
+int    old;
+{
+       Reg1    int     i;
+       Reg2    aClient *acptr;
+
+       send_umode(NULL, sptr, old, SEND_UMODES, buf);
+
+       sendto_serv_butone(acptr, ":%s SVSMODE %s :%s",
+                                  bsptr->name, sptr->name, buf);
+
+/*     if (cptr && MyClient(cptr))
+               send_umode(cptr, sptr, old, ALL_UMODES, buf);
+*/
+}
+
+/***********************************************************************
+ * m_silence() - Added 19 May 1994 by Run. 
+ *
+ ***********************************************************************/
+
+/*
+ * is_silenced : Does the actual check wether sptr is allowed
+ *               to send a message to acptr.
+ *               Both must be registered persons.
+ * If sptr is silenced by acptr, his message should not be propagated,
+ * but more over, if this is detected on a server not local to sptr
+ * the SILENCE mask is sent upstream.
+ */
+static int is_silenced(sptr, acptr)
+aClient *sptr;
+aClient *acptr;
+{ Reg1 Link *lp;
+  Reg2 anUser *user;
+  static char sender[HOSTLEN+NICKLEN+USERLEN+5];
+
+  if (!(acptr->user) || !(lp = acptr->user->silence) ||
+      !(user = sptr->user)) return 0;
+  sprintf(sender,"%s!%s@%s",sptr->name,user->username,user->realhost);
+  for (; lp; lp = lp->next)
+  { if (!match(lp->value.cp, sender))
+    { if (!MyConnect(sptr))
+      { sendto_one(sptr->from, ":%s SILENCE %s :%s",acptr->name,
+            sptr->name, lp->value.cp);
+        lp->flags=1; }
+      return 1; } }
+  return 0;
+}
+
+int del_silence(sptr, mask)
+aClient *sptr;
+char *mask;
+{ Reg1 Link **lp;
+  Reg2 Link *tmp;
+
+  for (lp = &(sptr->user->silence); *lp; lp = &((*lp)->next))
+    if (mycmp(mask, (*lp)->value.cp)==0)
+    { tmp = *lp;
+      *lp = tmp->next;
+      MyFree(tmp->value.cp);
+      free_link(tmp);
+      return 0; }
+  return -1;
+}
+
+static int add_silence(sptr, mask)
+aClient *sptr;
+char *mask;
+{ Reg1 Link *lp;
+  Reg2 int cnt = 0, len = 0;
+
+  for (lp = sptr->user->silence; lp; lp = lp->next)
+  { len += strlen(lp->value.cp);
+    if (MyClient(sptr))
+      if ((len > MAXSILELENGTH) || (++cnt >= MAXSILES))
+      { sendto_one(sptr, err_str(ERR_SILELISTFULL), me.name, sptr->name, mask);
+       return -1; }
+      else
+      { if (!match(lp->value.cp, mask))
+         return -1; }
+    else if (!mycmp(lp->value.cp, mask))
+      return -1;
+  }
+  lp = make_link();
+  bzero((char *)lp, sizeof(Link));
+  lp->next = sptr->user->silence;
+  lp->value.cp = (char *)MyMalloc(strlen(mask)+1);
+  (void)strcpy(lp->value.cp, mask);
+  sptr->user->silence = lp;
+  return 0;
+}
+
+/*
+** m_silence
+**     parv[0] = sender prefix
+** From local client:
+**     parv[1] = mask (NULL sends the list)
+** From remote client:
+**     parv[1] = nick that must be silenced
+**      parv[2] = mask
+*/
+
+int m_silence(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+  Link *lp;
+  aClient *acptr;
+  char c, *cp, *user, *host;
+
+  if (check_registered_user(sptr)) return 0;
+
+  if (MyClient(sptr))
+  {
+    acptr = sptr;
+    if (parc < 2 || *parv[1]=='\0' || (acptr = find_person(parv[1], NULL)))
+    { 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, acptr->name);
+      return 0; }
+    cp = parv[1];
+    c = *cp;
+    if (c=='-' || c=='+') cp++;
+    else if (!(index(cp, '@') || index(cp, '.') ||
+       index(cp, '!') || index(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 ((c = *parv[2])=='-' || (acptr = find_person(parv[1], NULL)))
+  {
+    if (c=='-')
+    { if (!del_silence(sptr,parv[2]+1))
+       sendto_serv_butone(cptr, ":%s SILENCE %s :%s",
+           parv[0], parv[1], parv[2]); }
+    else
+    { (void)add_silence(sptr,parv[2]);
+      if (!MyClient(acptr))
+        sendto_one(acptr, ":%s SILENCE %s :%s",
+            parv[0], parv[1], parv[2]); }
+  }
+  else
+  {
+    sendto_one(sptr, err_str(ERR_NOSUCHNICK), me.name, parv[0], parv[1]);
+    return -1;
+  }
+  return 0;
+}
+
+/* m_svsjoin() - Lamego - Wed Jul 21 20:04:48 1999
+   Copied off PTlink IRCd (C) PTlink coders team.
+       parv[0] - sender
+       parv[1] - nick to make join
+       parv[2] - channel(s) to join
+*/
+int    m_svsjoin(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       if (!IsULine(cptr, sptr))
+               return 0;
+
+       if (parc!=3 || !(acptr = find_person(parv[1], NULL)))
+               return 0;
+       
+       if(MyClient(acptr)) {
+               parv [0] = parv [1];
+               parv [1] = parv [2];
+                (void)m_join(acptr,acptr,2,parv); 
+       }
+       else
+       sendto_serv_butone(cptr, ":%s SVSJOIN %s %s", parv[0],
+                       parv[1], parv[2]);
+
+       return 0;
+}
+
+/* m_sajoin() - Lamego - Wed Jul 21 20:04:48 1999
+   Copied off PTlink IRCd (C) PTlink coders team.
+   Coded for Sadmin by Stskeeps
+       parv[0] - sender
+       parv[1] - nick to make join
+       parv[2] - channel(s) to join
+*/
+int    m_sajoin(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       if (!IsSAdmin(sptr) && !IsULine(cptr, sptr))
+               return 0;
+
+       if (parc!=3 || !(acptr = find_person(parv[1], NULL)))
+               return 0;
+       
+       sendto_realops("%s used SAJOIN to make %s join %s", sptr->name, parv[1], parv[2]);
+
+       if(MyClient(acptr)) {
+               parv [0] = parv [1];
+               parv [1] = parv [2];
+               sendto_one(acptr, ":%s NOTICE %s :*** You were forced to join %s", me.name, acptr->name, parv[2]);
+                (void)m_join(acptr,acptr,2,parv); 
+       }
+       else
+       sendto_serv_butone(cptr, ":%s SAJOIN %s %s", parv[0],
+                       parv[1], parv[2]);
+
+       return 0;
+}
+/* m_svspart() - Lamego - Wed Jul 21 20:04:48 1999
+   Copied off PTlink IRCd (C) PTlink coders team.
+  Modified for PART by Stskeeps
+       parv[0] - sender
+       parv[1] - nick to make part
+       parv[2] - channel(s) to part
+*/
+int    m_svspart(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       if (!IsULine(cptr, sptr))
+               return 0;
+
+       if (parc!=3 || !(acptr = find_person(parv[1], NULL)))
+               return 0;
+       
+       if(MyClient(acptr)) {
+               parv [0] = parv [1];
+               parv [1] = parv [2];
+                (void)m_part(acptr,acptr,2,parv); 
+       }
+       else
+       sendto_serv_butone(cptr, ":%s SVSPART %s %s", parv[0],
+                       parv[1], parv[2]);
+
+       return 0;
+}
+
+/* m_sapart() - Lamego - Wed Jul 21 20:04:48 1999
+   Copied off PTlink IRCd (C) PTlink coders team.
+   Coded for Sadmin by Stskeeps
+       parv[0] - sender
+       parv[1] - nick to make part
+       parv[2] - channel(s) to part
+*/
+int    m_sapart(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       aClient *acptr;
+       if (!IsSAdmin(sptr) && !IsULine(cptr, sptr))
+               return 0;
+
+       if (parc!=3 || !(acptr = find_person(parv[1], NULL)))
+               return 0;
+       
+       sendto_realops("%s used SAPART to make %s part %s", sptr->name, parv[1], parv[2]);
+
+       if(MyClient(acptr)) {
+               parv [0] = parv [1];
+               parv [1] = parv [2];
+               sendto_one(acptr, ":%s NOTICE %s :*** You were forced to part %s", me.name, acptr->name, parv[2]);
+                (void)m_part(acptr,acptr,2,parv); 
+       }
+       else
+       sendto_serv_butone(cptr, ":%s SAPART %s %s", parv[0],
+                       parv[1], parv[2]);
+
+       return 0;
+}
+/* These just waste space 
+int m_noshortn(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{      sendto_one(sptr, "NOTICE %s :*** Please use /nickserv for that command",sptr->name);
+}
+int m_noshortc(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{      sendto_one(sptr, "NOTICE %s :*** Please use /chanserv for that command",sptr->name);
+}
+int m_noshortm(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{      sendto_one(sptr, "NOTICE %s :*** Please use /memoserv for that command",sptr->name);
+}
+int m_noshorto(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{      sendto_one(sptr, "NOTICE %s :*** Please use /operserv for that command",sptr->name);
+}
+int m_noshorth(cptr, sptr, parc, parv)
+aClient *cptr, *sptr;
+int     parc;
+char    *parv[];
+{       sendto_one(sptr, "NOTICE %s :*** Please use /helpserv for that command",sptr->name);
+}
+*/
diff --git a/src/send.c b/src/send.c
new file mode 100644 (file)
index 0000000..23a2981
--- /dev/null
@@ -0,0 +1,1300 @@
+/*
+ *   IRC - Internet Relay Chat, common/send.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.
+ */
+
+/* -- Jto -- 16 Jun 1990
+ * Added Armin's PRIVMSG patches...
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)send.c    2.32 2/28/94 (C) 1988 University of Oulu, Computing Center and Jarkko Oikarinen";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include <stdarg.h>
+#include <stdio.h>
+#ifdef _WIN32
+#include <io.h>
+#endif
+
+ID_CVS("$Id$");
+
+void vsendto_one(aClient *to, char *pattern, va_list vl);
+void sendbufto_one(aClient *to);
+extern int sendanyways;
+#ifndef NO_FDLIST
+extern fdlist serv_fdlist;
+extern fdlist oper_fdlist;
+#endif
+
+#ifdef IRCII_KLUDGE
+#define        NEWLINE "\n"
+#else
+#define NEWLINE        "\r\n"
+#endif
+
+static char    sendbuf[2048];
+static int     send_message PROTO((aClient *, char *, int));
+
+static int     sentalong[MAXCONNECTIONS];
+
+void vsendto_prefix_one(struct Client *to, struct Client *from,
+    const char* pattern, va_list vl);
+
+int sentalong_marker;
+
+/*
+** dead_link
+**     An error has been detected. The link *must* be closed,
+**     but *cannot* call ExitClient (m_bye) from here.
+**     Instead, mark it with FLAGS_DEADSOCKET. This should
+**     generate ExitClient from the main loop.
+**
+**     If 'notice' is not NULL, it is assumed to be a format
+**     for a message to local opers. I can contain only one
+**     '%s', which will be replaced by the sockhost field of
+**     the failing link.
+**
+**     Also, the notice is skipped for "uninteresting" cases,
+**     like Persons and yet unknown connections...
+*/
+static int     dead_link(to, notice)
+aClient *to;
+char   *notice;
+{
+       to->flags |= FLAGS_DEADSOCKET;
+       /*
+        * If because of BUFFERPOOL problem then clean dbuf's now so that
+        * notices don't hurt operators below.
+        */
+       DBufClear(&to->recvQ);
+       DBufClear(&to->sendQ);
+       if (!IsPerson(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING))
+               (void)sendto_failops_whoare_opers(notice, get_client_name(to, FALSE));
+       Debug((DEBUG_ERROR, notice, get_client_name(to, FALSE)));
+       return -1;
+}
+
+/*
+** flush_connections
+**     Used to empty all output buffers for all connections. Should only
+**     be called once per scan of connections. There should be a select in
+**     here perhaps but that means either forcing a timeout or doing a poll.
+**     When flushing, all we do is empty the obuffer array for each local
+**     client and try to send it. if we cant send it, it goes into the sendQ
+**     -avalon
+*/
+void   flush_connections(fd)
+int    fd;
+{
+#ifdef SENDQ_ALWAYS
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+
+       if (fd == me.fd)
+           {
+               for (i = highest_fd; i >= 0; i--)
+                       if ((cptr = local[i]) && DBufLength(&cptr->sendQ) > 0)
+                               (void)send_queued(cptr);
+           }
+       else if (fd >= 0 && (cptr = local[fd]) && DBufLength(&cptr->sendQ) > 0)
+               (void)send_queued(cptr);
+#endif
+}
+
+/*
+** send_queued
+**     This function is called from the main select-loop (or whatever)
+**     when there is a chance the some output would be possible. This
+**     attempts to empty the send queue as far as possible...
+*/
+int    send_queued(to)
+aClient *to;
+{
+       char    *msg;
+       int     len, rlen;
+
+#ifndef pyr
+       if (IsBlocked(to)) return; /* Can't write to already blocked socket */
+#endif /* pyr */
+
+       /*
+       ** 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
+               */
+#ifndef SENDQ_ALWAYS
+               return dead_link(to, "send_queued called for a DEADSOCKET:%s");
+#else
+               return -1;
+#endif
+           }
+       while (DBufLength(&to->sendQ) > 0)
+           {
+               msg = dbuf_map(&to->sendQ, &len);
+                                       /* Returns always len > 0 */
+               if ((rlen = deliver_it(to, msg, len)) < 0)
+                       return dead_link(to,"Write error to %s, closing link");
+               (void)dbuf_delete(&to->sendQ, rlen);
+               to->lastsq = DBufLength(&to->sendQ)/1024;
+               if (rlen < len) {
+                       /* If we can't write full message, mark the socket
+                        * as "blocking" and stop trying. -Donwulff */
+                       SetBlocked(to);
+                       break;
+               }
+           }
+
+       return (IsDead(to)) ? -1 : 0;
+}
+
+/*
+ *  send message to single client
+ */
+void sendto_one(aClient *to, char *pattern, ...)
+{
+  va_list vl;
+  va_start(vl, pattern);
+  vsendto_one(to, pattern, vl);
+  va_end(vl);
+}
+
+void vsendto_one(aClient *to, char *pattern, va_list vl)
+{
+  vsprintf(sendbuf, pattern, vl);
+  sendbufto_one(to);
+}
+
+void sendbufto_one(aClient *to)
+{
+  int len;
+
+  Debug((DEBUG_ERROR, "Sending [%s] to %s", sendbuf, to->name));
+
+  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;
+}
+
+  len = strlen(sendbuf);
+  if (sendbuf[len - 1] != '\n')
+  {
+    if (len > 510)
+      len = 510;
+    sendbuf[len++] = '\r';
+    sendbuf[len++] = '\n';
+    sendbuf[len] = '\0';
+  }
+
+  if (IsMe(to))
+  {
+    char tmp_sendbuf[sizeof(sendbuf)];
+
+    strcpy(tmp_sendbuf, sendbuf);
+    sendto_ops("Trying to send [%s] to myself!", tmp_sendbuf);
+    return;
+  }
+
+  if (DBufLength(&to->sendQ) > get_sendq(to))
+  {
+    if (IsServer(to))
+      sendto_ops("Max SendQ limit exceeded for %s: "
+          "%lu > %lu",
+         get_client_name(to, FALSE), 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;
+  }
+  /*
+   * 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;
+  /*
+   * 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
+   * 2k has been added to the queue since the last non-fatal write.
+   * Also stops us from deliberately building a large sendQ and then
+   * trying to flood that link with data (possible during the net
+   * relinking done by servers with a large load).
+   */
+  if (DBufLength(&to->sendQ) / 1024 > to->lastsq)
+    send_queued(to);
+}
+
+void   sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr, char *pattern, ...)
+{
+  va_list vl;
+  Link *lp;
+  aClient *acptr;
+  int i;
+
+  va_start(vl, pattern);
+
+  ++sentalong_marker;
+  for (lp = chptr->members; lp; lp = lp->next)
+  {
+    acptr = lp->value.cptr;
+    /* ...was the one I should skip */
+    if (acptr->from == one || (IsDeaf(acptr) && !(sendanyways==1)))
+      continue;
+    if (MyConnect(acptr))       /* (It is always a client) */
+      vsendto_prefix_one(acptr, from, pattern, vl);
+    else if (sentalong[(i = acptr->from->fd)] != sentalong_marker)
+    {
+      sentalong[i] = sentalong_marker;
+      /*
+       * Burst messages comes here..
+       */
+        vsendto_prefix_one(acptr, from, pattern, vl);
+    }
+  }
+  va_end(vl);
+}
+
+/*
+ * sendto_channelops_butone Added 1 Sep 1996 by Cabal95.
+ *   Send a message to all OPs in channel chptr that
+ *   are directly on this server and sends the message
+ *   on to the next server if it has any OPs.
+ *
+ *   All servers must have this functional ability
+ *    or one without will send back an error message. -- Cabal95
+ */
+void   sendto_channelops_butone(aClient *one, aClient *from, aChannel *chptr, char *pattern, ...)
+{ 
+       va_list vl;
+       Reg1    Link    *lp;
+       Reg2    aClient *acptr;
+       Reg3    int     i;
+
+       va_start(vl,pattern);
+       for (i = 0; i < MAXCONNECTIONS; i++)
+               sentalong[i] = 0;
+       for (lp = chptr->members; lp; lp = lp->next)
+           {
+               acptr = lp->value.cptr;
+               if (acptr->from == one ||
+                   !(lp->flags & CHFL_CHANOP))
+                       continue;       /* ...was the one I should skip
+                                           or user not not a channel op */
+               i = acptr->from->fd;
+               if (MyConnect(acptr) && IsRegisteredUser(acptr))
+                   {
+                       vsendto_prefix_one(acptr, from, pattern, vl);
+                       sentalong[i] = 1;
+                   }
+               else
+                    {
+               /* Now check whether a message has been sent to this
+                * remote link already */
+                       if (sentalong[i] == 0) 
+                           {
+                               vsendto_prefix_one(acptr, from, pattern, vl);
+                               sentalong[i] = 1;
+                           }
+                   }
+           }
+       va_end(vl); 
+       return;
+}
+
+/*
+ * sendto_channelvoice_butone
+ * direct port of Cabal95's sendto_channelops_butone
+ * to allow for /notice @+#channel messages
+ * not exactly the most adventurous coding (made heavy use of copy-paste) <G>
+ * but it's needed to avoid mass-msg trigger in script vnotices
+ * -DuffJ
+ */
+
+void   sendto_channelvoice_butone(aClient *one, aClient *from, aChannel *chptr, char *pattern, ...)
+{ 
+       va_list vl;
+       Reg1    Link    *lp;
+       Reg2    aClient *acptr;
+       Reg3    int     i;
+
+       va_start(vl,pattern);
+       for (i = 0; i < MAXCONNECTIONS; i++)
+               sentalong[i] = 0;
+       for (lp = chptr->members; lp; lp = lp->next)
+           {
+               acptr = lp->value.cptr;
+               if (acptr->from == one ||
+                   !((lp->flags & CHFL_VOICE) || (lp->flags & CHFL_CHANOP) || (lp->flags & CHFL_HALFOP)))
+                       continue;       /* ...was the one I should skip
+                                           or user not (a channel voice or op) */
+               i = acptr->from->fd;
+               if (MyConnect(acptr) && IsRegisteredUser(acptr))
+                   {
+                       vsendto_prefix_one(acptr, from, pattern, vl);
+                       sentalong[i] = 1;
+                   }
+               else
+                    {
+               /* Now check whether a message has been sent to this
+                * remote link already */
+                       if (sentalong[i] == 0) 
+                           {
+                               vsendto_prefix_one(acptr, from, pattern, vl);
+                               sentalong[i] = 1;
+                           }
+                   }
+           }
+       va_end(vl); 
+       return;
+}
+
+/*
+ * sendto_channelhalfop_butone
+ * direct port of Cabal95's sendto_channelops_butone
+ * to allow for /notice @+#channel messages
+ * not exactly the most adventurous coding (made heavy use of copy-paste) <G>
+ * but it's needed to avoid mass-msg trigger in script hnotices
+ * -Stskeeps
+ */
+
+void   sendto_channelhalfop_butone(aClient *one, aClient *from, aChannel *chptr, char *pattern, ...)
+{ 
+       va_list vl;
+       Reg1    Link    *lp;
+       Reg2    aClient *acptr;
+       Reg3    int     i;
+
+       va_start(vl,pattern);
+       for (i = 0; i < MAXCONNECTIONS; i++)
+               sentalong[i] = 0;
+       for (lp = chptr->members; lp; lp = lp->next)
+           {
+               acptr = lp->value.cptr;
+               if (acptr->from == one ||
+                   !((lp->flags & CHFL_HALFOP) || (lp->flags & CHFL_CHANOP)))
+                       continue;       /* ...was the one I should skip
+                                           or user not (a channel halfop or op) */
+               i = acptr->from->fd;
+               if (MyConnect(acptr) && IsRegisteredUser(acptr))
+                   {
+                       vsendto_prefix_one(acptr, from, pattern, vl);
+                       sentalong[i] = 1;
+                   }
+               else
+                    {
+               /* Now check whether a message has been sent to this
+                * remote link already */
+                       if (sentalong[i] == 0) 
+                           {
+                               vsendto_prefix_one(acptr, from, pattern, vl);
+                               sentalong[i] = 1;
+                           }
+                   }
+           }
+       va_end(vl); 
+       return;
+}
+
+/*
+ * sendto_server_butone
+ *
+ * Send a message to all connected servers except the client 'one'.
+ */
+void   sendto_serv_butone(aClient *one, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+#ifndef NO_FDLIST
+        Reg3    int     j;
+#endif
+
+       va_start(vl,pattern);
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry;
+                       i=serv_fdlist.entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]) || (one && cptr == one->from))
+                       continue;
+#ifdef NO_FDLIST
+               if (IsServer(cptr))
+#endif
+                       vsendto_one(cptr, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_serv_butone_quit
+ *
+ * Send a message to all connected servers except the client 'one'.
+ * BUT, don't send to NOQUIT servers.
+ */
+void   sendto_serv_butone_quit(aClient *one, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+#ifndef NO_FDLIST
+       Reg3    int     j;
+#endif
+       va_start(vl,pattern);
+
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry;
+                               i=serv_fdlist.entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]) || (one && cptr == one->from))
+                       continue;
+#ifdef NO_FDLIST
+               if (IsServer(cptr) && !DontSendQuit(cptr))
+#else
+               if (!DontSendQuit(cptr))
+#endif
+                       vsendto_one(cptr, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_serv_butone_sjoin
+ *
+ * Send a message to all connected servers except the client 'one'.
+ * BUT, don't send to SJOIN servers.
+ */
+void   sendto_serv_butone_sjoin(aClient *one, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+#ifndef NO_FDLIST
+       Reg3    int     j;
+#endif
+       va_start(vl,pattern);
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry;
+                               i=serv_fdlist.entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]) || (one && cptr == one->from))
+                       continue;
+#ifdef NO_FDLIST
+               if (IsServer(cptr) && !SupportSJOIN(cptr))
+#else
+               if (!SupportSJOIN(cptr))
+#endif
+                       vsendto_one(cptr, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_serv_sjoin
+ *
+ * Send a message to all connected servers except the client 'one'.
+ * BUT only send to SJOIN servers.
+ */
+void   sendto_serv_sjoin(aClient *one, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+#ifndef NO_FDLIST
+       Reg3    int     j;
+#endif 
+       va_start(vl,pattern);
+
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry;
+                               i=serv_fdlist.entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]) || (one && cptr == one->from))
+                       continue;
+#ifdef NO_FDLIST
+               if (IsServer(cptr) && SupportSJOIN(cptr))
+#else
+               if (SupportSJOIN(cptr))
+#endif
+                       vsendto_one(cptr, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_serv_butone_nickv2
+ *
+ * Send a message to all connected servers except the client 'one'.
+ * BUT, don't send to NICKv2 servers.
+ */
+void   sendto_serv_butone_nickv2(aClient *one, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+#ifndef NO_FDLIST
+       Reg3    int     j;
+#endif
+       va_start(vl,pattern);
+
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry;
+                               i=serv_fdlist.entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]) || (one && cptr == one->from))
+                       continue;
+#ifdef NO_FDLIST
+               if (IsServer(cptr) && !SupportNICKv2(cptr))
+#else
+               if (!SupportNICKv2(cptr))
+#endif
+                       vsendto_one(cptr, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_serv_nickv2
+ *
+ * Send a message to all connected servers except the client 'one'.
+ * BUT only send to NICKv2 servers.
+ */
+void   sendto_serv_nickv2(aClient *one, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+#ifndef NO_FDLIST
+       Reg3    int     j;
+#endif 
+       va_start(vl,pattern);
+
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=serv_fdlist.entry[j=1];j<=serv_fdlist.last_entry;
+                               i=serv_fdlist.entry[++j])
+#endif
+           {
+               if (!(cptr = local[i]) || (one && cptr == one->from))
+                       continue;
+#ifdef NO_FDLIST
+               if (IsServer(cptr) && SupportNICKv2(cptr))
+#else
+               if (SupportNICKv2(cptr))
+#endif
+                       vsendto_one(cptr, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_common_channels()
+ * 
+ * Sends a message to all people (inclusing user) on local server who are
+ * in same channel with user.
+ */
+void sendto_common_channels(aClient *user, char *pattern, ...)
+{
+va_list     vl;
+
+register Link *channels;
+register Link *users;
+register aClient *cptr;
+
+   va_start(vl,pattern);
+   memset((char *) sentalong, '\0', sizeof(sentalong));
+   if (user->fd >= 0)
+      sentalong[user->fd] = 1;
+   if (user->user)
+      for (channels = user->user->channel; channels; channels = channels->next)
+        for (users = channels->value.chptr->members; users; users = users->next) {
+           cptr = users->value.cptr;
+           if (!MyConnect(cptr) || sentalong[cptr->fd])
+              continue;
+           sentalong[cptr->fd]++;
+           vsendto_prefix_one(cptr, user, pattern, vl);
+        }
+   if (MyConnect(user))
+      vsendto_prefix_one(user, user, pattern, vl);
+   va_end(vl);
+   return;
+}
+/*
+ * sendto_channel_butserv
+ *
+ * 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, ...)
+{
+       va_list vl;
+       Reg1    Link    *lp;
+       Reg2    aClient *acptr;
+
+       for (va_start(vl,pattern), lp = chptr->members; lp; lp = lp->next)
+               if (MyConnect(acptr = lp->value.cptr))
+                       vsendto_prefix_one(acptr, from, pattern, vl);
+       va_end(vl);
+       return;
+}
+
+/*
+** send a msg to all ppl on servers/hosts that match a specified mask
+** (used for enhanced PRIVMSGs)
+**
+** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de)
+*/
+
+static int     match_it(one, mask, what)
+aClient *one;
+char   *mask;
+int    what;
+{
+       switch (what)
+       {
+       case MATCH_HOST:
+               return (match(mask, one->user->realhost)==0);
+       case MATCH_SERVER:
+       default:
+               return (match(mask, one->user->server)==0);
+       }
+}
+
+/*
+ * sendto_match_servs
+ *
+ * send to all servers which match the mask at the end of a channel name
+ * (if there is a mask present) or to all if no mask.
+ */
+void   sendto_match_servs(aChannel *chptr, aClient *from, char *format, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+       char    *mask;
+
+       va_start(vl, format);
+
+       if (chptr)
+           {
+               if (*chptr->chname == '&')
+                       return;
+               if (mask = (char *)rindex(chptr->chname, ':'))
+                       mask++;
+           }
+       else
+               mask = (char *)NULL;
+
+       for (i = 0; i <= highest_fd; i++)
+           {
+               if (!(cptr = local[i]))
+                       continue;
+               if ((cptr == from) || !IsServer(cptr))
+                       continue;
+               if (!BadPtr(mask) && IsServer(cptr) &&
+                   match(mask, cptr->name))
+                       continue;
+               vsendto_one(cptr, format, vl);
+           }
+       va_end(vl);
+}
+
+/*
+ * sendto_match_butone
+ *
+ * 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, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr, *acptr;
+       char    cansendlocal, cansendglobal;
+  
+       va_start(vl,pattern);
+       if (MyConnect(from))
+           {
+               cansendlocal = (OPCanLNotice(from)) ? 1 : 0;
+               cansendglobal = (OPCanGNotice(from)) ? 1 : 0;
+           }
+       else
+               cansendlocal = cansendglobal = 1;
+
+       for (i = 0; i <= highest_fd; i++)
+           {
+               if (!(cptr = local[i]))
+                       continue;       /* that clients are not mine */
+               if (cptr == one)        /* must skip the origin !! */
+                       continue;
+               if (IsServer(cptr))
+                   {
+                       if (!cansendglobal)
+                               continue;
+                       for (acptr = client; acptr; acptr = acptr->next)
+                               if (IsRegisteredUser(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;
+                       /* ... but only if there *IS* a matching person */
+                   }
+               /* my client, does he match ? */
+               else if (!cansendlocal || (!(IsRegisteredUser(cptr) &&
+                       match_it(cptr, mask, what))))
+                       continue;
+               vsendto_prefix_one(cptr, from, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_all_butone.
+ *
+ * Send a message to all connections except 'one'. The basic wall type
+ * message generator.
+ */
+
+void   sendto_all_butone(aClient *one, aClient *from, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+
+       for (va_start(vl,pattern), i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsMe(cptr) && one != cptr)
+                       vsendto_prefix_one(cptr, from, pattern, vl);
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_ops
+ *
+ *     Send to *local* ops only.
+ */
+void   sendto_ops(char *pattern, ...)
+{
+       va_list vl;
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       char    nbuf[1024];
+
+       va_start(vl,pattern);
+       for (i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   SendServNotice(cptr))
+                   {
+                       (void)sprintf(nbuf, ":%s NOTICE %s :*** Notice -- ",
+                                       me.name, cptr->name);
+                       (void)strncat(nbuf, pattern,
+                                       sizeof(nbuf) - strlen(nbuf));
+                       vsendto_one(cptr, nbuf, vl);
+                   }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_failops
+ *
+ *      Send to *local* mode +g ops only.
+ */
+void    sendto_failops(char *pattern, ...)
+{
+        va_list vl;
+        Reg1    aClient *cptr;
+        Reg2    int     i;
+        char    nbuf[1024];
+
+        va_start(vl,pattern);
+        for (i = 0; i <= highest_fd; i++)
+                if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                    SendFailops(cptr))
+                    {
+                        (void)sprintf(nbuf, ":%s NOTICE %s :*** Global -- ",
+                                        me.name, cptr->name);
+                        (void)strncat(nbuf, pattern,
+                                        sizeof(nbuf) - strlen(nbuf));
+                        vsendto_one(cptr, nbuf, vl);
+                    }
+       va_end(vl);
+        return;
+}
+
+/*
+ * sendto_chatops
+ *
+ *      Send to *local* mode +b ops only.
+ */
+/*
+sendto_umode does just as good a job -- codemastr
+  void    sendto_chatops(char *pattern, ...)
+{
+        va_list vl;
+        Reg1    aClient *cptr;
+        Reg2    int     i;
+        char    nbuf[1024];
+
+        va_start(vl,pattern);
+        for (i = 0; i <= highest_fd; i++)
+                if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                    SendChatops(cptr))
+                    {
+                        (void)sprintf(nbuf, ":%s NOTICE %s :*** ChatOps -- ", 
+                                        me.name, cptr->name);
+                        (void)strncat(nbuf, pattern,
+                                        sizeof(nbuf) - strlen(nbuf));
+                        vsendto_one(cptr, nbuf, vl);
+                    }
+       va_end(vl);
+        return;
+} */
+
+/*
+ * sendto_helpops
+ *
+ *     Send to mode +h people
+ */
+void   sendto_helpops(char *pattern, ...)
+{
+       va_list vl;
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       char    nbuf[1024];
+
+       va_start(vl,pattern);
+       for (i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   IsHelpOp(cptr))
+                   {
+                       (void)sprintf(nbuf, ":%s NOTICE %s :*** HelpOp -- ",
+                                     me.name, cptr->name);
+                       (void)strncat(nbuf, pattern,
+                                     sizeof(nbuf) - strlen(nbuf));
+                       vsendto_one(cptr, nbuf, vl);
+                   }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_umode
+ *
+ *  Send to specified umode
+ */
+void   sendto_umode(int umodes, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       char    nbuf[1024];
+       Reg3    int     w;
+       va_start(vl,pattern);
+       w = (umodes == UMODE_OPER|UMODE_CLIENT ? 1 : 0);
+       for (i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   (cptr->umodes & umodes)==umodes && ((w == 1) && !IsHybNotice(cptr)))
+                   {
+                       (void)sprintf(nbuf, ":%s NOTICE %s :",
+                               me.name, cptr->name);
+                       (void)strncat(nbuf, pattern,
+                                     sizeof(nbuf) - strlen(nbuf));
+                       vsendto_one(cptr, nbuf, vl);
+                   }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_conn_hcn
+ *
+ *  Send to umode +c && IsHybNotice(cptr)
+ */
+void   sendto_conn_hcn(char *pattern, ...)
+{
+       va_list vl;
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       char    nbuf[1024];
+
+       va_start(vl,pattern);
+       for (i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   (cptr->umodes & UMODE_CLIENT) && IsHybNotice(cptr))
+                   {
+                       (void)sprintf(nbuf, ":%s NOTICE %s :",
+                               me.name, cptr->name);
+                       (void)strncat(nbuf, pattern,
+                                     sizeof(nbuf) - strlen(nbuf));
+                       vsendto_one(cptr, nbuf, vl);
+                   }
+       va_end(vl);
+       return;
+}
+
+/*
+ * sendto_failops_whoare_opers
+ *
+ *      Send to *local* mode +g ops only who are also +o.
+ */
+void    sendto_failops_whoare_opers(char *pattern, ...)
+{
+        va_list vl;
+        Reg1    aClient *cptr;
+        Reg2    int     i;
+        char    nbuf[1024];
+
+        va_start(vl,pattern);
+        for (i = 0; i <= highest_fd; i++)
+                if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                    SendFailops(cptr) && IsAnOper(cptr))
+               {
+                        (void)sprintf(nbuf, ":%s NOTICE %s :*** Global -- ",
+                                        me.name, cptr->name);
+                        (void)strncat(nbuf, pattern,
+                                        sizeof(nbuf) - strlen(nbuf));
+                        vsendto_one(cptr, nbuf, vl);
+                    }
+       va_end(vl);
+        return;
+}
+/*
+ * sendto_locfailops
+ *
+ *      Send to *local* mode +g ops only who are also +o.
+ */
+void    sendto_locfailops(char *pattern, ...)
+{
+        va_list vl;
+        Reg1    aClient *cptr;
+        Reg2    int     i;
+        char    nbuf[1024];
+
+        va_start(vl, pattern);
+        for (i = 0; i <= highest_fd; i++)
+                if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                    SendFailops(cptr) && IsAnOper(cptr))
+                    {
+                        (void)sprintf(nbuf, ":%s NOTICE %s :*** LocOps -- ",
+                                        me.name, cptr->name);
+                        (void)strncat(nbuf, pattern,
+                                        sizeof(nbuf) - strlen(nbuf));
+                        vsendto_one(cptr, nbuf, vl);
+                    }
+       va_end(vl);
+        return;
+}
+/*
+ * sendto_opers
+ *
+ *     Send to *local* ops only. (all +O or +o people)
+ */
+void   sendto_opers(char *pattern, ...)
+{
+       va_list vl;
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       char    nbuf[1024];
+
+       va_start(vl,pattern);
+       for (i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   IsAnOper(cptr))
+                   {
+                       (void)sprintf(nbuf, ":%s NOTICE %s :*** Oper -- ",
+                                       me.name, cptr->name);
+                       (void)strncat(nbuf, pattern,
+                                       sizeof(nbuf) - strlen(nbuf));
+                       vsendto_one(cptr, nbuf, vl);
+                   }
+       va_end(vl);
+       return;
+}
+
+/* ** sendto_ops_butone
+**     Send message to all operators.
+** 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, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+
+       va_start(vl,pattern);
+       for (i=0; i <= highest_fd; i++)
+               sentalong[i] = 0;
+       for (cptr = client; cptr; cptr = cptr->next)
+           {
+               if (!SendWallops(cptr))
+                       continue;
+               i = cptr->from->fd;     /* find connection oper is on */
+               if (sentalong[i])       /* sent message along it already ? */
+                       continue;
+               if (cptr->from == one)
+                       continue;       /* ...was the one I should skip */
+               sentalong[i] = 1;
+               vsendto_prefix_one(cptr->from, from, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+/*
+** sendto_ops_butone
+**     Send message to all operators regardless of whether they are +w or 
+**     not.. 
+** one - client not to send message to
+** from- client which message is from *NEVER* NULL!!
+*/
+void   sendto_opers_butone(aClient *one, aClient *from, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+
+       va_start(vl,pattern);
+       for (i=0; i <= highest_fd; i++)
+               sentalong[i] = 0;
+       for (cptr = client; cptr; cptr = cptr->next)
+           {
+               if (!IsAnOper(cptr))
+                       continue;
+               i = cptr->from->fd;     /* find connection oper is on */
+               if (sentalong[i])       /* sent message along it already ? */
+                       continue;
+               if (cptr->from == one)
+                       continue;       /* ...was the one I should skip */
+               sentalong[i] = 1;
+               vsendto_prefix_one(cptr->from, from, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+/*
+** sendto_ops_butme
+**     Send message to all operators except local ones
+** from- client which message is from *NEVER* NULL!!
+*/
+void   sendto_ops_butme(aClient *from, char *pattern, ...)
+{
+       va_list vl;
+       Reg1    int     i;
+       Reg2    aClient *cptr;
+
+       va_start(vl,pattern);
+       for (i=0; i <= highest_fd; i++)
+               sentalong[i] = 0;
+       for (cptr = client; cptr; cptr = cptr->next)
+           {
+               if (!SendWallops(cptr))
+                       continue;
+               i = cptr->from->fd;     /* find connection oper is on */
+               if (sentalong[i])       /* sent message along it already ? */
+                       continue;
+               if (!strcmp(cptr->user->server, me.name))       /* a locop */
+                       continue;
+               sentalong[i] = 1;
+               vsendto_prefix_one(cptr->from, from, pattern, vl);
+           }
+       va_end(vl);
+       return;
+}
+
+void vsendto_prefix_one(struct Client *to, struct Client *from,
+    const char* pattern, va_list vl)
+{
+  if (to && from && MyClient(to) && from->user)
+  {
+    static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
+    char *par;
+    int flag = 0;
+    struct User *user = from->user;
+
+    par = va_arg(vl, char *);
+    strcpy(sender, from->name);
+    if (user)
+    {
+      if (*user->username)
+      {
+        strcat(sender, "!");
+        strcat(sender, user->username);
+      }
+      if (*user->realhost && !MyConnect(from))
+      {
+        strcat(sender, "@");
+        (void)strcat(sender, (!IsHidden(from) ?user->realhost:user->virthost));
+        flag = 1;
+      }
+    }
+    /*
+     * Flag is used instead of strchr(sender, '@') for speed and
+     * also since username/nick may have had a '@' in them. -avalon
+     */
+    if (!flag && MyConnect(from) && *user->realhost)
+    {
+      strcat(sender, "@");
+      strcat(sender, (!IsHidden(from) ? from->sockhost : user->virthost));
+    }
+    *sendbuf = ':';
+    strcpy(&sendbuf[1], sender);
+    /* Assuming 'pattern' always starts with ":%s ..." */
+    vsprintf(sendbuf + strlen(sendbuf), &pattern[3], vl);
+  }
+  else
+    vsprintf(sendbuf, pattern, vl);
+  sendbufto_one(to);
+}
+/*
+ * sendto_prefix_one
+ *
+ * to - destination client
+ * from - client which message is from
+ *
+ * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!!
+ * -avalon
+ */
+
+void sendto_prefix_one(aClient *to, aClient *from, const char *pattern, ...)
+{
+  va_list vl;
+  va_start(vl, pattern);
+  vsendto_prefix_one(to, from, pattern, vl);
+  va_end(vl);
+}
+/*
+ * sendto_realops
+ *
+ *     Send to *local* ops only but NOT +s nonopers.
+ */
+void   sendto_realops(char *pattern, ...)
+{
+       va_list vl;
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+#ifndef NO_FDLIST
+       Reg3    int     j;
+#endif
+       char    nbuf[1024];
+
+       va_start(vl, pattern);
+#ifdef NO_FDLIST
+       for (i = 0; i <= highest_fd; i++)
+#else
+        for (i=oper_fdlist.entry[j=1];j<=oper_fdlist.last_entry;
+                       i=oper_fdlist.entry[++j])
+#endif
+#ifdef NO_FDLIST
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   IsOper(cptr))
+#else
+               if ((cptr = local[i]))
+#endif
+                   {
+                       (void)sprintf(nbuf, ":%s NOTICE %s :*** Notice -- ",
+                                       me.name, cptr->name);
+                       (void)strncat(nbuf, pattern,
+                                       sizeof(nbuf) - strlen(nbuf));
+                       vsendto_one(cptr, nbuf, vl);
+                   }
+       va_end(vl);
+       return;
+}
+
+void   sendto_connectnotice(nick, user,sptr)
+char   *nick;
+anUser *user;
+aClient *sptr;
+{
+       Reg1    aClient *cptr;
+       Reg2    int     i;
+       char    connectd[1024];
+       char    connecth[1024];
+       sprintf(connectd, "*** Notice -- Client connecting on port %d: %s (%s@%s)", 
+                       sptr->acpt->port, nick, user->username, user->realhost);
+       sprintf(connecth, "*** Notice -- Client connecting: %s (%s@%s) [%s] {%d}",
+               nick, user->username, user->realhost, sptr->sockhost, get_client_class(sptr));  
+       
+       for (i = 0; i <= highest_fd; i++)
+               if ((cptr = local[i]) && !IsServer(cptr) && !IsMe(cptr) &&
+                   IsOper(cptr) && (cptr->umodes & UMODE_CLIENT))
+       {
+               if (IsHybNotice(cptr))
+                       sendto_one(cptr, ":%s NOTICE %s :%s", me.name, cptr->name, connecth);
+               else
+                       sendto_one(cptr, ":%s NOTICE %s :%s", me.name, cptr->name, connectd);
+                       
+       }
+}
\ No newline at end of file
diff --git a/src/strtoul.c b/src/strtoul.c
new file mode 100644 (file)
index 0000000..337d16e
--- /dev/null
@@ -0,0 +1,118 @@
+/*     $NetBSD: strtoul.c,v 1.9 1996/07/20 01:00:57 jtc Exp $  */
+
+/*
+ * Copyright (c) 1990 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *sccsid = "from: @(#)strtoul.c     5.3 (Berkeley) 2/23/91";
+#else
+static char *rcsid = "$NetBSD: strtoul.c,v 1.9 1996/07/20 01:00:57 jtc Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff.  Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(nptr, endptr, base)
+       char *nptr;
+       char **endptr;
+       int base;
+{
+       char *s;
+       unsigned long acc, cutoff;
+       int c;
+       int neg, any, cutlim;
+
+       /*
+        * See strtol for comments as to the logic used.
+        */
+       s = nptr;
+       do {
+               c = (unsigned char) *s++;
+       } while (isspace(c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else {
+               neg = 0;
+               if (c == '+')
+                       c = *s++;
+       }
+       if ((base == 0 || base == 16) &&
+           c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0)
+               base = c == '0' ? 8 : 10;
+
+       cutoff = ULONG_MAX / (unsigned long)base;
+       cutlim = ULONG_MAX % (unsigned long)base;
+       for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+               if (isdigit(c))
+                       c -= '0';
+               else if (isalpha(c))
+                       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+               else
+                       break;
+               if (c >= base)
+                       break;
+               if (any < 0)
+                       continue;
+               if (acc > cutoff || acc == cutoff && c > cutlim) {
+                       any = -1;
+                       acc = ULONG_MAX;
+                       errno = ERANGE;
+               } else {
+                       any = 1;
+                       acc *= (unsigned long)base;
+                       acc += c;
+               }
+       }
+       if (neg && any > 0)
+               acc = -acc;
+       if (endptr != 0)
+               *endptr = (char *) (any ? s - 1 : nptr);
+       return (acc);
+}
diff --git a/src/support.c b/src/support.c
new file mode 100644 (file)
index 0000000..7e7f989
--- /dev/null
@@ -0,0 +1,500 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, common/support.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.
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)support.c 2.21 4/13/94 1990, 1991 Armin Gruner;\
+1992, 1993 Darren Reed";
+#endif
+
+#include "config.h"
+#ifdef DYNIXPTX
+#include <sys/timers.h>
+#include <stddef.h>
+#endif
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#ifdef _WIN32
+#include <io.h>
+#else
+
+ID_CVS("$Id$");
+
+extern int errno; /* ...seems that errno.h doesn't define this everywhere */
+#endif
+extern void    outofmemory();
+
+#ifdef NEED_STRTOKEN
+/*
+**     strtoken.c --   walk through a string of tokens, using a set
+**                     of separators
+**                     argv 9/90
+**
+**     $Id$
+*/
+
+char *strtoken(save, str, fs)
+char **save;
+char *str, *fs;
+{
+    char *pos = *save; /* keep last position across calls */
+    Reg1 char *tmp;
+
+    if (str)
+       pos = str;              /* new string scan */
+
+    while (pos && *pos && index(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 && index(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 /* NEED_STRTOKEN */
+
+#ifdef NEED_STRTOK
+/*
+** NOT encouraged to use!
+*/
+
+char *strtok2(str, fs)
+char *str, *fs;
+{
+    static char *pos;
+
+    return strtoken(&pos, str, fs);
+}
+
+#endif /* NEED_STRTOK */
+
+#ifdef NEED_STRERROR
+/*
+**     strerror - return an appropriate system error string to a given errno
+**
+**                argv 11/90
+**     $Id$
+*/
+
+char *strerror(err_no)
+int err_no;
+{
+       extern  char    *sys_errlist[];  /* Sigh... hopefully on all systems */
+       extern  int     sys_nerr;
+
+       static  char    buff[40];
+       char    *errp;
+
+       errp = (err_no > sys_nerr ? (char *)NULL : sys_errlist[err_no]);
+
+       if (errp == (char *)NULL)
+           {
+               errp = buff;
+#ifndef _WIN32
+               (void) sprintf(errp, "Unknown Error %d", err_no);
+#else
+               switch (err_no)
+                   {
+                       case WSAECONNRESET:
+                               sprintf(errp, "Connection reset by peer");
+                               break;
+                       default:
+                               sprintf(errp, "Unknown Error %d", err_no);
+                               break;
+                   }
+#endif
+           }
+       return errp;
+}
+
+#endif /* NEED_STRERROR */
+
+/*
+**     inetntoa  --    changed name to remove collision possibility and
+**                     so behaviour is gaurunteed 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
+**     $Id$
+*/
+
+char   *inetntoa(in)
+char   *in;
+{
+       static  char    buf[16];
+       Reg1    u_char  *s = (u_char *)in;
+       Reg2    int     a,b,c,d;
+
+       a = (int)*s++;
+       b = (int)*s++;
+       c = (int)*s++;
+       d = (int)*s++;
+       (void) sprintf(buf, "%d.%d.%d.%d", a,b,c,d );
+
+       return buf;
+}
+
+#ifdef NEED_INET_NETOF
+/*
+**     inet_netof --   return the net portion of an internet number
+**                     argv 11/90
+**     $Id$
+**
+*/
+
+int inet_netof(in)
+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 /* NEED_INET_NETOF */
+
+
+#if defined(DEBUGMODE)
+void   dumpcore(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+char   *msg, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9;
+{
+       static  time_t  lastd = 0;
+       static  int     dumps = 0;
+       char    corename[12];
+       time_t  now;
+       int     p;
+
+       now = time(NULL);
+
+       if (!lastd)
+               lastd = now;
+       else if (now - lastd < 60 && dumps > 2)
+               (void)s_die();
+       if (now - lastd > 60)
+           {
+               lastd = now;
+               dumps = 1;
+           }
+       else
+               dumps++;
+#if !defined(_WIN32) && !defined(_AMIGA)
+       p = getpid();
+       if (fork()>0) {
+               kill(p, 3);
+               kill(p, 9);
+       }
+       write_pidfile();
+       (void)sprintf(corename, "core.%d", p);
+       (void)rename("core", corename);
+       Debug((DEBUG_FATAL, "Dumped core : core.%d", p));
+       sendto_ops("Dumped core : core.%d", p);
+#endif
+       Debug((DEBUG_FATAL, msg, p1, p2, p3, p4, p5, p6, p7, p8, p9));
+       sendto_ops(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+               (void)s_die();
+}
+
+static char    *marray[20000];
+static int     mindex = 0;
+
+#define        SZ_EX   (sizeof(char *) + sizeof(size_t) + 4)
+#define        SZ_CHST (sizeof(char *) + sizeof(size_t))
+#define        SZ_CH   (sizeof(char *))
+#define        SZ_ST   (sizeof(size_t))
+
+char   *MyMalloc(x)
+size_t x;
+{
+       register int    i;
+       register char   **s;
+       char    *ret;
+
+#ifndef _WIN32
+       ret = (char *)malloc(x + (size_t)SZ_EX);
+#else
+       ret = (char *)GlobalAlloc(GPTR, x + (size_t)SZ_EX);
+#endif
+
+       if (!ret)
+           {
+               outofmemory();
+           }
+       bzero(ret, (int)x + SZ_EX);
+       bcopy((char *)&ret, ret, SZ_CH);
+       bcopy((char *)&x, ret + SZ_CH, SZ_ST);
+       bcopy("VAVA", ret + SZ_CHST + (int)x, 4);
+       Debug((DEBUG_MALLOC, "MyMalloc(%ld) = %#x", x, ret+8));
+       for(i = 0, s = marray; *s && i < mindex; i++, s++)
+               ;
+       if (i < 20000)
+           {
+               *s = ret;
+               if (i == mindex)
+                       mindex++;
+           }
+       return ret + SZ_CHST;
+    }
+
+char    *MyRealloc(x, y)
+char   *x;
+size_t y;
+    {
+       register int    l;
+       register char   **s;
+       char    *ret, *cp;
+       size_t  i;
+       int     k;
+
+       x -= SZ_CHST;
+       bcopy(x, (char *)&cp, SZ_CH);
+       bcopy(x + SZ_CH, (char *)&i, SZ_ST);
+       bcopy(x + (int)i + SZ_CHST, (char *)&k, 4);
+       if (bcmp((char *)&k, "VAVA", 4) || (x != cp))
+               dumpcore("MyRealloc %#x %d %d %#x %#x", x, y, i, cp, k);
+#ifndef _WIN32
+       ret = (char *)realloc(x, y + (size_t)SZ_EX);
+#else
+       ret = (char *)GlobalReAlloc(x, y + (size_t)SZ_EX, GMEM_MOVEABLE|GMEM_ZEROINIT);
+#endif
+
+       if (!ret)
+           {
+               outofmemory();
+           }
+       bcopy((char *)&ret, ret, SZ_CH);
+       bcopy((char *)&y, ret + SZ_CH, SZ_ST);
+       bcopy("VAVA", ret + SZ_CHST + (int)y, 4);
+       Debug((DEBUG_NOTICE, "MyRealloc(%#x,%ld) = %#x", x, y, ret + SZ_CHST));
+       for(l = 0, s = marray; *s != x && l < mindex; l++, s++)
+               ;
+       if (l < mindex)
+               *s = NULL;
+       else if (l == mindex)
+               Debug((DEBUG_MALLOC, "%#x !found", x));
+       for(l = 0, s = marray; *s && l < mindex; l++,s++)
+               ;
+       if (l < 20000)
+           {
+               *s = ret;
+               if (l == mindex)
+                       mindex++;
+           }
+       return ret + SZ_CHST;
+    }
+
+void   MyFree(x)
+char   *x;
+{
+       size_t  i;
+       char    *j;
+       u_char  k[4];
+       register int    l;
+       register char   **s;
+
+       if (!x)
+               return;
+       x -= SZ_CHST;
+
+       bcopy(x, (char *)&j, SZ_CH);
+       bcopy(x + SZ_CH, (char *)&i, SZ_ST);
+       bcopy(x + SZ_CHST + (int)i, (char *)k, 4);
+
+       if (bcmp((char *)k, "VAVA", 4) || (j != x))
+               dumpcore("MyFree %#x %ld %#x %#x", x, i, j,
+                        (k[3]<<24) | (k[2]<<16) | (k[1]<<8) | k[0]);
+
+#undef free
+#ifndef _WIN32
+       (void)free(x);
+#else
+       (void)GlobalFree(x);
+#endif
+#define        free(x) MyFree(x)
+       Debug((DEBUG_MALLOC, "MyFree(%#x)",x + SZ_CHST));
+
+       for (l = 0, s = marray; *s != x && l < mindex; l++, s++)
+               ;
+       if (l < mindex)
+               *s = NULL;
+       else if (l == mindex)
+               Debug((DEBUG_MALLOC, "%#x !found", x));
+}
+
+#else
+char   *MyMalloc(x)
+size_t x;
+{
+#ifndef _WIN32
+       char *ret = (char *)malloc(x);
+#else
+       char *ret = (char *)GlobalAlloc(GPTR, x);
+#endif
+
+       if (!ret)
+           {
+               outofmemory();
+           }
+       return  ret;
+}
+
+char   *MyRealloc(x, y)
+char   *x;
+size_t y;
+    {
+#ifndef _WIN32
+       char *ret = (char *)realloc(x, y);
+#else
+       char *ret = (char *)GlobalReAlloc(x, y, GMEM_MOVEABLE|GMEM_ZEROINIT);
+#endif
+
+       if (!ret)
+           {
+               outofmemory();
+           }
+       return ret;
+    }
+#endif
+
+
+/*
+** read a string terminated by \r or \n in from a fd
+**
+** Created: Sat Dec 12 06:29:58 EST 1992 by avalon
+** Returns:
+**     0 - EOF
+**     -1 - error on read
+**     >0 - number of bytes returned (<=num)
+** After opening a fd, it is necessary to init dgets() by calling it as
+**     dgets(x,y,0);
+** to mark the buffer as being empty.
+*/
+int    dgets(fd, buf, num)
+int    fd, num;
+char   *buf;
+{
+       static  char    dgbuf[8192];
+       static  char    *head = dgbuf, *tail = dgbuf;
+       register char   *s, *t;
+       register int    n, nr;
+
+       /*
+       ** Sanity checks.
+       */
+       if (head == tail)
+               *head = '\0';
+       if (!num)
+           {
+               head = tail = dgbuf;
+               *head = '\0';
+               return 0;
+           }
+       if (num > sizeof(dgbuf) - 1)
+               num = sizeof(dgbuf) - 1;
+dgetsagain:
+       if (head > dgbuf)
+           {
+               for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
+                       *t++ = *s++;
+               tail = t;
+               head = dgbuf;
+           }
+       /*
+       ** check input buffer for EOL and if present return string.
+       */
+       if (head < tail &&
+           ((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail)
+           {
+               n = MIN(s - head + 1, num);     /* at least 1 byte */
+dgetsreturnbuf:
+               bcopy(head, buf, n);
+               head += n;
+               if (head == tail)
+                       head = tail = dgbuf;
+               return n;
+           }
+
+       if (tail - head >= num)         /* dgets buf is big enough */
+           {
+               n = num;
+               goto dgetsreturnbuf;
+           }
+
+       n = sizeof(dgbuf) - (tail - dgbuf) - 1;
+       nr = read(fd, tail, n);
+       if (nr == -1)
+           {
+               head = tail = dgbuf;
+               return -1;
+           }
+       if (!nr)
+           {
+               if (head < tail)
+                   {
+                       n = MIN(tail - head, num);
+                       goto dgetsreturnbuf;
+                   }
+               head = tail = dgbuf;
+               return 0;
+           }
+       tail += nr;
+       *tail = '\0';
+       for (t = head; (s = index(t, '\n')); )
+           {
+               if ((s > head) && (s > dgbuf))
+                   {
+                       t = s-1;
+                       for (nr = 0; *t == '\\'; nr++)
+                               t--;
+                       if (nr & 1)
+                           {
+                               t = s+1;
+                               s--;
+                               nr = tail - t;
+                               while (nr--)
+                                       *s++ = *t++;
+                               tail -= 2;
+                               *tail = '\0';
+                           }
+                       else
+                               s++;
+                   }
+               else
+                       s++;
+               t = s;
+           }
+       *tail = '\0';
+       goto dgetsagain;
+}
diff --git a/src/userload.c b/src/userload.c
new file mode 100644 (file)
index 0000000..c0e8b04
--- /dev/null
@@ -0,0 +1,367 @@
+/****************************************************************************
+ *  Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
+ *  Written 2/93.  Originally grafted into irc2.7.2g 4/93.
+ *
+ *   IRC - Internet Relay Chat, ircd/userload.c
+ *   Copyright (C) 1990 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 "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "userload.h"
+#include <stdio.h>
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include <signal.h>
+#ifndef _WIN32
+#include <sys/resource.h>
+#endif
+#include "h.h"
+
+ID_CVS("$Id$");
+
+struct current_load_struct current_load_data;
+struct load_entry *load_list_head = NULL, *load_list_tail = NULL,
+                  *load_free_head = NULL, *load_free_tail = NULL;
+
+#ifdef DEBUGMODE
+clock_t        clock_last = 0;
+#endif
+
+void update_load()
+{
+  static struct timeval now, last;
+  register struct load_entry *cur_load_entry;
+
+  /* This seems to get polluted on startup by an exit_client()
+   * before any connections have been recorded.
+   */
+  if (current_load_data.local_count > MAXCONNECTIONS ||
+      current_load_data.client_count > MAXCONNECTIONS ||
+      current_load_data.conn_count > MAXCONNECTIONS)
+    bzero(&current_load_data, sizeof(struct current_load_struct));
+  
+  memcpy(&last, &now, sizeof(struct timeval));
+#ifndef _WIN32
+  if (gettimeofday(&now, NULL) != 0)
+    return;  /* error getting time of day--can't calculate time diff */
+#else
+  /* Well, since the windows libs don't have gettimeofday() we have
+   * to improvise a bit, hopefully this will achieve close to the
+   * same result.  -Cabal95
+   */
+  now.tv_sec = TStime();
+#endif
+
+  if (load_free_tail == NULL) {
+    if ((cur_load_entry =
+        (struct load_entry *) MyMalloc(sizeof(struct load_entry))) == NULL)
+      return;
+    /* printf("malloc pointer: %x\n", cur_load_entry); */
+  } else {
+    cur_load_entry = load_free_tail;
+    load_free_tail = cur_load_entry->prev;
+    if (load_free_tail == NULL)
+      load_free_head = NULL;
+    /* printf("free pointer: %x\n", cur_load_entry); */
+  }
+  if (load_list_tail != NULL) {
+#ifndef _WIN32
+    cur_load_entry->time_incr = ((now.tv_sec * 1000 + now.tv_usec / 1000 + 5)
+          - (last.tv_sec * 1000 + last.tv_usec / 1000)) / 10;
+#else
+    /* Don't even use *.tv_usec since its an unknown value.  -Cabal95 */
+    cur_load_entry->time_incr = ((now.tv_sec * 1000 + 5)
+          - last.tv_sec * 1000) / 10;
+#endif
+    cur_load_entry->local_count = current_load_data.local_count;
+    cur_load_entry->client_count = current_load_data.client_count;
+    cur_load_entry->conn_count = current_load_data.conn_count;
+#ifdef DEBUGMODE
+    cur_load_entry->cpu_usage = (clock()-clock_last);
+    clock_last = clock();
+#endif
+  } else {
+    load_list_head = cur_load_entry;
+    bzero(cur_load_entry, sizeof(struct load_entry));
+    cur_load_entry->time_incr = 1;
+  }
+  cur_load_entry->prev = load_list_tail;
+  load_list_tail = cur_load_entry;
+}
+
+
+void calc_load(sptr, parv)
+aClient *sptr;
+char    *parv;  /* we only get passed the original parv[0] */
+{
+  register struct load_entry *cur_load_entry;
+  struct load_entry *last;
+#ifdef DEBUGMODE
+  u_long secs = 0, adj_secs, total[4], adj[4];/*[local,client,conn,cpu]*/
+  int i;
+  u_int times[5][4]; /* [min,hour,day,Yest,YYest][local,client,conn,cpu] */
+  char what[4][HOSTLEN + 1];
+
+  bzero(total, 4 * sizeof(u_long));
+#else
+  u_long secs = 0, adj_secs, total[3], adj[3];/*[local,client,conn]*/
+  int i, times[5][3]; /* [min,hour,day,Yest,YYest][local,client,conn] */
+  char what[3][HOSTLEN + 1];
+
+  bzero(total, 3 * sizeof(u_long));
+#endif
+
+  current_load_data.entries = 0;
+
+  update_load();  /* we want stats accurate as of *now* */
+
+  for (cur_load_entry = load_list_tail; (secs < 6000) &&
+       (cur_load_entry != NULL); cur_load_entry = cur_load_entry->prev) {
+    u_long time_incr = cur_load_entry->time_incr;
+    total[0] += time_incr * cur_load_entry->local_count;
+    total[1] += time_incr * cur_load_entry->client_count;
+    total[2] += time_incr * cur_load_entry->conn_count;
+#ifdef DEBUGMODE
+    total[3] += cur_load_entry->cpu_usage;
+#endif
+    last = cur_load_entry;
+    secs += cur_load_entry->time_incr;
+    current_load_data.entries++;
+  }
+  if ((secs > 6000) && (last != NULL)) {
+    adj_secs = secs - 6000;
+    adj[0] = adj_secs * last->local_count;
+    adj[1] = adj_secs * last->client_count;
+    adj[2] = adj_secs * last->conn_count;
+#ifdef DEBUGMODE
+    times[0][3] = total[3]-(last->cpu_usage*(double)adj_secs/last->time_incr);
+  } else {
+    adj_secs = adj[0] = adj[1] = adj[2] = adj[3] = 0;
+    times[0][3] = total[3];
+  }
+#else
+  } else
+    adj_secs = adj[0] = adj[1] = adj[2] = 0;
+#endif
+  for (i = 0; i < 3; i++) {
+    times[0][i] = ((total[i] - adj[i]) * 1000 / (secs - adj_secs) + 5) / 10;
+  }
+
+  secs = (secs + 5) / 10;
+  for (i = 0; i < 3; i++)
+    total[i] = (total[i] + 5) / 10;
+
+  for ( ; (secs < 36000) && (cur_load_entry != NULL); secs +=
+       (cur_load_entry->time_incr + 5) / 10, cur_load_entry =
+       cur_load_entry->prev, current_load_data.entries++) {
+    u_long time_incr = (cur_load_entry->time_incr + 5) / 10;
+    total[0] += time_incr * cur_load_entry->local_count;
+    total[1] += time_incr * cur_load_entry->client_count;
+    total[2] += time_incr * cur_load_entry->conn_count;
+#ifdef DEBUGMODE
+    total[3] += cur_load_entry->cpu_usage;
+#endif
+    last = cur_load_entry;
+  }
+  if ((secs > 36000) && (last != NULL)) {
+    adj_secs = secs - 36000;
+    adj[0] = adj_secs * last->local_count;
+    adj[1] = adj_secs * last->client_count;
+    adj[2] = adj_secs * last->conn_count;
+#ifdef DEBUGMODE
+    times[1][3] = total[3]-(last->cpu_usage*(double)adj_secs/last->time_incr);
+  } else {
+    adj_secs = adj[0] = adj[1] = adj[2] = adj[3] = 0;
+    times[1][3] = total[3];
+  }
+#else
+  } else
+    adj_secs = adj[0] = adj[1] = adj[2] = 0;
+#endif
+  for (i = 0; i < 3; i++) {
+    times[1][i] = ((total[i] - adj[i]) * 100 / (secs - adj_secs) + 5) / 10;
+  }
+
+  secs = (secs + 5) / 10;
+  for (i = 0; i < 3; i++)
+    total[i] = (total[i] + 5) / 10;
+
+  for ( ; (secs < 86400) && (cur_load_entry != NULL); secs +=
+       (cur_load_entry->time_incr + 50) / 100, cur_load_entry =
+       cur_load_entry->prev, current_load_data.entries++) {
+    u_long time_incr = (cur_load_entry->time_incr + 50) / 100;
+    total[0] += time_incr * cur_load_entry->local_count;
+    total[1] += time_incr * cur_load_entry->client_count;
+    total[2] += time_incr * cur_load_entry->conn_count;
+#ifdef DEBUGMODE
+    total[3] += cur_load_entry->cpu_usage;
+#endif
+    last = cur_load_entry;
+  }
+  if ((secs > 86400) && (last != NULL)) {
+    adj_secs = secs - 86400;
+    adj[0] = adj_secs * last->local_count;
+    adj[1] = adj_secs * last->client_count;
+    adj[2] = adj_secs * last->conn_count;
+#ifdef DEBUGMODE
+    times[2][3] = total[3]-(last->cpu_usage*(double)adj_secs/last->time_incr);
+  } else {
+    adj_secs = adj[0] = adj[1] = adj[2] = adj[3] = 0;
+    times[2][3] = total[3];
+  }
+#else
+  } else
+    adj_secs = adj[0] = adj[1] = adj[2] = 0;
+#endif
+  for (i = 0; i < 3; i++) {
+    times[2][i] = ((total[i] - adj[i]) * 10 / (secs - adj_secs) + 5) / 10;
+  }
+
+#ifdef DEBUGMODE
+  bzero(total, 4 * sizeof(u_long));
+#else
+  bzero(total, 3 * sizeof(u_long));
+#endif
+
+  for (secs = 1 ; (secs < 86400) && (cur_load_entry != NULL); secs +=
+       (cur_load_entry->time_incr + 50) / 100, cur_load_entry =
+       cur_load_entry->prev, current_load_data.entries++) {
+    u_long time_incr = (cur_load_entry->time_incr + 50) / 100;
+    total[0] += time_incr * cur_load_entry->local_count;
+    total[1] += time_incr * cur_load_entry->client_count;
+    total[2] += time_incr * cur_load_entry->conn_count;
+#ifdef DEBUGMODE
+    total[3] += cur_load_entry->cpu_usage;
+#endif
+    last = cur_load_entry;
+  }
+  if ((secs > 86400) && (last != NULL)) {
+    adj_secs = secs - 86400;
+    adj[0] = adj_secs * last->local_count;
+    adj[1] = adj_secs * last->client_count;
+    adj[2] = adj_secs * last->conn_count;
+#ifdef DEBUGMODE
+    times[3][3] = total[3]-(last->cpu_usage*(double)adj_secs/last->time_incr);
+  } else {
+    adj_secs = adj[0] = adj[1] = adj[2] = adj[3] = 0;
+    times[3][3] = total[3];
+  }
+#else
+  } else
+    adj_secs = adj[0] = adj[1] = adj[2] = 0;
+#endif
+  for (i = 0; i < 3; i++) {
+    times[3][i] = ((total[i] - adj[i]) * 10 / (secs - adj_secs) + 5) / 10;
+  }
+
+#ifdef DEBUGMODE
+  bzero(total, 4 * sizeof(u_long));
+#else
+  bzero(total, 3 * sizeof(u_long));
+#endif
+
+  for (secs = 1 ; (secs < 86400) && (cur_load_entry != NULL); secs +=
+       (cur_load_entry->time_incr + 50) / 100, cur_load_entry =
+       cur_load_entry->prev, current_load_data.entries++) {
+    u_long time_incr = (cur_load_entry->time_incr + 50) / 100;
+    total[0] += time_incr * cur_load_entry->local_count;
+    total[1] += time_incr * cur_load_entry->client_count;
+    total[2] += time_incr * cur_load_entry->conn_count;
+#ifdef DEBUGMODE
+    total[3] += cur_load_entry->cpu_usage;
+#endif
+    last = cur_load_entry;
+  }
+  if ((secs > 86400) && (last != NULL)) {
+    adj_secs = secs - 86400;
+    adj[0] = adj_secs * last->local_count;
+    adj[1] = adj_secs * last->client_count;
+    adj[2] = adj_secs * last->conn_count;
+#ifdef DEBUGMODE
+    times[4][3] = total[3]-(last->cpu_usage*(double)adj_secs/last->time_incr);
+  } else {
+    adj_secs = adj[0] = adj[1] = adj[2] = adj[3] = 0;
+    times[4][3] = total[3];
+  }
+#else
+  } else
+    adj_secs = adj[0] = adj[1] = adj[2] = 0;
+#endif
+  for (i = 0; i < 3; i++) {
+    times[4][i] = ((total[i] - adj[i]) * 10 / (secs - adj_secs) + 5) / 10;
+  }
+
+  if ((cur_load_entry != NULL) && (cur_load_entry->prev != NULL) &&
+      (secs > 86400)) {  /* have nodes to free -- more than 3 days old */
+    struct load_entry *cur_free_entry = load_free_head;
+
+    load_free_head = load_list_head;
+    load_list_head = cur_load_entry;
+    if (cur_free_entry != NULL)
+      cur_free_entry->prev = cur_load_entry->prev;
+    else
+      load_free_tail = cur_load_entry->prev;
+
+    /* printf("freeing: %x  (head: %x,  tail: %x)\n", cur_load_entry->prev,
+          load_free_head, load_free_tail); */
+
+    cur_load_entry->prev = NULL;
+  }
+
+  strcpy(what[0], DOMAINNAME);
+  strcat(what[0], " clients");
+  strcpy(what[1], "total clients");
+  strcpy(what[2], "total connections");
+#ifdef DEBUGMODE
+  strcpy(what[3], "CPU usage");
+#endif
+  sendto_one(sptr,
+    ":%s NOTICE %s :Minute   Hour  Day  Yest.  YYest.  Userload for:",
+    me.name, parv);
+  for (i = 0; i < 3; i++)
+    sendto_one(sptr,
+      ":%s NOTICE %s :%3d.%02d  %3d.%01d  %3d   %3d     %3d   %s",
+      me.name, parv, times[0][i] / 100, times[0][i] % 100, times[1][i] / 10,
+      times[1][i] % 10, times[2][i], times[3][i], times[4][i], what[i]);
+
+#ifdef DEBUGMODE
+    sendto_one(sptr,
+      ":%s NOTICE %s :%6.2f%% %5.1f%% %3d%%  %3d%%    %3d%%  %s",
+      me.name, parv,
+      (double)((double)times[0][3]/(0.6*CLOCKS_PER_SEC)),
+      (double)((double)times[1][3]/(36*CLOCKS_PER_SEC)),
+      (int)((double)times[2][3]/(864*CLOCKS_PER_SEC)),
+      (int)((double)times[3][3]/(864*CLOCKS_PER_SEC)),
+      (int)((double)times[4][3]/(864*CLOCKS_PER_SEC)),
+      what[3]);
+#endif
+}
+
+
+void initload()
+{
+  bzero(&current_load_data, sizeof(struct current_load_struct));
+  update_load();  /* Initialize the load list */
+}
diff --git a/src/version.c.SH b/src/version.c.SH
new file mode 100644 (file)
index 0000000..b1374f4
--- /dev/null
@@ -0,0 +1,268 @@
+# $Id$
+case $CONFIG in
+'')     if test -r ../config.sh
+        then 
+           . ../config.sh ;
+        else 
+           spitshell=cat
+           package=IRC
+        fi
+        ;;
+esac
+
+echo "Extracting $package/ircd/version.c..."
+
+if test -r version.c
+then
+   generation=`sed -n 's/^char \*generation = \"\(.*\)\";/\1/p' < version.c`
+   if test ! "$generation" ; then generation=0; fi
+else
+   generation=0
+fi
+
+generation=`expr $generation + 1`
+
+creation=`date | \
+awk '{if (NF == 6) \
+         { print $1 " "  $2 " " $3 " "  $6 " at " $4 " " $5 } \
+else \
+         { print $1 " "  $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
+
+$spitshell >version.c <<!SUB!THIS!
+/*
+ *   IRC - Internet Relay Chat, ircd/version.c
+ *   Copyright (C) 1990 Chelsea Ashley Dyerman
+ *
+ *   This program is free software; you can 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$
+ */
+
+/*
+ * This file is generated by version.c.SH. Any changes made will go away.
+ */
+
+#include "struct.h"
+#include "version.h"
+#include "license.h"
+
+char *generation = "$generation";
+char *creation = "$creation";
+#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9
+char *version = IRCDTOTALVERSION;
+
+/* moved to s_serv.c */
+char *infotext[] = 
+{ 0 };
+
+char *unrealcredits[] =
+{
+       "-=-=-=-=-=-=-=-=-=-= [ " IRCDTOTALVERSION " Credits ] -=-=-=-=-",
+       "The people on this list is people who have helped up through",
+       "the development of UnrealIRCd. The Unreal Team would like to thank",
+       "those people by listing them here:",
+       "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=",
+       "              \2\37The UnrealIRCd Team would like to thank:\2\37",
+       "Nutcais (Phil Hawkins)",
+       "- the original shell for Unreal development, useful comments,",
+       "  being a real IRCbrother for me (Stskeeps) :), learning me a lot",
+       "  about IRC stuff, getting me more and more into IRCd business",
+       "  thanks for the *.tspre.org domain as well :)",
+       "",
+       "\37Local Irelands (http://www.local.ie)\37",
+       "- Thanks for sponsoring UnrealIRCd, test facilities,",
+       "  supporting UnrealIRCd, many new ideas, thanks for making",
+       "  Unreal what it is today:)",
+       "Mick and Sp^",
+       "- Amiga port of Unreal (UnrealIRCd/Amiga), continually strange",
+       "  comments on #UnrealIRCd, being great supporters of Unreal",
+       "  and following Unreal development all the way",
+       "DrBin (Dave) drbin@tspre.org",
+       "- Recoded & made the new UnrealIRCd/32 code, support,"
+       "  finding bugs, and tonnes of other stuff:)",
+       "{X} (Laurie) x@tspre.org",
+       "- Making the main code/design of UnrealIRCd/32 gui",
+       "  bugfounds, etc",
+       "SourceForge.net",
+       "- Good hosting, CVS hosting, FTP etc etc:) - thanks for",
+       "  supporting opensource projects",
+       "",
+       "                         \37Donations to Unreal:\37",
+       "BlueFlame^",
+       " - the first UnrealIRCd donation :)",
+       "   (yes your name can be here too;)",
+       "",
+       "              \37These people have helped alpha/betatesting\37",
+       "zshack, Headbang, Mick, Sp^, WonderWal, bomb, BullFrog, JacobD,",
+       "SirDeath, l33, EiniD, uo, RevPsych and the subgenius.net network,",
+       "^RavenX^, Mich[a]el, {X}, Fish, Shmad, Killer, BrainSCAN, RevNull,",
+       "GoNiS (irc.coreplex.org), Mikey, DrBin, and others",
+       "",
+       "",
+        "                   \2\37Stskeeps would like to thank:\2\37", 
+       "Morrigan             Julie Frederiksen",
+       " - Being a friend, thinking I was cute, uhm laying on a recycle",
+       "   thing.. 'Its the wrong recycle box Julie!', 'you got too cold",
+       "   hands *freezing*', etc ;)",
+       "DJBoxy       *unknown*                *unknown*",
+       " - For getting me up from #wIRCd bringing me to Mp3fansNet and",
+       "   after we linked to Global-IRC.net - and made people choose me",
+       "   as netadmin/ircd coder - Thanx!",
+       "TC           Tabita Clausen           (reallife)",
+       " - Making me smile of my life, talking with me, being a friend",
+       "   always got a pen sharpener when needed=/, accepting some",
+       "   wierdnesses from my side, going to the cinema with me",
+       "   and many other stuff. You'll always be in my heart,",
+       "   sorry for all the things I did or maybe didn't",
+       "   love you :(",
+       "KUFO          John MacKenzie",
+       " - Support, helping me always with getting through my life",
+       "   shells, etc etc ;)",
+       "Sporty_McFly  Cedric",
+       " - Comments, helping me when I got problems with my life and so on",
+        "   *toh* to him - Thanks!",
+       "Del_Monte     K. Hawkes               k.hawkes@zombies.force9.net",
+       " - Is just trying to put the lamer side of things across :cP",
+       "   No. I saw 2 moos. - Well having to input in seconds",
+       "   is fine if you're real quick at maths - but if not - it's a PAIN",
+       "   - Comments, bugfixes, moral support etc.;)",
+       "Skywalker     Chris Morley            skywalker@irc.ru.ac.za",
+       " - Helping me start up ROXnet at first (which brought me",
+       "   into IRCd business.. + Numerous kicks /Kills akills and alike;)",
+       "zero9000      Kevin Alford",
+       " - UnrealIRCd logo, graphics, null desu ;), ideas etc.",
+        "                   \2\37codemastr would like to thank:\2\37", 
+       "CaliMonk      Ivo Teel                calimonk@nhn.net",
+       " - Getting me started at NeoHorizon which basically got me",
+       "   started coding IRCd",
+       "Kenpo         Ian Ricci               ianr@nhn.net",
+       " - Starting me out learning *nix and giving me a place",
+       "   to develop Unreal",
+       "[FBI]         Corey Lang              *unknown*",
+       " - Being a good IRC friend and getting me started with",
+       "   IRC through our old little wIRCd net :)",
+       "",                     
+       "                            \2\37Also thanks to:\2\37",
+       "Enforcer, Andy Church, Mick, Sp^, ShadowMastr, Almaris",
+       "}{, Erik/Dr|zzt, Hedge, Kyle, MissKel, jfc, Fish, kore, Syndicate, Bagge,",
+       "#Coder-Com@Undernet, ^NeVeR^, flygirl^, DannyM, JuliuZ, wah-wah^, Lisa,",
+       "Melisa, NonMortal, Andryan, TomaHawk, Lushes, Skywalker, Merlin, Sporty_McFly,", 
+       "zero9000, #wIRCd@DALnet, comstud, dog3, Dianora, Isomer, and others who arent listed here:)",
+       "",
+       "------------------------------------------------------",
+       "Unreal 3.0 and up is dedicated to Morrigan - Julie Frederiksen",
+       "- a girl who have helped me through anything in my life, hugging",
+       "me at the right times, a definate dedication. Thanks for the kisses",
+       "long phonetalks, waste of my mobilephone ;), crying together",
+       "and making life go on for us both. I will never forget you",
+       "never leave you, love ya forever",
+       "------------------------------------------------------",
+       "This IRCd is dedicated to the love that has always been",
+       "and will always be there - Thanks to the girls & friends that kept me up",
+       "when I was down",
+       0
+};
+char *unrealcreditsold[] = 
+{
+       "------------------------------------------------------",
+       "Unreal 3.0 and up is dedicated to Morrigan - Julie Frederiksen",
+       "- a girl who have helped me through anything in my life, hugging",
+       "me at the right times, a definate dedication. Thanks for the kisses",
+       "long phonetalks, waste of my mobilephone ;), crying together",
+       "and making life go on for us both. I will never forget you",
+       "never leave you, love ya forever",
+       "------------------------------------------------------",
+       "This IRCd is dedicated to the love that has always been",
+       "and will always be there - Thanks to the girls & friends that kept me up",
+       "when I was down",
+       0
+};
+
+char *dalinfotext[] =
+    {
+        "$package --",
+        "Based on the original code written by Jarkko Oikarinen",
+        "Copyright 1988, 1989, 1990, 1991 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.",
+       "- Any name/comment should never be changed except by the one who made it -",
+       "",
+       "UnrealIRCd contains code developed by:",
+       "Potvin       Chris Wolkowski          potvin@acestar.org",
+       "RogerY       Roger Y.                 rogery@austnet.org",
+       "GZ                                    gz@starchat.net",
+       "binary",
+       "",
+       "",
+       "The following people have helped in making the DALnet ircd",
+        "that is based on irc2.8.21.mu3.2 :",
+        "",
+        "Russell      Russell Miller           russell@dal.net",
+        "Donwulff     Jukka Santala            donwulff@dal.net",
+        "Aetobatus    Michael Sawyer           aetobatus@dal.net",
+        "Dalvenjah    Sven Nielsen             dalvenjah@dal.net",
+        "Skandranon   Michael Graff            explorer@flame.org",
+        "Barubary     -                        barubary@dal.net",
+        "white_dragon Chip Norkus              wd@dal.net",
+        "DuffJ        Dafydd James             duffj@dal.net",
+        "taz          David Kopstain           taz@dal.net",
+        "NikB         Nik Bougalis             nikb@dal.net",
+        "Rakarra      -                        rakarra@dal.net",
+        "DarkRot      Lucas Madar              darkrot@dal.net",
+        "Studded      -                        studded@dal.net",
+        "JoelKatz     David Schwartz           joelkatz@dal.net",
+        "",
+        "This product includes software developed by Colin Plumb.",
+        "",
+        "The following persons have made many changes and enhancements to the",
+        "code and still know how IRC really works if you have questions about it:",
+        "",
+        "Run          Carlo Kid                carlo@runaway.xs4all.nl",
+        "Avalon       Darren Reed              avalon@coombs.anu.edu.au",
+        "msa          Markku Savela            Markku.Savela@vtt.fi",
+        "Wumpus       Greg Lindahl             gl8f@virginia.edu",
+        "WiZ          Jarkko Oikarinen         jto@tolsun.oulu.fi",
+        "Argv         Armin Gruner Armin.Gruner@Informatik.TU-Muenchen.de",
+        "",
+        "Thanks to the following people for help with preparing 2.8",
+        "",
+        "phone        Matthew Green            phone@coombs.anu.edu.au",
+        "Sodapop      Chuck Kane               ckane@ece.uiuc.edu",
+        "Skygod       Matt Lyle                matt@oc.com",
+        "Vesa         Vesa Ruokonen            ruokonen@lut.fi",
+        "Nap          Nicolas PIOCH pioch@poly.polytechnique.fr",
+        "",
+        "Those who helped in prior versions and continue to be helpful:",
+        "",
+        "Stellan Klebom      Dan Goodwin         Mike Bolotski",
+        "Ian Frechette       Markku Jarvinen     Kimmo Suominen",
+        "Jeff Trim           Vijay Subramaniam   Karl Kleinpaste",
+        "Bill Wisner         Tom Davis           Hugo Calendar",
+        "Tom Hopkins         Stephen van den Berg",
+        "Bo Adler            Michael Sandrof     Jon Solomon",
+        "Jan Peterson        Helen Rose          Paul Graham",
+        "",
+        "Thanks also goes to those persons not mentioned here who have added",
+        "their advice, opinions, and code to IRC.",
+        "Thanks also to those who provide the kind sys admins who let me and",
+        "others continue to develop IRC.",
+        "",
+
+        0
+    };
+!SUB!THIS!
diff --git a/src/whowas.c b/src/whowas.c
new file mode 100644 (file)
index 0000000..cc8e450
--- /dev/null
@@ -0,0 +1,266 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, ircd/whowas.c
+ *   Copyright (C) 1990 Markku Savela
+ *
+ *   This program is free software; you can 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.
+ */
+
+/*
+ * --- 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.
+ */
+
+#ifndef lint
+static  char sccsid[] = "@(#)whowas.c  2.16 08 Nov 1993 (C) 1988 Markku Savela";
+#endif
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "whowas.h"
+#include "h.h"
+
+ID_CVS("$Id$");
+
+static aName   was[NICKNAMEHISTORYLENGTH];
+static int     ww_index = 0;
+
+void   add_history(cptr)
+Reg1   aClient *cptr;
+{
+       aName   ntmp;
+       Reg2    aName   *np = &ntmp, *np2;
+       Link    *lp;
+
+       strncpyzt(np->ww_nick, cptr->name, NICKLEN+1);
+       strncpyzt(np->ww_info, cptr->info, REALLEN+1);
+       np->ww_user = cptr->user;
+       np->ww_logout = TStime();
+       np->ww_online = (cptr->from != NULL) ? cptr : NULL;
+       np->ww_user->refcnt++;
+
+       np2 = &was[ww_index];
+       if (np2->ww_user)
+               free_user(np2->ww_user, np2->ww_online);
+       /*
+        * New whowas handling, we keep a list of what whowas entries
+        * are "used" by a client, in its cptr structure.  This means
+        * that when we overwrite a whowas entry, we have to remove the
+        * relative pointer in the client. -Cabal95
+        */
+       if (np2->ww_online) {
+               Link    *last = NULL;
+
+               for (lp = np2->ww_online->history; lp;
+                    last = lp, lp = lp->next)
+                       if (lp->value.whowas == np2)
+                               break;
+
+               if (lp) {       /* Sanity check, never trust anything */
+                       if (last)
+                               last->next = lp->next;
+                       else
+                               np2->ww_online->history = lp->next;
+
+                       free_link(lp);
+               }
+       }
+
+       bcopy((char *)&ntmp, (char *)np2, sizeof(aName));
+
+       /*
+        * Add this whowas entry into the clients history list
+        */
+       lp = make_link();
+       lp->value.whowas = np2;
+       lp->next = cptr->history;
+       cptr->history = lp;
+
+       ww_index++;
+       if (ww_index >= NICKNAMEHISTORYLENGTH)
+               ww_index = 0;
+       return;
+}
+
+/*
+** get_history
+**      Return the current client that was using the given
+**      nickname within the timelimit. Returns NULL, if no
+**      one found...
+*/
+aClient *get_history(nick, timelimit)
+char    *nick;
+time_t  timelimit;
+{
+        Reg1    aName   *wp, *wp2;
+        Reg2    int     i = 0;
+
+       if (ww_index == 0)
+         wp = wp2 = &was[NICKNAMEHISTORYLENGTH - 1];
+         else
+         wp = wp2 = &was[ww_index - 1];
+        timelimit = TStime()-timelimit;
+
+       do {
+               if (!mycmp(nick, wp->ww_nick) && wp->ww_logout >= timelimit)
+                       break;
+               if (wp == was)
+               {
+                 i = 1;
+                 wp = &was[NICKNAMEHISTORYLENGTH - 1];
+               }
+               else
+                 wp--;
+       } while (wp != wp2);
+
+       if (wp != wp2 || !i)
+               return (wp->ww_online);
+       return (NULL);
+}
+
+void   off_history(cptr)
+Reg3   aClient *cptr;
+{
+       Reg1    Link    *lp;
+       Reg2    Link    *next;
+
+
+       for (lp = cptr->history; lp; lp = next) {
+               next = lp->next;
+               lp->value.whowas->ww_online = NULL;
+               free_link(lp);
+       }
+
+       cptr->history = NULL;
+
+       return;
+}
+
+void   initwhowas()
+{
+       Reg1    int     i;
+
+       for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
+               bzero((char *)&was[i], sizeof(aName));
+       return;
+}
+
+
+/*
+** m_whowas
+**     parv[0] = sender prefix
+**     parv[1] = nickname queried
+*/
+int    m_whowas(cptr, sptr, parc, parv)
+aClient        *cptr, *sptr;
+int    parc;
+char   *parv[];
+{
+       Reg1    aName   *wp, *wp2 = NULL;
+       Reg2    int     j = 0;
+       Reg3    anUser  *up = NULL;
+       int     max = -1;
+       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(cptr,sptr,":%s WHOWAS %s %s :%s", 3,parc,parv))
+                       return 0;
+
+       for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL)
+           {
+               wp = wp2 = &was[ww_index - 1];
+
+               do {
+                       if (wp < was)
+                               wp = &was[NICKNAMEHISTORYLENGTH - 1];
+                       if (mycmp(nick, wp->ww_nick) == 0)
+                           {
+                               up = wp->ww_user;
+                               sendto_one(sptr, rpl_str(RPL_WHOWASUSER),
+                                          me.name, parv[0], wp->ww_nick,
+                                          up->username,
+                               (IsOper(sptr) ? 
+                                up->realhost     :
+                                 (up->virthost[0] != '\0') ?
+                                   up->virthost : up->realhost), 
+                                           wp->ww_info);
+                               sendto_one(sptr, rpl_str(RPL_WHOISSERVER),
+                                          me.name, parv[0], wp->ww_nick,
+                                          up->server, myctime(wp->ww_logout));
+                               if (up->away)
+                                       sendto_one(sptr, rpl_str(RPL_AWAY),
+                                                  me.name, parv[0],
+                                                  wp->ww_nick, up->away);
+                               j++;
+                           }
+                       if (max > 0 && j >= max)
+                               break;
+                       wp--;
+               } while (wp != wp2);
+
+               if (up == NULL)
+                       sendto_one(sptr, err_str(ERR_WASNOSUCHNICK),
+                                  me.name, parv[0], nick);
+               up=NULL;
+
+               if (p)
+                       p[-1] = ',';
+           }
+       sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]);
+       return 0;
+    }
+
+
+void   count_whowas_memory(wwu, wwa, wwam)
+int    *wwu, *wwa;
+u_long *wwam;
+{
+       Reg1    anUser  *tmp;
+       Reg2    int     i, j;
+       int     u = 0, a = 0;
+       u_long  am = 0;
+
+       for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
+               if ((tmp = was[i].ww_user))
+                       if (!was[i].ww_online)
+                           {
+                               for (j = 0; j < i; j++)
+                                       if (was[j].ww_user == tmp)
+                                               break;
+                               if (j < i)
+                                       continue;
+                               u++;
+                               if (tmp->away)
+                                   {
+                                       a++;
+                                       am += (strlen(tmp->away)+1);
+                                   }
+                           }
+       *wwu = u;
+       *wwa = a;
+       *wwam = am;
+
+       return;
+}
diff --git a/src/win32.c b/src/win32.c
new file mode 100644 (file)
index 0000000..2ba7605
--- /dev/null
@@ -0,0 +1,905 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, win32.c
+ *   Copyright (C) 1996 Daniel Hazelbaker
+ *
+ *   This program is free software; you can 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)win32.c    2.01 10/21/96 (C) 1996 Daniel Hazelbaker";
+#endif
+
+
+#define APPNAME "wIRCD"
+#define wTITLEBAR "UnrealIRCd"
+
+// Windows Header Files:
+#include "common.h"
+#include <windows.h>
+#include <commctrl.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <io.h>
+#include <fcntl.h>
+#include "struct.h"
+#include "sys.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "h.h"
+#include "version.h"
+#include "resource.h"
+#include "CioFunc.h"
+
+ID_CVS("$Id$");
+
+
+BOOL              InitApplication(HINSTANCE);
+BOOL              InitInstance(HINSTANCE, int);
+LRESULT CALLBACK  FrameWndProc(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK  About(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK  Dlg_IRCDCONF(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK  Dlg_IRCDMOTD(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK  Dlg_IRCDRULES(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
+
+BOOL              DisplayString(HWND hWnd, char *InBuf, ...);
+void              LoadSetup(void);
+void              SaveSetup(void);
+int              SetDebugLevel(HWND hWnd, int NewLevel);
+
+LRESULT CALLBACK  Credits(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK  Dreamforge(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK  IRCDLicense(HWND, UINT, WPARAM, LPARAM);
+
+
+extern  void      SocketLoop(void *dummy), s_rehash(), do_dns_async(HANDLE id);
+extern  int       localdie(void), InitwIRCD(int argc, char *argv[]);
+
+
+HINSTANCE   hInst; // current instance
+char        szAppName[] = APPNAME; // The name of this application
+char        szTitle[]   = wTITLEBAR; // The title bar text
+HWND        hwIRCDWnd=NULL, hCio=NULL;
+HANDLE      hMainThread = 0;
+
+#ifndef IRCDTOTALVERSION
+#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9
+#endif
+
+/*
+ *  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
+ *
+ *  PURPOSE: Entry point for the application.
+ *
+ *  COMMENTS:
+ *
+ *     This function initializes the application and processes the
+ *     message loop.
+ */
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+       MSG msg;
+       HANDLE hAccelTable;
+       int argc=1;
+       char *s, *argv[20], String[128];
+
+       if (!hPrevInstance)
+               if (!InitApplication(hInstance))
+                       return (FALSE);
+
+       if (!InitInstance(hInstance, nCmdShow))
+               return (FALSE);
+
+       argv[0] = "WIRCD.EXE";
+       if ( *(s = lpCmdLine) )
+           {
+               argv[argc++] = s;
+               while ( (s = strchr(s, ' ')) != NULL )
+                   {
+                       while ( *s == ' ' ) *s++ = 0;
+                       argv[argc++] = s;
+                   }
+           }
+       argv[argc] = NULL;
+       if ( InitwIRCD(argc, argv) != 1 )
+               return FALSE;
+
+       wsprintf(String, "UnrealIRCd/32 - %s", me.name);
+       SetWindowText(hwIRCDWnd, String);
+
+       SetDebugLevel(hwIRCDWnd, debuglevel);
+
+       hMainThread = (HANDLE)_beginthread(SocketLoop, 0, NULL);
+       hAccelTable = LoadAccelerators (hInstance, szAppName);
+
+       LoadSetup();
+       atexit(SaveSetup);
+
+       /* Say we are ready to recieve connections */
+       wsprintf(String, "%c%c%c%c[info] -=-=[ UnrealIRCd/32 v%s Ready ] - %s\r", 0,0,0,0, VERSIONONLY);
+       DisplayString(hCio, String);
+       /* Main message loop */
+       while (GetMessage(&msg, NULL, 0, 0))
+           {
+               if ( !TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
+                   {
+                       TranslateMessage(&msg);
+                       DispatchMessage(&msg);
+                   }
+           }
+
+       return (msg.wParam);
+       lpCmdLine; /* This will prevent 'unused formal parameter' warnings */
+}
+
+
+/*
+ *  FUNCTION: InitApplication(HANDLE)
+ *
+ *  PURPOSE: Initializes window data and registers window class 
+ *
+ *  COMMENTS:
+ *
+ *       In this function, we initialize a window class by filling out a data
+ *       structure of type WNDCLASS and calling either RegisterClass or 
+ *       the internal MyRegisterClass.
+ */
+BOOL InitApplication(HINSTANCE hInstance)
+{
+    WNDCLASS  wc;
+
+    // Fill in window class structure.
+    wc.style         = CS_HREDRAW | CS_VREDRAW;
+    wc.lpfnWndProc   = (WNDPROC)FrameWndProc;
+    wc.cbClsExtra    = 0;
+    wc.cbWndExtra    = 0;
+    wc.hInstance     = hInstance;
+    wc.hIcon         = LoadIcon (hInstance, APPNAME);
+    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
+       wc.lpszMenuName  = szAppName;
+    wc.lpszClassName = szAppName;
+
+    if ( !RegisterClass(&wc) ) return 0;
+
+    return 1;
+}
+
+
+/*
+ *   FUNCTION: InitInstance(HANDLE, int)
+ *
+ *   PURPOSE: Saves instance handle and creates main window 
+ *
+ *   COMMENTS:
+ *
+ *        In this function, we save the instance handle in a global variable and
+ *        create and display the main program window.
+ */
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+       HWND hWnd;
+    WSADATA             WSAData;
+
+       
+    if ( WSAStartup(MAKEWORD(1, 1), &WSAData) != 0 )
+    {
+        MessageBox(NULL, "UnrealIRCD/32 Init Error", "Unable to initialize WinSock DLL", MB_OK);
+        return FALSE;
+    }
+
+       hInst = hInstance; /* Store instance handle in our global variable */
+    
+    if ( !Cio_Init(hInst) )
+    {
+        MessageBox(NULL, "UnrealIRCD/32 Init Error", "Couldn't Init CIO Library", MB_OK);
+        return FALSE;
+    }
+
+       hWnd = CreateWindow(szAppName, szTitle, WS_OVERLAPPEDWINDOW,
+               CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+               NULL, NULL, hInstance, NULL);
+
+       if ( !hWnd )
+               return (FALSE);
+
+    ShowWindow(hWnd, nCmdShow);
+       UpdateWindow(hwIRCDWnd = hWnd);
+
+       return (TRUE);
+}
+
+
+/*
+ *  FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for the main window.
+ *
+ */
+LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    int    wmId, wmEvent;
+       char    *xx = NULL;
+       
+       switch (message)
+           {
+               case WM_CREATE:
+                       hCio  = Cio_Create(hInst, hWnd, WS_VISIBLE, 0, 0, 300, 200);
+                       xx = MyMalloc(1024);
+                       sprintf(xx, "%c%c%c%c[info] -=-=[ UnrealIRCd/32 v%s Loading ]-=-=\r", 0, 0, 0, 0,
+                               VERSIONONLY);
+                       DisplayString(hCio, xx);
+#ifdef WIN32_SPECIFY
+                       sprintf(xx, "%c%c%c%c[info] - Ported by %s", 0,0,0,0, WIN32_PORTER);
+                       DisplayString(hCio, xx);        
+                       sprintf(xx, "%c%c%c%c[info] - %s", 0,0,0,0, WIN32_URL);
+                       DisplayString(hCio, xx);
+#endif
+                       MyFree(xx);
+                       return 0;
+               case WM_COMMAND:
+                       wmId    = LOWORD(wParam);
+                       wmEvent = HIWORD(wParam);
+
+                       switch (wmId)
+                           {
+                               case IDM_ABOUT:
+                                       DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)About);
+                                       break;
+                               case IDM_CREDITS:
+                                       DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)Credits);
+                                       break;
+                               case IDM_DF:
+                                       DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)Dreamforge);
+                                       break;
+                               case IDM_LICENSE:
+                                       DialogBox(hInst, "AboutBox", hWnd, (DLGPROC)IRCDLicense);
+                                       break;
+
+                               case IDM_IRCDCONF:
+                                       DialogBox(hInst, "DLG_IRCDCONF", hWnd, (DLGPROC)Dlg_IRCDCONF);
+                                       break;
+                               case IDM_IRCDMOTD:
+                                       DialogBox(hInst, "DLG_IRCDMOTD", hWnd, (DLGPROC)Dlg_IRCDMOTD);
+                                       break;
+                               case IDM_IRCDRULES:
+                                       DialogBox(hInst, "DLG_IRCDRULES", hWnd, (DLGPROC)Dlg_IRCDRULES);
+                                       break;
+                               case IDM_REHASH:
+                                       s_rehash();
+                                       break;
+
+                               case IDM_EXIT:
+                                       if ( MessageBox(hWnd, "Are you sure?",
+                                               "Terminate UnrealIRCD/32",
+                                               MB_ICONQUESTION | MB_YESNO) == IDNO )
+                                               break;
+                                       DestroyWindow(hWnd);
+                                       break;
+
+                               case IDM_DBGOFF:
+                               case IDM_DBGFATAL:
+                               case IDM_DBGERROR:
+                               case IDM_DBGNOTICE:
+                               case IDM_DBGDNS:
+                               case IDM_DBGINFO:
+                               case IDM_DBGNUM:
+                               case IDM_DBGSEND:
+                               case IDM_DBGDEBUG:
+                               case IDM_DBGMALLOC:
+                               case IDM_DBGLIST:
+                                       SetDebugLevel(hWnd, wmId-IDM_DBGFATAL);
+                                       break;
+
+                               default:
+                                       return (DefWindowProc(hWnd, message, wParam, lParam));
+                           }
+                       break;
+
+               case WM_CLOSE:
+                       if ( MessageBox(hWnd, "Are you sure?", "Terminate UnrealIRCd/32",
+                                       MB_ICONQUESTION | MB_YESNO) == IDNO )
+                               break;
+                       return (DefWindowProc(hWnd, message, wParam, lParam));
+
+               case WM_DESTROY:
+                       localdie();   /* Never returns */
+                       PostQuitMessage(0);
+                       break;
+
+               case WM_SIZE:
+                       SetWindowPos(hCio, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam),
+                               SWP_NOZORDER);
+                       /* Fallthrough to get the default handling too. */
+
+               default:
+                       return (DefWindowProc(hWnd, message, wParam, lParam));
+           }
+       return (0);
+}
+
+
+/*
+ *  FUNCTION: About(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "About" dialog box
+ *             This version allows greater flexibility over the contents of the 'About' box,
+ *             by pulling out values from the 'Version' resource.
+ *
+ *  MESSAGES:
+ *
+ *     WM_INITDIALOG - initialize dialog box
+ *     WM_COMMAND    - Input received
+ *
+ */
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+           {
+               case WM_INITDIALOG:
+#define Ccat strcat(String, String2)
+                   {
+                       char    String[16384], String2[16384], **s = infotext;
+                       sprintf(String, "%s\n%s", version, creation);
+                       SetDlgItemText(hDlg, IDC_VERSION, String);
+                       String[0] = 0; String2[0] = 0;
+                       sprintf(String2, "-=-=-=-=-=-==-==- %s -=-=-==-==-=-=-=-=-=-\r\n", ircnetwork); Ccat;
+                       sprintf(String2, "|Web Page:      | http://www.%s\r\n", netdomain); Ccat;
+                       sprintf(String2, "|FTP Archive:   | ftp://ftp.%s\r\n", netdomain); Ccat;
+                       sprintf(String2, "|Help channel:  | %s\r\n", helpchan); Ccat;
+                       sprintf(String2, "|=-=-=-=-=-==-==|-=-=-=-=-=-=-==-==-=-=-=-=-=-=-=\r\n"); Ccat;
+                       sprintf(String2, "|IRCd version:  | %s\r\n", IRCDTOTALVERSION); Ccat;                   
+                       sprintf(String2, "| Developers:   | Stskeeps <stskeeps@tspre.org>\r\n"); Ccat;
+                       sprintf(String2, "|               | codemastr <codemastr@tspre.org>\r\n"); Ccat; 
+#if defined(_WIN32) && defined(WIN32_SPECIFY)
+                       sprintf(String2, "| Win32 Porter: | %s\r\n", WIN32_PORTER); Ccat;
+                       sprintf(String2, "|     >>URL:    | %s\r\n", WIN32_URL); Ccat;
+#endif
+                       sprintf(String2, "|Credits:       | Type /Credits\r\n"); Ccat;
+                       sprintf(String2, "|DALnet Credits:| Type /DALinfo\r\n"); Ccat;
+                       sprintf(String2, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n"); Ccat;
+                       sprintf(String2, "| Unreal IRCd can be downloaded at http://unreal.tspre.org\r\n"); Ccat;       
+                       sprintf(String2, "| This notice may not be removed from the IRCd package\r\n"); Ccat;
+                       sprintf(String2, "| It will be a violation of copyright. This program must always stay free of charge\r\n"); Ccat;
+                       sprintf(String2, "| being sold commercially or privately\r\n"); Ccat;
+                       sprintf(String2, "| Only charge may be for the transport medium like on CD-ROM, floppy\r\n"); Ccat;
+                       sprintf(String2, "| or other kinds (-Stskeeps'1999)\r\n"); Ccat;
+                       sprintf(String2, "--------------------------------------------\r\n"); Ccat;
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);
+#undef Ccat
+                       ShowWindow (hDlg, SW_SHOW);
+                       return (TRUE);
+                   }
+
+               case WM_COMMAND:
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+                           {
+                               EndDialog(hDlg, TRUE);
+                               return (TRUE);
+                           }
+                       break;
+           }
+    return FALSE;
+}
+
+/*
+ *  FUNCTION: Credits(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "Credits" dialog box
+ *             This version allows greater flexibility over the contents of the 'Credits' box,
+ *             by pulling out values from the 'Version' resource.
+ *
+ *  MESSAGES:
+ *
+ *     WM_INITDIALOG - initialize dialog box
+ *     WM_COMMAND    - Input received
+ *
+ */
+LRESULT CALLBACK Credits(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+           {
+               case WM_INITDIALOG:
+                   {
+                       char    String[16384], **s = unrealcredits;
+
+                       sprintf(String, "%s\n%s", version, creation);
+                       SetDlgItemText(hDlg, IDC_VERSION, String);
+                       String[0] = 0;
+                       while ( *s )
+                           {
+                               strcat(String, *s++);
+                               if ( *s )
+                                       strcat(String, "\r\n");
+                           }
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);
+
+
+                       ShowWindow (hDlg, SW_SHOW);
+                       return (TRUE);
+                   }
+
+               case WM_COMMAND:
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+                           {
+                               EndDialog(hDlg, TRUE);
+                               return (TRUE);
+                           }
+                       break;
+           }
+    return FALSE;
+}
+
+/*
+ *  FUNCTION: Dreamforge(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "Dreamforge" dialog box
+ *             This version allows greater flexibility over the contents of the 'Dreamforge' box,
+ *             by pulling out values from the 'Version' resource.
+ *
+ *  MESSAGES:
+ *
+ *     WM_INITDIALOG - initialize dialog box
+ *     WM_COMMAND    - Input received
+ *
+ */
+LRESULT CALLBACK Dreamforge(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+           {
+               case WM_INITDIALOG:
+                   {
+                       char    String[16384], **s = dalinfotext;
+
+                       sprintf(String, "%s\n%s", version, creation);
+                       SetDlgItemText(hDlg, IDC_VERSION, String);
+                       String[0] = 0;
+                       while ( *s )
+                           {
+                               strcat(String, *s++);
+                               if ( *s )
+                                       strcat(String, "\r\n");
+                           }
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);
+
+
+                       ShowWindow (hDlg, SW_SHOW);
+                       return (TRUE);
+                   }
+
+               case WM_COMMAND:
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+                           {
+                               EndDialog(hDlg, TRUE);
+                               return (TRUE);
+                           }
+                       break;
+           }
+    return FALSE;
+}
+
+/*
+ *  FUNCTION: IRCDLicense(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "IRCDLicense" dialog box
+ *             This version allows greater flexibility over the contents of the 'IRCDLicense' box,
+ *             by pulling out values from the 'Version' resource.
+ *
+ *  MESSAGES:
+ *
+ *     WM_INITDIALOG - initialize dialog box
+ *     WM_COMMAND    - Input received
+ *
+ */
+LRESULT CALLBACK IRCDLicense(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+           {
+               case WM_INITDIALOG:
+                   {
+                       char    String[16384], **s = gnulicense;
+
+                       sprintf(String, "%s\n%s", version, creation);
+                       SetDlgItemText(hDlg, IDC_VERSION, String);
+                       String[0] = 0;
+                       while ( *s )
+                           {
+                               strcat(String, *s++);
+                               if ( *s )
+                                       strcat(String, "\r\n");
+                           }
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);
+
+
+                       ShowWindow (hDlg, SW_SHOW);
+                       return (TRUE);
+                   }
+
+               case WM_COMMAND:
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
+                           {
+                               EndDialog(hDlg, TRUE);
+                               return (TRUE);
+                           }
+                       break;
+           }
+    return FALSE;
+}
+
+
+/*
+ *  FUNCTION: Dlg_IrcdConf(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box
+ *
+ */
+LRESULT CALLBACK Dlg_IRCDCONF(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+    {
+        case WM_INITDIALOG:
+            {
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */
+                int   fd, Len;
+
+                if ( !Buffer )
+                {
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",
+                        "UnrealIRCd/32 Setup", MB_OK);
+                    EndDialog(hDlg, FALSE);
+                                       return FALSE;
+                }
+                /* Open the ircd.conf file */
+                fd = open(CONFIGFILE, _O_RDONLY | _O_BINARY);
+                if ( fd == -1 )
+                   {
+                       MessageBox(hDlg, "Error: Could not open configuration file",
+                                  "UnrealIRCd/32 Setup", MB_OK);
+                       MyFree(Buffer);
+                       EndDialog(hDlg, FALSE);
+                       return FALSE;
+                   }
+
+                Buffer[0] = 0;          /* Incase read() fails */
+                Len = read(fd, Buffer, 65535);
+                Buffer[Len] = 0;
+                /* Set the text for the edit control to what was in the file */
+                SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_SETTEXT, 0,
+                    (LPARAM)(LPCTSTR)Buffer);
+
+                close(fd);
+                MyFree(Buffer);
+            }
+                       return (TRUE);
+
+               case WM_COMMAND:
+                       if ( LOWORD(wParam) == IDOK )
+            {
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */
+                DWORD Len;
+                int   fd;
+
+                if ( !Buffer )
+                {
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",
+                        "UnrealIRCD/32 Setup", MB_OK);
+                    return TRUE;
+                }
+                /* Open the ircd.conf file */
+                fd = open(CONFIGFILE, _O_TRUNC|_O_CREAT|_O_RDWR|_O_BINARY,
+                       S_IREAD|S_IWRITE);
+                if ( fd == -1 )
+                {
+                    MessageBox(hDlg, "Error: Could not open configuration file",
+                        "UnrealIRCD/32 Setup", MB_OK);
+                    MyFree(Buffer);
+                    return TRUE;
+                }
+
+                /* Get the text from the edit control and save it to disk. */
+                Len = SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_GETTEXT, 65535,
+                    (LPARAM)(LPCTSTR)Buffer);
+                write(fd, Buffer, Len);
+
+                close(fd);
+                MyFree(Buffer);
+
+                               EndDialog(hDlg, TRUE);
+                               return TRUE;
+                       }
+            if ( LOWORD(wParam) == IDCANCEL )
+            {
+                EndDialog(hDlg, FALSE);
+                return TRUE;
+            }
+                       break;
+       }
+
+    return FALSE;
+}
+
+/*
+ *  FUNCTION: Dlg_Dlg_IRCdMotd(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box
+ *
+ */
+LRESULT CALLBACK Dlg_IRCDMOTD(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+    {
+        case WM_INITDIALOG:
+            {
+                char  *Buffer = MyMalloc(65535*2);   /* Should be big enough */
+                int   fd, Len;
+
+                if ( !Buffer )
+                {
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",
+                        "UnrealIRCd/32 Setup", MB_OK);
+                    EndDialog(hDlg, FALSE);
+                                       return FALSE;
+                }
+                /* Open the ircd.motd file */
+                fd = open(MPATH, _O_RDONLY | _O_BINARY);
+                if ( fd == -1 )
+                   {
+                       MessageBox(hDlg, "Error: Could not open MOTD file",
+                                  "UnrealIRCd/32 Setup", MB_OK);
+                       MyFree(Buffer);
+                       EndDialog(hDlg, FALSE);
+                       return FALSE;
+                   }
+
+                Buffer[0] = 0;          /* Incase read() fails */
+                Len = read(fd, Buffer, 65535);
+                Buffer[Len] = 0;
+                /* Set the text for the edit control to what was in the file */
+                SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_SETTEXT, 0,
+                    (LPARAM)(LPCTSTR)Buffer);
+
+                close(fd);
+                MyFree(Buffer);
+            }
+                       return (TRUE);
+
+               case WM_COMMAND:
+                       if ( LOWORD(wParam) == IDOK )
+            {
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */
+                DWORD Len;
+                int   fd;
+
+                if ( !Buffer )
+                {
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",
+                        "UnrealIRCD/32 Setup", MB_OK);
+                    return TRUE;
+                }
+                /* Open the ircd.motd file */
+                fd = open(MPATH, _O_TRUNC|_O_CREAT|_O_RDWR|_O_BINARY,
+                       S_IREAD|S_IWRITE);
+                if ( fd == -1 )
+                {
+                    MessageBox(hDlg, "Error: Could not open motd file",
+                        "UnrealIRCD/32 Setup", MB_OK);
+                    MyFree(Buffer);
+                    return TRUE;
+                }
+
+                /* Get the text from the edit control and save it to disk. */
+                Len = SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_GETTEXT, 65535,
+                    (LPARAM)(LPCTSTR)Buffer);
+                write(fd, Buffer, Len);
+
+                close(fd);
+                MyFree(Buffer);
+
+                               EndDialog(hDlg, TRUE);
+                               return TRUE;
+                       }
+            if ( LOWORD(wParam) == IDCANCEL )
+            {
+                EndDialog(hDlg, FALSE);
+                return TRUE;
+            }
+                       break;
+       }
+
+    return FALSE;
+}
+
+/*
+ *  FUNCTION: Dlg_IRCdRules(HWND, unsigned, WORD, LONG)
+ *
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box
+ *
+ */
+LRESULT CALLBACK Dlg_IRCDRULES(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+       switch (message)
+    {
+        case WM_INITDIALOG:
+            {
+                char  *Buffer = MyMalloc(65535*2);   /* Should be big enough */
+                int   fd, Len;
+
+                if ( !Buffer )
+                {
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",
+                        "UnrealIRCd/32 Setup", MB_OK);
+                    EndDialog(hDlg, FALSE);
+                                       return FALSE;
+                }
+                /* Open the ircd.rules file */
+                fd = open(RPATH, _O_RDONLY | _O_BINARY);
+                if ( fd == -1 )
+                   {
+                       MessageBox(hDlg, "Error: Could not open rules file",
+                                  "UnrealIRCd/32 Setup", MB_OK);
+                       MyFree(Buffer);
+                       EndDialog(hDlg, FALSE);
+                       return FALSE;
+                   }
+
+                Buffer[0] = 0;          /* Incase read() fails */
+                Len = read(fd, Buffer, 65535);
+                Buffer[Len] = 0;
+                /* Set the text for the edit control to what was in the file */
+                SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_SETTEXT, 0,
+                    (LPARAM)(LPCTSTR)Buffer);
+
+                close(fd);
+                MyFree(Buffer);
+            }
+                       return (TRUE);
+
+               case WM_COMMAND:
+                       if ( LOWORD(wParam) == IDOK )
+            {
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */
+                DWORD Len;
+                int   fd;
+
+                if ( !Buffer )
+                {
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",
+                        "UnrealIRCD/32 Setup", MB_OK);
+                    return TRUE;
+                }
+                /* Open the ircd.rules file */
+                fd = open(RPATH, _O_TRUNC|_O_CREAT|_O_RDWR|_O_BINARY,
+                       S_IREAD|S_IWRITE);
+                if ( fd == -1 )
+                {
+                    MessageBox(hDlg, "Error: Could not open rules file",
+                        "UnrealIRCD/32 Setup", MB_OK);
+                    MyFree(Buffer);
+                    return TRUE;
+                }
+
+                /* Get the text from the edit control and save it to disk. */
+                Len = SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_GETTEXT, 65535,
+                    (LPARAM)(LPCTSTR)Buffer);
+                write(fd, Buffer, Len);
+
+                close(fd);
+                MyFree(Buffer);
+
+                               EndDialog(hDlg, TRUE);
+                               return TRUE;
+                       }
+            if ( LOWORD(wParam) == IDCANCEL )
+            {
+                EndDialog(hDlg, FALSE);
+                return TRUE;
+            }
+                       break;
+       }
+
+    return FALSE;
+}
+
+
+int  DisplayString(HWND hWnd, char *InBuf, ...)
+{
+    CioWndInfo  *CWI;
+    va_list  argptr;
+    char    *Buffer=NULL, *Ptr=NULL;
+    DWORD    Len=0, TLen=0, Off=0, i=0;
+    BYTE     Red=0, Green=0, Blue=0;
+    BOOL     Bold = FALSE;
+
+    if ( (Buffer = LocalAlloc(LPTR, 16384)) == NULL ) return FALSE;
+
+    va_start(argptr, InBuf);
+    Len = vsprintf(Buffer, InBuf, argptr);
+    va_end(argptr);
+    if ( Len == 0 )
+    {
+        LocalFree(Buffer);
+        return FALSE;
+    }
+
+    CWI = (CioWndInfo *)GetWindowLong(hWnd, GWL_USER);
+    for ( i = 0; i < Len; i++ )
+    {
+        if ( Buffer[i] == 0 )
+        {
+            i+=3;
+            continue;
+        }
+        if ( Buffer[i] == 0x02 )
+        {
+            if ( !Bold )
+            {
+                Buffer[i] = 0;
+                Cio_Puts(hWnd, Buffer+Off, i-Off);
+                Red = CWI->FR;
+                Green = CWI->FG;
+                Blue = CWI->FB;
+                       
+                Off=i+1;
+                Cio_PrintF(hWnd, "%c%c%c%c", 0, 255, 32, 32);
+                Bold = 1;
+                continue;
+            }
+            if ( Bold )
+            {
+                Buffer[i] = 0;
+                Cio_Puts(hWnd, Buffer+Off, i-Off);
+                Off=i+1;
+                Cio_PrintF(hWnd, "%c%c%c%c", 0, Red, Green, Blue);
+                Bold = 0;
+                continue;
+            }
+        }
+    }
+    Cio_Puts(hWnd, Buffer+Off, Len-Off);
+
+    LocalFree(Buffer);
+    return TRUE;
+}
+
+
+void   LoadSetup(void)
+{
+}
+
+void   SaveSetup(void)
+{
+}
+
+
+int    SetDebugLevel(HWND hWnd, int NewLevel)
+{
+       HMENU   hMenu = GetMenu(hWnd);
+
+       if ( !hMenu || !(hMenu = GetSubMenu(hMenu, 1)) ||
+            !(hMenu = GetSubMenu(hMenu, 4)) )
+               return -1;
+
+       CheckMenuItem(hMenu, IDM_DBGFATAL+debuglevel,
+               MF_BYCOMMAND | MF_UNCHECKED);
+       debuglevel = NewLevel;
+       CheckMenuItem(hMenu,IDM_DBGFATAL+debuglevel,
+               MF_BYCOMMAND | MF_CHECKED);
+
+       return debuglevel;
+}
+
+
diff --git a/src/win32.rc b/src/win32.rc
new file mode 100644 (file)
index 0000000..1a7a14e
--- /dev/null
@@ -0,0 +1,228 @@
+//Microsoft Developer Studio generated resource script.
+//
+// $Id$
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+#include "resource.h"
+#include "winver.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+WIRCD MENU DISCARDABLE 
+BEGIN
+    POPUP "&File"
+    BEGIN
+        MENUITEM "E&xit",                       IDM_EXIT
+    END
+    POPUP "&System"
+    BEGIN
+        MENUITEM "Ircd.&Conf",                  IDM_IRCDCONF
+       MENUITEM "Ircd.&Motd",                  IDM_IRCDMOTD
+       MENUITEM "Ircd.R&ules",                 IDM_IRCDRULES
+        MENUITEM SEPARATOR
+        MENUITEM "&Rehash",                     IDM_REHASH
+        POPUP "Debug Level"
+        BEGIN
+            MENUITEM "&Off",                        IDM_DBGOFF
+            MENUITEM "&Fatal",                      IDM_DBGFATAL
+            MENUITEM "&Error",                      IDM_DBGERROR
+            MENUITEM "&Notice",                     IDM_DBGNOTICE
+            MENUITEM "&DNS",                        IDM_DBGDNS
+            MENUITEM "&Info",                       IDM_DBGINFO
+            MENUITEM "N&umerics",                   IDM_DBGNUM
+            MENUITEM "&Send",                       IDM_DBGSEND
+            MENUITEM "&Debug",                      IDM_DBGDEBUG
+            MENUITEM "&Malloc",                     IDM_DBGMALLOC
+            MENUITEM "&List",                       IDM_DBGLIST
+        END
+    END
+    POPUP "&Help", HELP
+    BEGIN
+       MENUITEM "&Credits...",                         IDM_CREDITS
+       MENUITEM "&Dreamforge Credits...",              IDM_DF
+       MENUITEM "&License...",                         IDM_LICENSE
+        MENUITEM "&About UnrealIRCD/32...",             IDM_ABOUT
+    END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+ABOUTBOX DIALOGEX 22, 17, 264, 129
+STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "UnrealIRCd Information"
+FONT 8, "System", 0, 0, 0x1
+BEGIN
+    DEFPUSHBUTTON   "OK",IDOK,228,5,32,18,WS_GROUP,WS_EX_DLGMODALFRAME | 
+                    WS_EX_CLIENTEDGE
+    CTEXT           "Version",IDC_VERSION,5,5,120,18,SS_SUNKEN
+    EDITTEXT        IDC_INFOTEXT,0,28,264,100,ES_MULTILINE | ES_READONLY | 
+                    WS_VSCROLL
+END
+
+DLG_IRCDCONF DIALOG DISCARDABLE  0, 0, 294, 159
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "UnrealIRCd Setup"
+FONT 9, "Fixedsys"
+BEGIN
+    DEFPUSHBUTTON   "&Save",IDOK,3,143,50,14
+    PUSHBUTTON      "&Cancel",IDCANCEL,241,143,50,14
+    EDITTEXT        IDC_IRCDCONF,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
+END
+
+DLG_IRCDRULES DIALOG DISCARDABLE  0, 0, 294, 159
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "UnrealIRCd Setup"
+FONT 9, "Fixedsys"
+BEGIN
+    DEFPUSHBUTTON   "&Save",IDOK,3,143,50,14
+    PUSHBUTTON      "&Cancel",IDCANCEL,241,143,50,14
+    EDITTEXT        IDC_IRCDCONF,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
+END
+
+DLG_IRCDMOTD DIALOG DISCARDABLE  0, 0, 294, 159
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "UnrealIRCd Setup"
+FONT 9, "Fixedsys"
+BEGIN
+    DEFPUSHBUTTON   "&Save",IDOK,3,143,50,14
+    PUSHBUTTON      "&Cancel",IDCANCEL,241,143,50,14
+    EDITTEXT        IDC_IRCDCONF,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | 
+                    ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+1 VERSIONINFO
+ FILEVERSION 3,5,0,0
+ PRODUCTVERSION 3,5,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0xbL
+#else
+ FILEFLAGS 0xaL
+#endif
+ FILEOS 0x10001L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    VALUE "StringFileInfo", "\0"
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", "\0"
+    END
+END
+
+#endif    // !_MAC
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""resource.h""\r\n"
+    "#include ""winver.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE 
+BEGIN
+    "ABOUTBOX", DIALOG
+    BEGIN
+        RIGHTMARGIN, 115
+        BOTTOMMARGIN, 78
+    END
+
+    "DLG_IRCDCONF", DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 287
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 152
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/src/win32/Icon1.ico b/src/win32/Icon1.ico
new file mode 100644 (file)
index 0000000..ee4b767
Binary files /dev/null and b/src/win32/Icon1.ico differ
diff --git a/src/win32/Win32GUI.c b/src/win32/Win32GUI.c
new file mode 100644 (file)
index 0000000..af51ce7
--- /dev/null
@@ -0,0 +1,1755 @@
+/************************************************************************\r
+ *   IRC - Internet Relay Chat, Win32GUI.c\r
+ *   Copyright (C) 2000 David Flynn (DrBin)\r
+ *   \r
+ *   This program is free software; you can redistribute it and/or modify\r
+ *   it under the terms of the GNU General Public License as published by\r
+ *   the Free Software Foundation; either version 1, or (at your option)\r
+ *   any later version.\r
+ *\r
+ *   This program is distributed in the hope that it will be useful,\r
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *   GNU General Public License for more details.\r
+ *\r
+ *   You should have received a copy of the GNU General Public License\r
+ *   along with this program; if not, write to the Free Software\r
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
+ */\r
+\r
+\r
+\r
+#define APPNAME "wIRCD"\r
+#define wTITLEBAR "UnrealIRCd"\r
+#define OEMRESOURCE\r
+//#define _WIN32_IE 0x0500\r
+\r
+\r
+/* debug stuff*/\r
+#define WINDEBUGLEVEL_0 0x01\r
+#define WINDEBUGLEVEL_1 0x02\r
+#define WINDEBUGLEVEL_2 0x04\r
+#define WINDEBUGLEVEL_3 0x08\r
+#define WINDEBUGLEVEL_FLUSH 0x10\r
+#define WINDEBUG_FORCE 0x20\r
+#define WINNOTIFY_0 0x0100\r
+#define WINNOTIFY_1 0x0200\r
+#define WINNOTIFY_2 0x0400\r
+#define WINNOTIFY_3 0x0800\r
+/*end*/\r
+//#define ircnetwork "a network"\r
+//#define netdomain "netdomain"\r
+//#define helpchan "helpchan"\r
+//#define IRCDTOTALVERSION "3"\r
+#ifndef IRCDTOTALVERSION\r
+#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9\r
+#endif\r
+\r
+#include <windows.h>\r
+#include "resource.h"\r
+#include "version.h"\r
+#include "setup.h"\r
+#include <commctrl.h>\r
+\r
+/* These came from ircd.c*/\r
+#include "struct.h"\r
+#include "common.h"\r
+#include "sys.h"\r
+#include "numeric.h"\r
+#include "userload.h"\r
+//#include "services.h"\r
+#include <sys/stat.h>\r
+#include <signal.h>\r
+#include <fcntl.h>\r
+#include <sys/types.h>\r
+#include <io.h>\r
+#include <direct.h>\r
+#include <errno.h>\r
+#include "h.h"\r
+#include "Win32New.h"\r
+#include <richedit.h>\r
+\r
+/* end */\r
+int    SetDebugLevel(HWND hWnd, int NewLevel);\r
+void SetupPopups(HWND hDlg);\r
+HWND CreateATreeView(HWND hwndParent/*, LPSTR lpszFileName*/,RECT rcClient); \r
+HTREEITEM AddItemToTree(HWND hWnd, LPSTR lpszItem, int nLevel);\r
+void win_map(cptr, server, mask, prompt_length, length,hwTreeView);\r
+LRESULT CALLBACK  WndProc(HWND, UINT, WPARAM, LPARAM);\r
+LRESULT CALLBACK  MainDLG(HWND, UINT, WPARAM, LPARAM);\r
+LRESULT CALLBACK wStatusDLG(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK Dlg_IRCDRULES(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK Dlg_IRCDMOTD(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK Dlg_IRCDCONF(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK Credits(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK Dreamforge(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+LRESULT CALLBACK IRCDLicense(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);\r
+extern  void      SocketLoop(void *dummy), s_rehash(), do_dns_async(HANDLE id);\r
+void   windebug(level, form, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);\r
+extern struct /*current_load_struct */current_load_data;\r
+LRESULT CALLBACK GraphCtlProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);\r
+void NiceQuit(void);\r
+extern int max_client_count;\r
+HINSTANCE hInst;\r
+HWND hStatsWnd,hgraphwnd;\r
+int windebuglevel = 0 ;\r
+//| WINDEBUGLEVEL_0 | WINDEBUGLEVEL_1 | WINDEBUGLEVEL_2 | WINDEBUGLEVEL_3 | WINDEBUGLEVEL_FLUSH ;\r
+int usernumhistory[530], usernumpointer;\r
+char String[2048];\r
+#include "version.h"\r
+FILE *debugfile;\r
+aConfiguration iConf;\r
+char *version, *creation;\r
+char shortversion[] = BASE_VERSION PATCH1;\r
+char        szAppName[] = APPNAME; // The name of this application\r
+char        szTitle[]   = wTITLEBAR; // The title bar text\r
+HWND        hwIRCDWnd=NULL/* hwnd=NULL*/;\r
+INFRICHLINE AllLines;\r
+       NOTIFYICONDATA SysTray;\r
+HANDLE      hMainThread = 0;\r
+HMENU  ConfPopup, AboutPopup, DebugPopup;\r
+int APIENTRY WinMain(HINSTANCE hInstance,\r
+                     HINSTANCE hPrevInstance,\r
+                     LPSTR     lpCmdLine,\r
+                     int       nCmdShow)\r
+{\r
+       MSG msg;\r
+       HANDLE hAccelTable;\r
+       int argc=0, yy;\r
+       char *s, *argv[20], String[128];\r
+       HWND hWnd;\r
+    WSADATA WSAData;\r
+       char meep[MAX_PATH];\r
+\r
+       if ((debugfile = fopen("debugout2.log","ac"))==NULL)\r
+               MessageBox(NULL, "UnrealIRCD/32 Initalization Error", "Unable to create debugout.log",MB_OK);\r
+       windebug(WINDEBUG_FORCE,"Initializing Unreal wIRCd");\r
+       windebug(WINDEBUG_FORCE,"%s compiled on %s %s",version,__DATE__,__TIME__);\r
+       windebug(WINDEBUG_FORCE,"%s Last modifed %s",__FILE__,__TIMESTAMP__);\r
+\r
+\r
+       /* Create a new instance */\r
+    if ( WSAStartup(MAKEWORD(1, 1), &WSAData) != 0 )\r
+    {\r
+        MessageBox(NULL, "UnrealIRCD/32 Initalization Error", "Unable to initialize WinSock", MB_OK);\r
+        return FALSE;\r
+    }\r
+       /* Store instance handle in our global variable */\r
+       hInst = hInstance; \r
+    \r
+       hWnd = CreateDialog(hInstance, "wIRCD", 0, MainDLG); \r
+       if ( !hWnd )\r
+               return (FALSE);\r
+       hwIRCDWnd = hWnd;\r
+\r
+       {\r
+\r
+       HICON hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(sysicondisabled), IMAGE_ICON,16, 16, 0);\r
+       SysTray.cbSize = sizeof (NOTIFYICONDATA);\r
+                                        \r
+       SysTray.hIcon  = hIcon;\r
+       SysTray.hWnd   = hwIRCDWnd;\r
+       lstrcpyn(SysTray.szTip, shortversion, sizeof(shortversion));;\r
+       SysTray.uCallbackMessage = WM_USER;\r
+       SysTray.uFlags =  NIF_ICON | NIF_TIP | NIF_MESSAGE; \r
+       SysTray.uID    = 0;\r
+       \r
+       Shell_NotifyIcon(NIM_ADD ,&SysTray);\r
+       if (hIcon)\r
+               {\r
+               DestroyIcon(hIcon);\r
+               }\r
+       }\r
+\r
+       /*\r
+       **  We have initialised, start doing something usefull !\r
+       */\r
+       /* Parse the command line */\r
+       /*argv[0] = "WIRCD.EXE";*/\r
+       if ( (s = /*lpCmdLine*/ GetCommandLine()) )\r
+           {\r
+               argv[argc++] = s;\r
+               /*while ( (s = strchr(s, ' ')) != NULL )\r
+                   {*/\r
+       //              while ( *s == ' ' ) *s++ = 0;\r
+       //              argv[argc++] = s;\r
+                  // }\r
+           }\r
+       argv[argc] = NULL;\r
+\r
+       if ( InitwIRCD(argc, argv) != 1 )\r
+               {\r
+               MessageBox(NULL,"Unreal IRCd for Windows has failed to initialise in InitwIRCD()","Error:",MB_OK);\r
+               return FALSE;\r
+               }\r
+\r
+       /*Make sure we have the common controlls loaded ...\r
+        *And the Rich edit controll */\r
+       InitCommonControls();\r
+       LoadLibrary("RichEd20.Dll");\r
+       {\r
+\r
+       /* Setup WNDCLASS for graphy control*/\r
+       WNDCLASS wc;\r
+       memset(&wc,0,sizeof(WNDCLASS));\r
+\r
+       wc.style = CS_DBLCLKS ;\r
+       wc.lpfnWndProc = GraphCtlProc;\r
+       wc.cbWndExtra = 4;\r
+       wc.hInstance = hInst;\r
+       wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);\r
+       wc.lpszClassName = "Graph";\r
+       wc.lpszMenuName = NULL;\r
+       wc.hCursor = LoadCursor(NULL,IDC_ARROW);\r
+\r
+    if (!RegisterClass (&wc))\r
+      {\r
+        MessageBox (NULL,"Error Initializing RegisterClass() for class Graphy",\r
+                    (LPCTSTR) "UnrealIRCD/32 Initalization Error", MB_OK | MB_ICONEXCLAMATION);\r
+      }\r
+       }\r
+\r
+       wsprintf(String, "UnrealIRCd/32 - %s", me.name);\r
+       SetWindowText(hwIRCDWnd, String);\r
+       SetDebugLevel(hwIRCDWnd, debuglevel);\r
+\r
+       hMainThread = (HANDLE) _beginthread(SocketLoop, 0, NULL);\r
+       hAccelTable = LoadAccelerators (hInstance, szAppName);\r
+       {\r
+               HICON hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(sysicon), IMAGE_ICON,16, 16, 0);\r
+       SysTray.hIcon = hIcon;\r
+       Shell_NotifyIcon(NIM_MODIFY ,&SysTray);\r
+       if (hIcon)\r
+               {\r
+               DestroyIcon(hIcon);\r
+               }\r
+       }\r
+\r
+       atexit(NiceQuit);\r
+\r
+       /* Main message loop */\r
+       while (GetMessage(&msg, NULL, 0, 0))\r
+           {\r
+                       TranslateMessage(&msg);\r
+                       DispatchMessage(&msg);\r
+           }\r
+\r
+       windebug(WINDEBUG_FORCE,"Unreal Terminating ....");\r
+       Shell_NotifyIcon(NIM_DELETE ,&SysTray);\r
+       fclose(debugfile);\r
+\r
+       return msg.wParam;\r
+}\r
+\r
+void NiceQuit(void)\r
+{\r
+       windebug(WINDEBUG_FORCE,"Unreal Terminating ....");\r
+       Shell_NotifyIcon(NIM_DELETE ,&SysTray);\r
+       fclose(debugfile);\r
+}\r
+\r
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+           {\r
+               case WM_CREATE :\r
+                       return 0;\r
+\r
+/*             case WM_USER:\r
+                       windebug(WINDEBUGLEVEL_2,"entering WM_USER");\r
+                       switch(lParam)\r
+                               {\r
+                               case WM_LBUTTONDOWN:\r
+                                       /* We want to first ... get a pasword if required, then show the window*/\r
+/*                                     if (hwIRCDWnd)\r
+                                       {\r
+                                               ShowWindow (hwIRCDWnd, SW_SHOW);\r
+                                               ShowWindow (hwIRCDWnd,SW_RESTORE);\r
+                                               SetForegroundWindow(hwIRCDWnd);\r
+                                       }else{\r
+                                               hwIRCDWnd = CreateDialog(hInst, "wIRCD", 0, MainDLG);\r
+                                               ShowWindow (hwIRCDWnd, SW_SHOW);\r
+                                       }\r
+                                       break;\r
+                               }\r
+                       return 1;*/\r
+           }\r
+    return DefWindowProc(hWnd, message, wParam, lParam);\r
+}\r
+\r
+\r
+LRESULT CALLBACK MainDLG(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+int wmId, wmEvent;     \r
+static HMENU hMenu, hSystemSubMenu, hHelpSubMenu;\r
+switch (message)\r
+           {\r
+               case WM_INITDIALOG:\r
+                       {\r
+                       /* ToDo :: ReWrite whole menu routine .. to actually work properly ... and use MF_(UN)CHECKED !\r
+                       **    -- David Flynn 15-02-2000 **/\r
+                       /* Done ! Now uses windebuglevel  -- David Flynn 16-02-2000 **/\r
+\r
+                       hMenu       = LoadMenu(hInst, "Menu_PopUp");\r
+                   hSystemSubMenu = GetSubMenu(hMenu, 2);\r
+                   hHelpSubMenu = GetSubMenu(hMenu, 3);\r
+               SetMenuDefaultItem(hSystemSubMenu,IDM_IRCDCONF, MF_BYCOMMAND);\r
+                       SetTimer (hDlg, UPDATE_TIMER, UPDATE_INTERVAL, NULL);\r
+                       }\r
+                       return 1;\r
+\r
+               case WM_SIZE :\r
+                       windebug(WINDEBUGLEVEL_2,"recieved WM_SIZE");\r
+                       if (wParam & SIZE_MINIMIZED)\r
+                               {\r
+                                       ShowWindow(hDlg,SW_HIDE);\r
+                                       return 0;\r
+                               }\r
+\r
+               case WM_USER:\r
+                       windebug(WINDEBUGLEVEL_2,"entering WM_USER");\r
+                       switch(lParam)\r
+                               {\r
+                               case WM_LBUTTONDOWN:\r
+                                       /* We want to first ... get a pasword if required, then show the window*/\r
+                               /*      if (hwIRCDWnd)\r
+                                       {*/\r
+                                               ShowWindow (hDlg, SW_SHOW);\r
+                                               ShowWindow (hDlg,SW_RESTORE);\r
+                                               SetForegroundWindow(hDlg);\r
+                               //      }else{\r
+                               //              hwIRCDWnd = CreateDialog(hInst, "wIRCD", 0, MainDLG);\r
+                               //              ShowWindow (hwIRCDWnd, SW_SHOW);\r
+                               //      }\r
+                                       break;\r
+                               }\r
+                       return 1;\r
+\r
+               case WM_TIMER :\r
+                       switch(wParam)\r
+                               {\r
+                               case UPDATE_TIMER:\r
+                                       usernumhistory[usernumpointer] = lu_clu;\r
+                                       usernumpointer++;\r
+                                       usernumpointer %= 370;\r
+                                       if (hStatsWnd != NULL)\r
+                                               PostMessage(hgraphwnd,(WM_USER +1), 0,0);\r
+                                       return 1;\r
+                               }\r
+                       break;\r
+\r
+               case WM_COMMAND:\r
+                       \r
+                       wmId    = LOWORD(wParam);\r
+               wmEvent = HIWORD(wParam);\r
+\r
+                       switch(LOWORD(wParam))\r
+                           {\r
+                               case MM_WINDEBUGLEVEL_0 :\r
+                                       /*Standard Level Debug ... not much stuff*/\r
+                                       windebug(WINDEBUGLEVEL_1,"Recieved MM_WINDEBUGLEVEL_0, windebuglevel = %X", windebuglevel);\r
+                                       if ((windebuglevel & WINDEBUGLEVEL_0) != 0)\r
+                                               {\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_0) != 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_0,MF_UNCHECKED);\r
+                                               windebuglevel &= ~WINDEBUGLEVEL_0;\r
+                                               }else{\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_0) = 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_0,MF_CHECKED);\r
+                                               windebuglevel |= WINDEBUGLEVEL_0;\r
+                                               }\r
+                                       windebug(WINDEBUGLEVEL_1,"finished MM_WINDEBUGLEVEL_0, windebuglevel = %X", windebuglevel);\r
+                                       return 0;\r
+                               case MM_WINDEBUGLEVEL_1 :\r
+                                       /*Higher Level ... Look at when functions are called*/\r
+                                       windebug(WINDEBUGLEVEL_1,"Recieved MM_WINDEBUGLEVEL_1, windebuglevel = %X", windebuglevel);\r
+                                       if ((windebuglevel & WINDEBUGLEVEL_1) != 0)\r
+                                               {\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_1) != 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_1,MF_UNCHECKED);\r
+                                               windebuglevel &= ~WINDEBUGLEVEL_1;\r
+                                               }else{\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_1) = 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_1,MF_CHECKED);\r
+                                               windebuglevel |= WINDEBUGLEVEL_1;\r
+                                               }\r
+                                       windebug(WINDEBUGLEVEL_1,"finished MM_WINDEBUGLEVEL_1, windebuglevel = %X", windebuglevel);\r
+                                       return 0;\r
+                               case MM_WINDEBUGLEVEL_2 :\r
+                                       /*Higher Still ... Look at what happens in functions*/\r
+                                       windebug(WINDEBUGLEVEL_1,"Recieved MM_WINDEBUGLEVEL_2, windebuglevel = %X", windebuglevel);\r
+                                       if ((windebuglevel & WINDEBUGLEVEL_2) != 0)\r
+                                               {\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_2) != 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_2,MF_UNCHECKED);\r
+                                               windebuglevel &= ~WINDEBUGLEVEL_2;\r
+                                               }else{\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_2) = 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_2,MF_CHECKED);\r
+                                               windebuglevel |= WINDEBUGLEVEL_2;\r
+                                               }\r
+                                       windebug(WINDEBUGLEVEL_1,"finished MM_WINDEBUGLEVEL_2, windebuglevel = %X", windebuglevel);\r
+                                       return 0;\r
+                               case MM_WINDEBUGLEVEL_FLUSH :\r
+                                       /*Make fflush happen on windebug()*/\r
+                                       windebug(WINDEBUGLEVEL_1,"Recieved MM_WINDEBUGLEVEL_FLUSH, windebuglevel = %X", windebuglevel);\r
+                                       if ((windebuglevel & WINDEBUGLEVEL_FLUSH) != 0)\r
+                                               {\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_FLUSH) != 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_FLUSH,MF_UNCHECKED);\r
+                                               windebuglevel &= ~WINDEBUGLEVEL_FLUSH;\r
+                                               }else{\r
+                                               windebug(WINDEBUGLEVEL_1,"(windebuglevel & WINDEBUGLEVEL_FLUSH) = 0");\r
+                                               CheckMenuItem(hSystemSubMenu,MM_WINDEBUGLEVEL_FLUSH,MF_CHECKED);\r
+                                               windebuglevel |= WINDEBUGLEVEL_FLUSH;\r
+                                               }\r
+                                       windebug(WINDEBUGLEVEL_1,"finished MM_WINDEBUGLEVEL_FLUSH, windebuglevel = %X", windebuglevel);\r
+                                       return 0;\r
+                               case IDM_ABOUT:\r
+                                       DialogBox(hInst, "AboutBox", hDlg, (DLGPROC)About);\r
+                               return 0;\r
+                               case IDM_CREDITS:\r
+                                       DialogBox(hInst, "AboutBox", hDlg, (DLGPROC)Credits);\r
+                               return 0;\r
+                               case IDM_DF:\r
+                                       DialogBox(hInst, "AboutBox", hDlg, (DLGPROC)Dreamforge);\r
+                               return 0;\r
+                               case IDM_LICENSE:\r
+                                       DialogBox(hInst, "AboutBox", hDlg, (DLGPROC)IRCDLicense);\r
+                               return 0;\r
+                               case IDM_IRCDCONF:\r
+                                       DialogBox(hInst, "Dlg_IRCDCONF", hDlg, (DLGPROC)Dlg_IRCDCONF);\r
+                               return 0;\r
+                               case IDM_IRCDMOTD:\r
+                                       DialogBox(hInst, "DLG_IRCDMOTD", hDlg, (DLGPROC)Dlg_IRCDMOTD);\r
+                               return 0;\r
+                               case IDM_IRCDRULES:\r
+                                       DialogBox(hInst, "DLG_IRCDRULES", hDlg, (DLGPROC)Dlg_IRCDRULES);\r
+                               return 0;\r
+                               case IDM_REHASH:\r
+                                       MessageBox(hDlg,"Server Rehashing ....","Unreal wIRCd3",MB_OK | MB_APPLMODAL);\r
+                                       s_rehash();\r
+                               return 0;\r
+\r
+                               case IDM_EXIT:\r
+                                       if ( MessageBox(hDlg, "Are you sure?",\r
+                                               "Terminate UnrealIRCD/32",\r
+                                               MB_ICONQUESTION | MB_YESNO) == IDNO )\r
+                                               return 0;\r
+                                       DestroyWindow(hDlg);\r
+                                       return 0;\r
+                           }\r
+                       return 0;\r
+\r
+               case WM_RBUTTONDBLCLK:\r
+        case WM_LBUTTONDBLCLK:\r
+         // emulate default menu item for double click\r
+               DialogBox(hInst, "Dlg_IRCDCONF", hDlg, (DLGPROC)Dlg_IRCDCONF);\r
+         break;\r
+\r
+      case WM_LBUTTONDOWN: {\r
+         POINT p;\r
+                    p.x = LOWORD(lParam);\r
+                    p.y = HIWORD(lParam);\r
+                    /* Config popup */\r
+                    if ((p.x >= 149) && (p.x <= 198)\r
+                     && (p.y >= 173) && (p.y <= 186))\r
+                     {\r
+\r
+                       ClientToScreen(hDlg,&p);\r
+                       TrackPopupMenu(hSystemSubMenu,\r
+                                 TPM_LEFTALIGN|TPM_LEFTBUTTON,\r
+                                p.x,p.y,0,hDlg,NULL);\r
+\r
+                       return 0;\r
+                     }\r
+                    /* about popup */\r
+                    if ((p.x >= 206) && (p.x <= 252)\r
+                     && (p.y >= 173) && (p.y <= 186))\r
+                     {\r
+                       ClientToScreen(hDlg,&p);\r
+                       TrackPopupMenu(hHelpSubMenu,\r
+                                 TPM_LEFTALIGN|TPM_LEFTBUTTON,\r
+                                p.x,p.y,0,hDlg,NULL);\r
+                        return 0;\r
+                     }\r
+                      /* rehash button */\r
+                    if ((p.x >= 31) && (p.x <= 81)\r
+                     && (p.y >= 173) && (p.y <= 186))\r
+                     {\r
+                       PostMessage(hDlg, WM_COMMAND, IDM_REHASH, 0); \r
+                        return 0;\r
+                     }\r
+                      /* quit button */\r
+                    if ((p.x >= 264) && (p.x <= 328)\r
+                     && (p.y >= 173) && (p.y <= 186))\r
+                     {\r
+                        PostMessage(hDlg, WM_COMMAND, IDM_EXIT, 0);\r
+                        return 0;\r
+                     }\r
+                     /* status button */\r
+                    if ((p.x >= 93) && (p.x <= 138)\r
+                     && (p.y >= 173) && (p.y <= 186))\r
+                     {\r
+                       if (hStatsWnd == NULL){\r
+                        DialogBox(hInst, /*"WIRCDSTATUS"*/"DLG_STATS", NULL, (DLGPROC)wStatusDLG);\r
+                        return 0;\r
+                               }else{\r
+                               if (SetForegroundWindow(hStatsWnd)==0){\r
+                                       windebug(WINDEBUG_FORCE,"Error at BringWindowToTop(), Err=%d",GetLastError());\r
+                                       }\r
+                               return 0;\r
+                               }\r
+                                }\r
+                                          \r
+                     break;\r
+               }\r
+               case WM_CLOSE:\r
+                PostMessage(hDlg, WM_COMMAND, IDM_EXIT, 0);\r
+                       \r
+                       return 0;\r
+                       /* Fall through to destroy the window and then send to WM_QUIT to the msg que*/\r
+\r
+               case WM_DESTROY:\r
+                   KillTimer(hDlg, UPDATE_TIMER);\r
+                       localdie();\r
+\r
+                                                       /* Never returns *//* i hope it does ... */\r
+                                                       /* Ok ... It doesnt ... That _NEEDS_ Fixing !!!!!*/\r
+                                                       /* Fixed -- i hope */\r
+                       PostQuitMessage(0);\r
+                       return 0;\r
+\r
+               case WM_QUIT:\r
+                       if ( MessageBox(hDlg, "WM_QUIT Are you sure?", "Terminate UnrealIRCd/32",\r
+                                       MB_ICONQUESTION | MB_YESNO | MB_APPLMODAL) == IDNO )\r
+                               return 0;\r
+\r
+                       return 0;\r
+\r
+           }\r
+       DefWindowProc(hDlg, message, wParam, lParam);\r
+    return 0;\r
+}\r
+\r
+\r
+\r
+LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+           {\r
+               case WM_INITDIALOG:\r
+#define Ccat strcat(String, String2)\r
+                   {\r
+                       char    String[16384], String2[16384], **s = infotext;\r
+                       wsprintf(String, "%s\n%s", version, creation);\r
+                       SetDlgItemText(hDlg, IDC_VERSION, String);\r
+                       String[0] = 0; String2[0] = 0;\r
+                       wsprintf(String2, "-=-=-=-=-=-==-==- %s -=-=-==-==-=-=-=-=-=-\r\n", ircnetwork); Ccat;\r
+                       wsprintf(String2, "|Web Page:      | http://www.%s\r\n", netdomain); Ccat;\r
+                       wsprintf(String2, "|FTP Archive:   | ftp://ftp.%s\r\n", netdomain); Ccat;\r
+                       wsprintf(String2, "|Help channel:  | %s\r\n", helpchan); Ccat;\r
+                       wsprintf(String2, "|=-=-=-=-=-==-==|-=-=-=-=-=-=-==-==-=-=-=-=-=-=-=\r\n"); Ccat;\r
+                       wsprintf(String2, "|IRCd version:  | %s\r\n", IRCDTOTALVERSION); Ccat;                  \r
+                       wsprintf(String2, "| Programmer:   | Stskeeps <stskeeps@tspre.org>\r\n"); Ccat;\r
+                       wsprintf(String2, "| Win32 Coders: | DrBin <drbin@tspre.org>\r\n"); Ccat;\r
+                       wsprintf(String2, "|               | codemastr <codemastr@tspre.org>\r\n"); Ccat; \r
+                       wsprintf(String2, "|               | {X} <x@tspre.org>\r\n"); Ccat; \r
+#if defined(_WIN32) && defined(WIN32_SPECIFY)\r
+                       wsprintf(String2, "| Win32 Porter: | %s\r\n", WIN32_PORTER); Ccat;\r
+                       wsprintf(String2, "|     >>URL:    | %s\r\n", WIN32_URL); Ccat;\r
+#endif\r
+                       wsprintf(String2, "|Credits:       | Type /Credits\r\n"); Ccat;\r
+                       wsprintf(String2, "|DALnet Credits:| Type /DALinfo\r\n"); Ccat;\r
+                       wsprintf(String2, "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\r\n"); Ccat;\r
+                       wsprintf(String2, "| Unreal IRCd can be downloaded at http://unreal.tspre.org\r\n"); Ccat;      \r
+                       wsprintf(String2, "| This notice may not be removed from the IRCd package\r\n"); Ccat;\r
+                       wsprintf(String2, "| It will be a violation of copyright. This program must always\r\n"); Ccat;\r
+                       wsprintf(String2, "| stay free of charge being sold commercially or privately\r\n"); Ccat;\r
+                       wsprintf(String2, "| Only charge may be for the transport medium like on CD-ROM, floppy\r\n"); Ccat;\r
+                       wsprintf(String2, "| or other kinds (-Stskeeps'1999)\r\n"); Ccat;\r
+                       wsprintf(String2, "--------------------------------------------\r\n"); Ccat;\r
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);\r
+#undef Ccat\r
+                       ShowWindow (hDlg, SW_SHOW);\r
+                       return (TRUE);\r
+                   }\r
+\r
+               case WM_COMMAND:\r
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)\r
+                           {\r
+                               EndDialog(hDlg, TRUE);\r
+                               return (TRUE);\r
+                           }\r
+                       break;\r
+           }\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ *  FUNCTION: Credits(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "Credits" dialog box\r
+ *             This version allows greater flexibility over the contents of the 'Credits' box,\r
+ *             by pulling out values from the 'Version' resource.\r
+ *\r
+ *  MESSAGES:\r
+ *\r
+ *     WM_INITDIALOG - initialize dialog box\r
+ *     WM_COMMAND    - Input received\r
+ *\r
+ */\r
+LRESULT CALLBACK Credits(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+           {\r
+               case WM_INITDIALOG:\r
+                   {\r
+                       char    String[16384], **s = unrealcredits;\r
+\r
+                       wsprintf(String, "%s\n%s", version, creation);\r
+                       SetDlgItemText(hDlg, IDC_VERSION, String);\r
+                       String[0] = 0;\r
+                       while ( *s )\r
+                           {\r
+                               strcat(String, *s++);\r
+                               if ( *s )\r
+                                       strcat(String, "\r\n");\r
+                           }\r
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);\r
+\r
+\r
+                       ShowWindow (hDlg, SW_SHOW);\r
+                       return (TRUE);\r
+                   }\r
+\r
+               case WM_COMMAND:\r
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)\r
+                           {\r
+                               EndDialog(hDlg, TRUE);\r
+                               return (TRUE);\r
+                           }\r
+                       break;\r
+           }\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ *  FUNCTION: Dreamforge(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "Dreamforge" dialog box\r
+ *             This version allows greater flexibility over the contents of the 'Dreamforge' box,\r
+ *             by pulling out values from the 'Version' resource.\r
+ *\r
+ *  MESSAGES:\r
+ *\r
+ *     WM_INITDIALOG - initialize dialog box\r
+ *     WM_COMMAND    - Input received\r
+ *\r
+ */\r
+LRESULT CALLBACK Dreamforge(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+           {\r
+               case WM_INITDIALOG:\r
+                   {\r
+                       char    String[16384], **s = dalinfotext;\r
+\r
+                       wsprintf(String, "%s\n%s", version, creation);\r
+                       SetDlgItemText(hDlg, IDC_VERSION, String);\r
+                       String[0] = 0;\r
+                       while ( *s )\r
+                           {\r
+                               strcat(String, *s++);\r
+                               if ( *s )\r
+                                       strcat(String, "\r\n");\r
+                           }\r
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);\r
+\r
+\r
+                       ShowWindow (hDlg, SW_SHOW);\r
+                       return (TRUE);\r
+                   }\r
+\r
+               case WM_COMMAND:\r
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)\r
+                           {\r
+                               EndDialog(hDlg, TRUE);\r
+                               return (TRUE);\r
+                           }\r
+                       break;\r
+           }\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ *  FUNCTION: IRCDLicense(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "IRCDLicense" dialog box\r
+ *             This version allows greater flexibility over the contents of the 'IRCDLicense' box,\r
+ *             by pulling out values from the 'Version' resource.\r
+ *\r
+ *  MESSAGES:\r
+ *\r
+ *     WM_INITDIALOG - initialize dialog box\r
+ *     WM_COMMAND    - Input received\r
+ *\r
+ */\r
+LRESULT CALLBACK IRCDLicense(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+           {\r
+               case WM_INITDIALOG:\r
+                   {\r
+                       char    String[16384], **s = gnulicense;\r
+\r
+                       wsprintf(String, "%s\n%s", version, creation);\r
+                       SetDlgItemText(hDlg, IDC_VERSION, String);\r
+                       String[0] = 0;\r
+                       while ( *s )\r
+                           {\r
+                               strcat(String, *s++);\r
+                               if ( *s )\r
+                                       strcat(String, "\r\n");\r
+                           }\r
+                       SetDlgItemText(hDlg, IDC_INFOTEXT, String);\r
+\r
+\r
+                       ShowWindow (hDlg, SW_SHOW);\r
+                       return (TRUE);\r
+                   }\r
+\r
+               case WM_COMMAND:\r
+                       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)\r
+                           {\r
+                               EndDialog(hDlg, TRUE);\r
+                               return (TRUE);\r
+                           }\r
+                       break;\r
+           }\r
+    return FALSE;\r
+}\r
+\r
+\r
+/*\r
+ *  FUNCTION: Dlg_IrcdConf(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box\r
+ *\r
+ */\r
+LRESULT CALLBACK Dlg_IRCDCONF(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+    {\r
+        case WM_INITDIALOG:\r
+            {\r
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */\r
+                int   fd, Len;\r
+\r
+                if ( !Buffer )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",\r
+                        "UnrealIRCd/32 Setup", MB_OK);\r
+                    EndDialog(hDlg, FALSE);\r
+                                       return FALSE;\r
+                }\r
+                /* Open the ircd.conf file */\r
+                fd = open(CONFIGFILE, _O_RDONLY | _O_BINARY);\r
+                if ( fd == -1 )\r
+                   {\r
+                       MessageBox(hDlg, "Error: Could not open configuration file",\r
+                                  "UnrealIRCd/32 Setup", MB_OK);\r
+                       MyFree(Buffer);\r
+                       EndDialog(hDlg, FALSE);\r
+                       return FALSE;\r
+                   }\r
+\r
+                Buffer[0] = 0;          /* Incase read() fails */\r
+                Len = read(fd, Buffer, 65535);\r
+                Buffer[Len] = 0;\r
+                /* Set the text for the edit control to what was in the file */\r
+                SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_SETTEXT, 0,\r
+                    (LPARAM)(LPCTSTR)Buffer);\r
+\r
+                close(fd);\r
+                MyFree(Buffer);\r
+            }\r
+                       return (TRUE);\r
+\r
+               case WM_COMMAND:\r
+                       if ( LOWORD(wParam) == IDOK )\r
+            {\r
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */\r
+                DWORD Len;\r
+                int   fd;\r
+\r
+                if ( !Buffer )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",\r
+                        "UnrealIRCD/32 Setup", MB_OK);\r
+                    return TRUE;\r
+                }\r
+                /* Open the ircd.conf file */\r
+                fd = open(CONFIGFILE, _O_TRUNC|_O_CREAT|_O_RDWR|_O_BINARY,\r
+                       S_IREAD|S_IWRITE);\r
+                if ( fd == -1 )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not open configuration file",\r
+                        "UnrealIRCD/32 Setup", MB_OK);\r
+                    MyFree(Buffer);\r
+                    return TRUE;\r
+                }\r
+\r
+                /* Get the text from the edit control and save it to disk. */\r
+                Len = SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_GETTEXT, 65535,\r
+                    (LPARAM)(LPCTSTR)Buffer);\r
+                write(fd, Buffer, Len);\r
+\r
+                close(fd);\r
+                MyFree(Buffer);\r
+\r
+                               EndDialog(hDlg, TRUE);\r
+                               return TRUE;\r
+                       }\r
+            if ( LOWORD(wParam) == IDCANCEL )\r
+            {\r
+                EndDialog(hDlg, FALSE);\r
+                return TRUE;\r
+            }\r
+                       break;\r
+       }\r
+\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ *  FUNCTION: Dlg_Dlg_IRCdMotd(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box\r
+ *\r
+ */\r
+LRESULT CALLBACK Dlg_IRCDMOTD(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+    {\r
+        case WM_INITDIALOG:\r
+            {\r
+                char  *Buffer = MyMalloc(65535*2);   /* Should be big enough */\r
+                int   fd, Len;\r
+\r
+                if ( !Buffer )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",\r
+                        "UnrealIRCd/32 Setup", MB_OK);\r
+                    EndDialog(hDlg, FALSE);\r
+                                       return FALSE;\r
+                }\r
+                /* Open the ircd.motd file */\r
+                fd = open(MPATH, _O_RDONLY | _O_BINARY);\r
+                if ( fd == -1 )\r
+                   {\r
+                       MessageBox(hDlg, "Error: Could not open MOTD file",\r
+                                  "UnrealIRCd/32 Setup", MB_OK);\r
+                       MyFree(Buffer);\r
+                       EndDialog(hDlg, FALSE);\r
+                       return FALSE;\r
+                   }\r
+\r
+                Buffer[0] = 0;          /* Incase read() fails */\r
+                Len = read(fd, Buffer, 65535);\r
+                Buffer[Len] = 0;\r
+                /* Set the text for the edit control to what was in the file */\r
+                SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_SETTEXT, 0,\r
+                    (LPARAM)(LPCTSTR)Buffer);\r
+\r
+                close(fd);\r
+                MyFree(Buffer);\r
+            }\r
+                       return (TRUE);\r
+\r
+               case WM_COMMAND:\r
+                       if ( LOWORD(wParam) == IDOK )\r
+            {\r
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */\r
+                DWORD Len;\r
+                int   fd;\r
+\r
+                if ( !Buffer )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",\r
+                        "UnrealIRCD/32 Setup", MB_OK);\r
+                    return TRUE;\r
+                }\r
+                /* Open the ircd.motd file */\r
+                fd = open(MPATH, _O_TRUNC|_O_CREAT|_O_RDWR|_O_BINARY,\r
+                       S_IREAD|S_IWRITE);\r
+                if ( fd == -1 )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not open motd file",\r
+                        "UnrealIRCD/32 Setup", MB_OK);\r
+                    MyFree(Buffer);\r
+                    return TRUE;\r
+                }\r
+\r
+                /* Get the text from the edit control and save it to disk. */\r
+                Len = SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_GETTEXT, 65535,\r
+                    (LPARAM)(LPCTSTR)Buffer);\r
+                write(fd, Buffer, Len);\r
+\r
+                close(fd);\r
+                MyFree(Buffer);\r
+\r
+                               EndDialog(hDlg, TRUE);\r
+                               return TRUE;\r
+                       }\r
+            if ( LOWORD(wParam) == IDCANCEL )\r
+            {\r
+                EndDialog(hDlg, FALSE);\r
+                return TRUE;\r
+            }\r
+                       break;\r
+       }\r
+\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ *  FUNCTION: Dlg_IRCdRules(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box\r
+ *\r
+ */\r
+LRESULT CALLBACK Dlg_IRCDRULES(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+       switch (message)\r
+    {\r
+        case WM_INITDIALOG:\r
+            {\r
+                char  *Buffer = MyMalloc(65535*2);   /* Should be big enough */\r
+                int   fd, Len;\r
+\r
+                if ( !Buffer )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",\r
+                        "UnrealIRCd/32 Setup", MB_OK);\r
+                    EndDialog(hDlg, FALSE);\r
+                                       return FALSE;\r
+                }\r
+                /* Open the ircd.rules file */\r
+                fd = open(RPATH, _O_RDONLY | _O_BINARY);\r
+                if ( fd == -1 )\r
+                   {\r
+                       MessageBox(hDlg, "Error: Could not open rules file",\r
+                                  "UnrealIRCd/32 Setup", MB_OK);\r
+                       MyFree(Buffer);\r
+                       EndDialog(hDlg, FALSE);\r
+                       return FALSE;\r
+                   }\r
+\r
+                Buffer[0] = 0;          /* Incase read() fails */\r
+                Len = read(fd, Buffer, 65535);\r
+                Buffer[Len] = 0;\r
+                /* Set the text for the edit control to what was in the file */\r
+                SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_SETTEXT, 0,\r
+                    (LPARAM)(LPCTSTR)Buffer);\r
+\r
+                close(fd);\r
+                MyFree(Buffer);\r
+            }\r
+                       return (TRUE);\r
+\r
+               case WM_COMMAND:\r
+                       if ( LOWORD(wParam) == IDOK )\r
+            {\r
+                char  *Buffer = MyMalloc(65535);   /* Should be big enough */\r
+                DWORD Len;\r
+                int   fd;\r
+\r
+                if ( !Buffer )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not allocate temporary buffer",\r
+                        "UnrealIRCD/32 Setup", MB_OK);\r
+                    return TRUE;\r
+                }\r
+                /* Open the ircd.rules file */\r
+                fd = open(RPATH, _O_TRUNC|_O_CREAT|_O_RDWR|_O_BINARY,\r
+                       S_IREAD|S_IWRITE);\r
+                if ( fd == -1 )\r
+                {\r
+                    MessageBox(hDlg, "Error: Could not open rules file",\r
+                        "UnrealIRCD/32 Setup", MB_OK);\r
+                    MyFree(Buffer);\r
+                    return TRUE;\r
+                }\r
+\r
+                /* Get the text from the edit control and save it to disk. */\r
+                Len = SendDlgItemMessage(hDlg, IDC_IRCDCONF, WM_GETTEXT, 65535,\r
+                    (LPARAM)(LPCTSTR)Buffer);\r
+                write(fd, Buffer, Len);\r
+\r
+                close(fd);\r
+                MyFree(Buffer);\r
+\r
+                               EndDialog(hDlg, TRUE);\r
+                               return TRUE;\r
+                       }\r
+            if ( LOWORD(wParam) == IDCANCEL )\r
+            {\r
+                EndDialog(hDlg, FALSE);\r
+                return TRUE;\r
+            }\r
+                       break;\r
+       }\r
+\r
+    return FALSE;\r
+}\r
+\r
+/*\r
+ *  FUNCTION: wStatusDLG(HWND, unsigned, WORD, LONG)\r
+ *\r
+ *  PURPOSE:  Processes messages for "DLG_IRCDCONF" dialog box\r
+ *\r
+ */\r
+HWND hreditwnd;\r
+LRESULT CALLBACK wStatusDLG(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+static HWND hwTreeView/*hreditwnd*/;\r
+POINT p;\r
+char string[1024];\r
+const int i=0;\r
+LPNMTREEVIEW lpnmtv;\r
+static HWND hgraph;\r
+\r
+                       RECT TV;\r
+       switch (message)\r
+    {\r
+        case WM_INITDIALOG:\r
+            {\r
+CHARFORMAT2 FontFormat;\r
+WINSTATS  pWSTATS /*= (pWINSTATS) LocalAlloc (LPTR, sizeof(pWINSTATS))*/;\r
+                       windebug(WINDEBUGLEVEL_1,"wStatusDLG recieved WM_INITDIALOG");\r
+                       hStatsWnd = hDlg;\r
+                       TV.left=14;\r
+                       TV.right=140;\r
+                       TV.top=14;\r
+                       TV.bottom=240;\r
+                       SetLastError(0);\r
+                       if ((hreditwnd=CreateWindowEx(WS_EX_CLIENTEDGE,RICHEDIT_CLASS ,"Unreal wIRCd 3", WS_VISIBLE | WS_CHILD |\r
+                                ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY ,\r
+                                                       0, 245, 535, 185, hDlg, NULL, hInst, NULL))==NULL)\r
+                                                       MessageBox(NULL,"garhle","grargle", MB_OK);\r
+                       if (GetLastError()!=0)\r
+                               windebug(WINDEBUG_FORCE,"error %d",GetLastError());\r
+\r
+                       FontFormat.cbSize = sizeof(CHARFORMAT2);\r
+                       FontFormat.yHeight = 8 * 20 /* We measure it in twips (1/20th of a point !)*/;\r
+                       FontFormat.crTextColor = RGB(0,150,0);\r
+                       lstrcpyn(FontFormat.szFaceName, "Lucida Console", sizeof("Lucida Console"));;;\r
+                       FontFormat.dwMask = CFM_COLOR | CFM_FACE | CFM_SIZE | CFM_BOLD | CFM_PROTECTED;\r
+\r
+                       SendMessage(hreditwnd,EM_SETCHARFORMAT,SCF_ALL,&FontFormat);\r
+\r
+\r
+\r
+                       hwTreeView = CreateATreeView(hDlg,TV);\r
+               win_map(NULL, &me, "*", 0, 60,hwTreeView);\r
+                       windebug(WINDEBUGLEVEL_2,"hDlg = %d",hDlg);\r
+                       windebug(WINDEBUGLEVEL_2,"win_map completed");\r
+               //      for (i=0;i<TreeView_GetCount(hwTreeView);i++)\r
+               //              {\r
+               //              windebug(WINDEBUGLEVEL_2,"Allocating pWSTATS for i=%d of max %d",i,TreeView_GetCount(hwTreeView));\r
+                               {\r
+                               \r
+                               windebug(WINDEBUGLEVEL_2,"Allocated pWSTATS");\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.connections");\r
+                               pWSTATS.connections=current_load_data.conn_count;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.connections=%d",pWSTATS.connections);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.CurrGlobUsers");\r
+                               pWSTATS.CurrGlobUsers=lu_cglobalu;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.CurrGlobUsers=%d",pWSTATS.CurrGlobUsers);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.CurrLoclUsers");\r
+                               pWSTATS.CurrLoclUsers=lu_clu;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.CurrLoclUsers=%d",pWSTATS.CurrLoclUsers);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.MaxGlobUsers");\r
+                               pWSTATS.MaxGlobUsers=max_client_count;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.MaxGlobUsers=%d",pWSTATS.MaxGlobUsers);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.NumUsers");\r
+                               pWSTATS.NumUsers=lu_noninv;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.NumUsers=%d",pWSTATS.NumUsers);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.Invisible");\r
+                               pWSTATS.Invisible=lu_inv;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.Invisible=%d",pWSTATS.Invisible);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.Servers");\r
+                               pWSTATS.Servers=TreeView_GetCount(hwTreeView);\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.Servers=%d",pWSTATS.Servers);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.LocalClients");\r
+                               pWSTATS.LocalClients=lu_mlu;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.LocalClients=%d",pWSTATS.LocalClients);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.LocalServers");\r
+                               pWSTATS.LocalServers=lu_lserv;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.LocalServers=%d",pWSTATS.LocalServers);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.NumIRCops");\r
+                               pWSTATS.NumIRCops=lu_oper;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.NumIRCops=%d",pWSTATS.NumIRCops);\r
+\r
+                               windebug(WINDEBUGLEVEL_2,"assigning pWSTATS.chans");\r
+                               pWSTATS.chans=lu_channel;\r
+                               windebug(WINDEBUGLEVEL_2,"pWSTATS.chans=%d",pWSTATS.chans);\r
+                               wsprintf(string, "%d",pWSTATS.CurrLoclUsers);\r
+                               SetDlgItemText(hDlg,EDIT_CLOCAL,string);\r
+                               wsprintf(string, "%d",pWSTATS.MaxLoclUsers);\r
+                               SetDlgItemText(hDlg,EDIT_CLOCALMAX,string);\r
+                               wsprintf(string, "%d",pWSTATS.Invisible);\r
+                               SetDlgItemText(hDlg,EDIT_INV,string);\r
+                               wsprintf(string, "%d",pWSTATS.NumUsers);\r
+                               SetDlgItemText(hDlg,EDIT_NONINV,string);\r
+                               wsprintf(string, "%d",pWSTATS.Servers);\r
+                               SetDlgItemText(hDlg,EDIT_IRCSERVERS,string);\r
+                               wsprintf(string, "%d",pWSTATS.LocalClients);\r
+                               SetDlgItemText(hDlg,EDIT_MYUSERS,string);\r
+                               wsprintf(string, "%d",pWSTATS.LocalServers);\r
+                               SetDlgItemText(hDlg,EDIT_MYSERVERS,string);\r
+                               wsprintf(string, "%d",pWSTATS.CurrGlobUsers);\r
+                               SetDlgItemText(hDlg,EDIT_GLOBAL,string);\r
+                               wsprintf(string, "%d",pWSTATS.MaxLoclUsers);\r
+                               SetDlgItemText(hDlg,EDIT_GLOBALMAX,string);\r
+                               wsprintf(string, "%d",pWSTATS.NumIRCops);\r
+                               SetDlgItemText(hDlg,EDIT_IRCOPS,string);\r
+                               wsprintf(string, "%d",pWSTATS.chans);\r
+                               SetDlgItemText(hDlg,EDIT_CHANNELS,string);\r
+                               wsprintf(string, "%d",MAXCLIENTS);\r
+                               SetDlgItemText(hDlg,EDIT_LOCALMAXPOS,string);\r
+\r
+ SetLastError(0);\r
+       //                      SetWindowLong (hDlg,i, (LONG) pWSTATS);\r
+         windebug(WINDEBUGLEVEL_2,"Saved (pWSTATS) into (hDlg) offset = i = %d, Last error =%u",i,GetLastError());\r
+//LocalFree (LocalHandle ((LPVOID) pWSTATS));\r
+\r
+                               //store them in a safe place that we can find later\r
+                               \r
+                               }\r
+                       //      }\r
+                       //      {\r
+\r
+\r
+                       if ((hgraph=CreateWindowEx(WS_EX_CLIENTEDGE,"Graph","m",WS_VISIBLE | WS_CHILD, 166, 70, 364, 70, hDlg, NULL, hInst, NULL))==NULL)\r
+                              {\r
+                                  MessageBox (NULL,\r
+                    "Error Creating Graph Control \n CreateWindow (\"Graph\", \"\",WS_VISIBLE , 335, 25, 100, 400, hDlg, NULL, hInst, NULL)","Error CreatingWindow",\r
+                    MB_OK | MB_ICONEXCLAMATION);\r
+                                  }\r
+                                  windebug(WINDEBUGLEVEL_2,"CreateWindowEx==Success");\r
+                                       UpdateWindow(hgraph);\r
+                                       windebug(WINDEBUGLEVEL_1,"UpdateWindow");\r
+                       //}\r
+                       /*      {\r
+                               pWINSTATS pWSTATS = (pWINSTATS) GetWindowLong (hDlg, 0);\r
+                               if (pWSTATS == NULL)\r
+                                       {\r
+                                       windebug(WINDEBUGLEVEL_1,"Error Getting pWSTATS from GetWindowLong (hDlg,0) -> LastError = %u",GetLastError());\r
+                                       }else{\r
+\r
+                                               }\r
+                               }*/\r
+                   }\r
+                       return (TRUE);\r
+\r
+               case WM_DESTROY:\r
+               //      MessageBox(NULL,"destroying ....","WM_DESTROY",MB_OK);\r
+               //      windebug(WINDEBUG_FORCE,"hreditwnd = %d , TreeViewCount = %d",hreditwnd,TreeView_GetCount(hwTreeView));\r
+//                     for (i=0;i<TreeView_GetCount(hwTreeView);i++)\r
+                       {\r
+       //                      pWINSTATS pWSTATS = (pWINSTATS) GetWindowLong (hDlg, i);\r
+       //                      LocalFree (LocalHandle ((LPVOID) pWSTATS));\r
+                       }\r
+                       DestroyWindow(hreditwnd);\r
+                       return (TRUE);\r
+                       \r
+               case WM_NOTIFY: \r
+                       switch (((LPNMHDR) lParam)->code) {\r
+                               case TVN_SELCHANGED :\r
+                                            lpnmtv = ((LPNMTREEVIEW) lParam);\r
+                                                \r
+                               wsprintf(string, "%d",lpnmtv->itemNew.hItem);\r
+                               SetDlgItemText(hDlg,EDIT_CHANNELS,string);\r
+                                                \r
+                               break; \r
+\r
+                               // Handle other notifications here. \r
+\r
+                               }\r
+                       break; \r
+\r
+           case WM_RBUTTONDOWN: {\r
+                    p.x = LOWORD(lParam);\r
+                    p.y = HIWORD(lParam);\r
+                    wsprintf(String, "Clicked at (%li, %li)", p.x, p.y);\r
+                    SetWindowText(hDlg, String);\r
+                       }\r
+                       return TRUE;\r
+               case WM_COMMAND:\r
+                       if ( LOWORD(wParam) == IDOK )\r
+            {\r
+  \r
+                               EndDialog(hDlg, TRUE);\r
+                               return TRUE;\r
+                       }\r
+            if ( LOWORD(wParam) == IDCANCEL )\r
+            {\r
+                EndDialog(hDlg, FALSE);\r
+                return TRUE;\r
+            }\r
+                       break;\r
+       }\r
+\r
+    return FALSE;\r
+}\r
+\r
+HTREEITEM AddItemToTree (HWND hWnd, LPSTR lpszItem, int nLevel)\r
+{\r
+       \r
+    TVITEM tvi; \r
+    TVINSERTSTRUCT tvins; \r
+    static HTREEITEM hPrev = (HTREEITEM) TVI_FIRST; \r
+    static HTREEITEM hPrevRootItem = NULL; \r
+    static HTREEITEM hPrevLev2Item = NULL; \r
+    HTREEITEM hti; \r
\r
+    tvi.mask = TVIF_TEXT  | TVIF_PARAM; \r
\r
+    // Set the text of the item. \r
+    tvi.pszText = lpszItem; \r
+    tvi.cchTextMax = lstrlen(lpszItem); \r
\r
+    // Assume the item is not a parent item, so give it a \r
+    // document image. \r
+//    tvi.iImage = g_nDocument; \r
+//    tvi.iSelectedImage = g_nDocument; \r
\r
+    // Save the heading level in the item's application-defined \r
+    // data area. \r
+    tvi.lParam = (LPARAM) nLevel; \r
\r
+    tvins.item = tvi; \r
+    tvins.hInsertAfter = hPrev; \r
\r
+    // Set the parent item based on the specified level. \r
+    if (nLevel == 1) \r
+        tvins.hParent = TVI_ROOT; \r
+    else if (nLevel == 2) \r
+        tvins.hParent = hPrevRootItem; \r
+    else \r
+        tvins.hParent = hPrevLev2Item; \r
\r
+    // Add the item to the tree view control. \r
+    hPrev = (HTREEITEM) SendMessage(hWnd, TVM_INSERTITEM, 0, \r
+         (LPARAM) (LPTVINSERTSTRUCT) &tvins); \r
\r
+    // Save the handle to the item. \r
+    if (nLevel == 1) \r
+        hPrevRootItem = hPrev; \r
+    else if (nLevel == 2) {\r
+        hPrevLev2Item = hPrev; \r
+               TreeView_EnsureVisible(hWnd,hPrev);\r
+               }\r
+    // The new item is a child item. Give the parent item a \r
+    // closed folder bitmap to indicate it now has child items. \r
+    if (nLevel > 1) { \r
+        hti = TreeView_GetParent(hWnd, hPrev); \r
+        tvi.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE; \r
+        tvi.hItem = hti; \r
+//        tvi.iImage = g_nClosed; \r
+//        tvi.iSelectedImage = g_nClosed; \r
+        TreeView_SetItem(hWnd, &tvi); \r
+    } \r
\r
+    return hPrev; \r
+} \r
+\r
+\r
+// CreateATreeView - creates a tree view control. \r
+// Returns the handle to the new control if successful,\r
+// or NULL otherwise. \r
+// hwndParent - handle to the control's parent window. \r
+// lpszFileName - name of the file to parse for tree view items.\r
+\r
+HWND CreateATreeView(HWND hwndParent/*, LPSTR lpszFileName*/,RECT rcClient) \r
+{ \r
+   // RECT rcClient;  // dimensions of client area \r
+    HWND hwndTV;    // handle to tree view control \r
\r
+    // Ensure that the common control DLL is loaded. \r
+    InitCommonControls(); \r
\r
+    // Get the dimensions of the parent window's client area, and create \r
+    // the tree view control. \r
+    //GetClientRect(hwndParent, &rcClient); \r
+    hwndTV = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, "Tree View", \r
+        WS_VISIBLE | WS_CHILD /*| WS_BORDER | */| TVS_HASBUTTONS /*| TVS_DISABLEDRAGDROP \r
+               | TVS_SHOWSELALWAYS */ | TVS_HASLINES, \r
+        0, 0, rcClient.right, rcClient.bottom, \r
+        hwndParent, NULL/*(HMENU) ID_TREEVIEW*/, hInst, NULL); \r
\r
+                     \r
+    // Initialize the image list, and add items to the control. \r
+    // InitTreeViewImageLists and InitTreeViewItems are application- \r
+    // defined functions. \r
+ /*   if (!InitTreeViewImageLists(hwndTV) || \r
+            !InitTreeViewItems(hwndTV, lpszFileName)) { \r
+        DestroyWindow(hwndTV); \r
+        return FALSE; \r
+    }*/ \r
+    return hwndTV;\r
+} \r
+\r
+/*\r
+ * Based on the New /MAP format [dump_map()] -Potvin\r
+ * Now used to create list of servers for server list tree view -- David Flynn\r
+ */\r
+void win_map(cptr, server, mask, prompt_length, length, hwTreeView)\r
+aClient *cptr, *server;\r
+char *mask;\r
+register int prompt_length;\r
+int length;\r
+HWND hwTreeView;\r
+{\r
+        static char prompt[64];\r
+        register char *p = &prompt[prompt_length];\r
+        register int cnt = 0, local = 0;\r
+        aClient *acptr;\r
+\r
+\r
+                for (acptr = client; acptr; acptr = acptr->next)\r
+                {\r
+                    if (IsPerson(acptr))\r
+                    {\r
+                                ++cnt;                       /* == */\r
+                                if (!strcmp(acptr->user->server, server->name)) ++local;\r
+                    }\r
+                }\r
+\r
+            //    sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name, prompt, length, server->name,\r
+                       //              local, (local*100)/cnt );\r
+                               AddItemToTree (hwTreeView,server->name,1+prompt_length);\r
+                cnt = 0;\r
+            \r
+/*        if (prompt_length > 0)\r
+        {\r
+                p[-1] = ' ';\r
+                if (p[-2] == '`') p[-2] = ' ';\r
+        }*/\r
+\r
+//        if (prompt_length > 60) return;\r
+\r
+        strcpy(p, "|-");\r
+\r
+\r
+        for (acptr = client; acptr ; acptr = acptr->next)\r
+        {\r
+                if ( !IsServer (acptr) || strcmp(acptr->serv->up, server->name)) continue;\r
+\r
+                if ( match(mask, acptr->name) )\r
+                        acptr->flags &= ~FLAGS_MAP;\r
+                else\r
+                {\r
+                        acptr->flags |= FLAGS_MAP;\r
+                        cnt++;\r
+                }\r
+        }\r
+\r
+        for (acptr = client; acptr ; acptr = acptr->next)\r
+        {\r
+                if ( ! (acptr->flags & FLAGS_MAP) ||          /* != */\r
+                     !IsServer (acptr) || strcmp(acptr->serv->up, server->name)) continue;\r
+                if (--cnt == 0) *p = '`';\r
+                win_map (cptr, acptr, mask, prompt_length+1, length-2,hwTreeView);\r
+        }\r
+\r
+        if (prompt_length > 0) p[-1] = '-';\r
+}\r
+\r
+/****************************************************************\r
+**********    Graphy !!!! (C) David Flynn 2000 *****************/\r
+\r
+LRESULT CALLBACK GraphCtlProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)\r
+{\r
+                HDC mem;\r
+                PAINTSTRUCT ps;\r
+                RECT r;\r
+\r
+       switch (msg) {\r
+    case WM_CREATE:\r
+               {\r
+               RECT temprect;\r
+               HDC            hdc;\r
+        LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;\r
+        PGRAPHINFO  pSCI = (PGRAPHINFO) LocalAlloc (LPTR, sizeof(GRAPHINFO));\r
+        if (!pSCI)\r
+                       {\r
+                       MessageBox (NULL,\r
+                    "It Seems that you have a potential problem ... \n This function dont want to do a LocallAlloc() ... Report this at once !!!!",\r
+                    (LPCTSTR) "GRAPHCNT.DLL",\r
+                    MB_OK | MB_ICONEXCLAMATION);\r
+                       return -1;\r
+                       }\r
+               hgraphwnd=hwnd;\r
+               /*\r
+               ** I am initialising the "constants" now ... as they could be a root to my problems\r
+               */\r
+               pSCI->Grid        = 0x00008000;\r
+               pSCI->BackColor   =     0x00000000;\r
+               pSCI->GridColor   =     0x00008000;\r
+               pSCI->CPUColor    = 0x00000000;\r
+\r
+               GetClientRect(hwnd,&temprect);\r
+               pSCI->WindowSize.cx = temprect.right;\r
+               pSCI->WindowSize.cy = temprect.bottom;\r
+\r
+           windebug(WINDEBUGLEVEL_2,"memset(pSCI->cpuhistory, -1, 2048)");\r
+               memset(pSCI->cpuhistory, -1, 2048);\r
+               windebug(WINDEBUGLEVEL_2,"memset completed");\r
+               windebug(WINDEBUGLEVEL_2,"hwnd = %d",hwnd);\r
+\r
+               /*\r
+               ** Alloc the compatible DC for this control.\r
+               */\r
+\r
+               pSCI->DCBack = GetDC (hwnd);\r
+               windebug(WINDEBUGLEVEL_2,"got hdc");\r
+\r
+               pSCI->DCDblBuff = CreateCompatibleDC (pSCI->DCBack);\r
+\r
+               if (pSCI->DCDblBuff == NULL)\r
+                       {\r
+                       windebug(WINDEBUG_FORCE,"Damn Bloody Errors ... pSCI->DCDblBuff == NULL ... GAH !");\r
+                       }else{\r
+                       windebug(WINDEBUGLEVEL_2,"[((pSCI->DCDblBuff (=%d) = CreateCompatibleDC (hdc)) != NULL)] ~> GOOD!!!",pSCI->DCDblBuff);\r
+                       }\r
+               /*\r
+               ** Baa ... What is going on here, i ask myself ... referencing things before i have initialised them ..\r
+               **   -- fixed !!!!\r
+               */\r
+\r
+               pSCI->BMDblBuff = CreateCompatibleBitmap(pSCI->DCBack, pSCI->WindowSize.cx, pSCI->WindowSize.cy);\r
+\r
+               if ((pSCI->BMDblBuff == NULL))\r
+                       {\r
+                       windebug(WINDEBUG_FORCE,"According to my calculations ... pSCI->BMDblBuff = NULL --Ooops");\r
+                       }else{\r
+                       windebug(WINDEBUGLEVEL_2,"Created Compatable Bitmap (pSCI->BMDblBuff) from (pSCI->DCBack)");\r
+                       }         \r
+\r
+               pSCI->OldDblBuff = (HBITMAP)SelectObject(pSCI->DCDblBuff, pSCI->BMDblBuff);\r
+               windebug(WINDEBUGLEVEL_2,"Selected (pSCI->BMDblBuff) into (pSCI->DCDblBuff) -- old value saved to (pSCI->OldDblBuff)");\r
+\r
+               ReleaseDC (hwnd, pSCI->DCBack);\r
+               windebug(WINDEBUGLEVEL_2,"Released (hdc)");\r
+\r
+\r
+\r
+               SetLastError(0);\r
+                 \r
+               SetWindowLong (hwnd, GWL_GRAPHDATA, (LONG) pSCI);\r
+                 \r
+//       windebug(WINDEBUGLEVEL_2,"Saved (pSCI) into (hwnd) offset = GWL_GRAPHDATA, Last error =%u",GetLastError());\r
+//      SetTimer (hwnd, GRAPH_EVENT, UPDATE_INTERVAL, NULL);\r
+//       windebug(WINDEBUGLEVEL_2,"SetTimer");\r
+\r
+         return 1;\r
+               }\r
+       case WM_ERASEBKGND:\r
+               {\r
+               windebug(WINDEBUGLEVEL_2,"recieved WM_ERASEBKGND");\r
+               }\r
+                return 1;\r
+       case WM_PAINT:\r
+               windebug(WINDEBUGLEVEL_2,"recieved WM_PAINT");\r
+               SetLastError(0);\r
+                       {\r
+               PGRAPHINFO pSCI = (PGRAPHINFO) GetWindowLong (hwnd, GWL_GRAPHDATA);\r
+               if (pSCI==NULL)\r
+                       {\r
+                       windebug(WINDEBUGLEVEL_2,"Error from GetWindowLong ~> %u",GetLastError);\r
+                       return FALSE;\r
+                       }\r
+               windebug(WINDEBUGLEVEL_2,"got pSCI from GetWindowLong()");\r
+               windebug(WINDEBUGLEVEL_2,"Testing pSCI .... pSCI->BMDblBuff=%d",pSCI->BMDblBuff);\r
+                GetClientRect(hwnd, &r);\r
+                windebug(WINDEBUGLEVEL_2,"got GetClientRect()=&r= r.bottom->%d, r.left->%d, r.right->%d, r.top->%d",r.bottom ,r.left,r.right,r.top);\r
+\r
+                DrawMonitor(pSCI->DCDblBuff, r,hwnd);\r
+                windebug(WINDEBUGLEVEL_2,"DrawMonitor returned");\r
+                mem = BeginPaint(hwnd, &ps);\r
+                BitBlt(mem, 0, 0, pSCI->WindowSize.cx, pSCI->WindowSize.cy, pSCI->DCDblBuff, 0, 0, SRCCOPY);\r
+                EndPaint(hwnd, &ps);\r
+         DeleteDC(mem);\r
+                return 0;\r
+               }\r
+\r
+       case (WM_USER + 1):\r
+                       GetClientRect(hwnd, &r);\r
+                       InvalidateRect(hwnd, &r, FALSE);\r
+\r
+       case WM_TIMER:\r
+         windebug(WINDEBUGLEVEL_2,"recieved WM_TIMER");\r
+      switch (wParam)\r
+      {\r
+        case GRAPH_EVENT:\r
+        {\r
+                       windebug(WINDEBUGLEVEL_2,"  -> Specifically GRAPH_EVENT");\r
+                       {PGRAPHINFO pSCI = (PGRAPHINFO) GetWindowLong (hwnd, GWL_GRAPHDATA);\r
+                       if (pSCI == NULL)\r
+                               windebug(WINDEBUGLEVEL_2,"Failed retreval of pSCI");\r
+                       pSCI->cpuhistory[pSCI->cpupointer] = (rand()%100)/1.5+20/**data*/;\r
+                       pSCI->cpupointer++;\r
+                       pSCI->cpupointer %= pSCI->width;\r
+               SetWindowLong (hwnd, GWL_GRAPHDATA, (LONG) pSCI);\r
+                       // Invalidate client. This causes a WM_PAINT message to be sent to our window\r
+                       GetClientRect(hwnd, &r);\r
+                       InvalidateRect(hwnd, &r, FALSE);\r
+          break;\r
+                       }\r
+        }\r
+      }\r
+\r
+      break;\r
+\r
+\r
+    case WM_DESTROY:\r
+        {\r
+\r
+               PGRAPHINFO pSCI = (PGRAPHINFO) GetWindowLong (hwnd, GWL_GRAPHDATA);\r
+//         KillTimer(hwnd, GRAPH_EVENT);\r
+               hStatsWnd = NULL;\r
+               //New DoubleBuffer Code\r
+               //SelectObject(DCBack, OldBack);\r
+\r
+           if(pSCI->DCBack)\r
+                  DeleteDC(pSCI->DCBack);\r
+       if(pSCI->BMBack)\r
+              DeleteObject(pSCI->BMBack);\r
+       //Free our DoubleBuffer Handles\r
+\r
+               if(pSCI->DCDblBuff) {\r
+                       SelectObject(pSCI->DCDblBuff, pSCI->OldDblBuff);\r
+                       DeleteDC(pSCI->DCDblBuff);\r
+               }\r
+\r
+               pSCI->DCDblBuff = NULL;\r
+\r
+               if(pSCI->BMDblBuff) {\r
+                       DeleteObject(pSCI->BMDblBuff);\r
+               }\r
+\r
+               pSCI->BMDblBuff = NULL;\r
+\r
+\r
+                     LocalFree (LocalHandle ((LPVOID) pSCI));\r
+        }\r
+               break;\r
+\r
+       default:\r
+               return DefWindowProc(hwnd,msg,wParam,lParam);\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+void DrawMonitor(HDC hdc, RECT r,HWND hwnd)\r
+{\r
+       {\r
+       windebug(WINDEBUGLEVEL_2,"Entering DrawMonitor"); \r
+       }\r
+       {\r
+               PGRAPHINFO pSCI = (PGRAPHINFO) GetWindowLong (hwnd, GWL_GRAPHDATA);\r
\r
+\r
+\r
+ int i, j;\r
+ HBRUSH brush;\r
+ HPEN pen, oldpen, dotpen;\r
+ HBITMAP graphmask;\r
+ HDC image, mask;\r
+ int height;\r
+int BorderTop = 0, BorderBottom = 0, BorderLeft= 0,BorderRight=0;\r
+windebug(WINDEBUGLEVEL_2,"Got pSCI from hwnd (=%d)",hwnd);\r
+windebug(WINDEBUGLEVEL_2,"initialised vars");\r
+ // Set border\r
+ r.top += BorderTop;\r
+ r.bottom -= BorderBottom;\r
+ r.left += BorderLeft;\r
+ r.right -= BorderRight;\r
+windebug(WINDEBUGLEVEL_2,"initialised vars -- 1");\r
+ pSCI->width  = (r.right - r.left); // Width of graph\r
+ height = (r.bottom - r.top); // Height of graph\r
+windebug(WINDEBUGLEVEL_2,"initialised vars -- 2");\r
+windebug(WINDEBUGLEVEL_2,"pSCI->Background=%d,pSCI->BMBack=%d,pSCI->BMDblBuff=%d,pSCI->BackColor=%d,pSCI->GridColor=%d,pSCI->WindowSize.cx=%d,pSCI->WindowSize.cy=%d,pSCI->cpupointer=%d",pSCI->Background,pSCI->BMBack,pSCI->BMDblBuff,pSCI->BackColor,pSCI->GridColor,pSCI->WindowSize.cx,pSCI->WindowSize.cy,pSCI->cpupointer);\r
+\r
+       // Draw Background\r
+ /*if (Background)\r
+   {\r
+    HDC src = CreateCompatibleDC(NULL);\r
+    SelectObject(src, Background);\r
+    BitBlt(hdc, 0, 0, WindowSize.cx, WindowSize.cy, src, 0, 0, SRCCOPY);\r
+       DeleteObject(src);\r
+   }\r
+ else*/\r
+   {\r
+    brush = CreateSolidBrush(pSCI->BackColor);\r
+    FillRect(hdc, &r, brush);\r
+    DeleteObject(brush);\r
+   }\r
+\r
+       // Draw Grid\r
+  if (pSCI->Grid) {\r
+               pen = CreatePen(PS_SOLID, 1, pSCI->GridColor);\r
+               oldpen = SelectObject(hdc, pen);\r
+\r
+               for (i=1; i<((r.bottom - r.top)%10 + 1); i++) {\r
+                       MoveToEx(hdc, r.left, r.top +/* ((r.bottom - r.top) / 10)*/ 10 * i, NULL);\r
+                       LineTo(hdc, r.right/*-1*/, r.top + /*((r.bottom - r.top) / 10)*/ 10 * i);\r
+                       windebug(WINDEBUGLEVEL_2,"i =%d, pen = %d , oldpen = %d , pSCI->Grid = %d", i,pen,oldpen,pSCI->Grid);\r
+               }\r
+\r
+               for (i=1; i<((r.right-r.left)/10+/*pSCI->cpupointer*/usernumpointer); i++) {\r
+                       MoveToEx(hdc, r.left + ((/*(r.right-r.left) / */ 10)*i-(/*pSCI->cpupointer*/usernumpointer)), r.top, NULL);\r
+                       LineTo(hdc, r.left + ((/*(r.right-r.left)/ */ 10)*i-(/*pSCI->cpupointer*/usernumpointer)), r.bottom/*-1*/);\r
+               }\r
+\r
+               SelectObject(hdc, oldpen);\r
+               DeleteObject(pen);\r
+       }\r
+windebug(WINDEBUGLEVEL_2,"Drawn Grid");\r
+\r
+/* mask = CreateCompatibleDC(NULL);\r
+\r
+ graphmask = CreateCompatibleBitmap(mask, pSCI->WindowSize.cx, pSCI->WindowSize.cy);\r
+ SelectObject(mask, graphmask);\r
+\r
+ brush = CreateSolidBrush(0x0FFFFFF);\r
+ FillRect(mask, &r, brush);\r
+ DeleteObject(brush);\r
+\r
+ pen = CreatePen(PS_SOLID, 1, 0x0FFFFF);\r
+ SelectObject(mask, pen);\r
+ oldpen = SelectObject(mask, pen);*/\r
+\r
+\r
+ j = (/*pSCI->cpupointer*/ usernumpointer + pSCI->width) % pSCI->width;\r
+ if (usernumhistory/*pSCI->cpuhistory*/[j-1]!= -1){ \r
+ //MoveToEx(mask, r.left, r.bottom-(height * pSCI->cpuhistory[j]/100), NULL);\r
+\r
+ for (i=0; i<pSCI->width; i++)\r
+   {\r
+    j++;\r
+       j %= pSCI->width;\r
+//     MoveToEx(mask, r.left+i, r.bottom-(height * pSCI->cpuhistory[j]/100), NULL);\r
+  //  LineTo(mask, r.left+i, r.bottom);\r
+//windebug(WINDEBUGLEVEL_2,"j = %d pSCI->width= %d , i= %d , pSCI->cpuhistory[j]=%d pSCI->cpuhistory[j+1]= %d pSCI->cpuhistory[j-1]= %d",j,pSCI->width,i,pSCI->cpuhistory[j],pSCI->cpuhistory[j+1],pSCI->cpuhistory[j-1]);\r
+                       if (i==0)\r
+                               MoveToEx(hdc, r.left-1, r.bottom-(pSCI->width * usernumhistory/*pSCI->cpuhistory*/[j]/ MAXCLIENTS /*(1+lu_mlu+(lu_mlu*(75/100)))*/), NULL);\r
+                       dotpen = CreatePen(PS_SOLID, 0, 0x0000FF00);\r
+                   oldpen = SelectObject(hdc, dotpen);\r
+                       LineTo(hdc, r.left+i, r.bottom-(pSCI->width * usernumhistory/*pSCI->cpuhistory*/[j]/ MAXCLIENTS/*(1+lu_mlu+(lu_mlu*(75/100)))*/));\r
+            SelectObject(hdc, oldpen);\r
+                   DeleteObject(dotpen);\r
+\r
+   }\r
+        }\r
+// SelectObject(mask, oldpen);\r
+// DeleteObject(pen);\r
+\r
+// image = CreateCompatibleDC(NULL);\r
+// SelectObject(image, CPUMap);\r
+\r
+// BitBlt(hdc, BorderLeft, BorderTop,pSCI->width, height, image, BorderLeft, BorderTop, SRCINVERT);\r
+ //BitBlt(hdc, BorderLeft, BorderTop,width, height, mask,  BorderLeft, BorderTop, SRCAND);\r
+// BitBlt(hdc, BorderLeft, BorderTop,pSCI->width, height, image, BorderLeft, BorderTop, SRCINVERT);\r
+\r
+ DeleteObject(graphmask);\r
+\r
+// DeleteObject(CPUMap);\r
+\r
+ DeleteDC(mask);\r
+// DeleteDC(image);\r
+ SetWindowLong (hwnd, GWL_GRAPHDATA, (LONG) pSCI);\r
+}\r
+\r
+}\r
+\r
+\r
+/***************************************************************\r
+*****************   Debug Code Added 14-02 *********************\r
+*****************   Modified 16-02         ********************/\r
+\r
+void   windebug(level, form, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)\r
+int    level;\r
+char   *form, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10;\r
+{\r
+       static  char    windebugbuf[1024];\r
+       static  char    windebugbuf2[1024];\r
+       char tmpbuf[128];\r
+       char tmpbuf2[128];\r
+/*\r
+0x0000001 = General Debug\r
+0x0000002 = Graphy Specific Debug\r
+0x0000004 = [undefined]\r
+0x0000008 = [undefined]\r
+0x0000010 = [undefined]\r
+*/\r
+       if (((windebuglevel & level) != 0)||(level & WINDEBUG_FORCE))\r
+               {\r
+                       int     err = WSAGetLastError();\r
+                       (void)sprintf(windebugbuf, form,\r
+                               p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);\r
+                       _strdate( tmpbuf );\r
+                       _strtime( tmpbuf2 );\r
+                       (void)sprintf(windebugbuf2, "%s %s::%s", tmpbuf,tmpbuf2,windebugbuf );\r
+\r
+\r
+               strcat(windebugbuf2, "\n");\r
+               fprintf(debugfile,windebugbuf2);\r
+               if (((windebuglevel & WINDEBUGLEVEL_FLUSH) != 0)||(level & WINDEBUG_FORCE))\r
+                       fflush(debugfile);\r
+               WSASetLastError(err);\r
+         }\r
+if (0)\r
+       {\r
+SETTEXTEX TextEx;\r
+TextEx.codepage = CP_ACP;\r
+SendMessage(hreditwnd,EM_SETTEXTEX,&TextEx,form);\r
+       }\r
+}\r
+\r
+int    SetDebugLevel(HWND hWnd, int NewLevel)\r
+{\r
+       HMENU   hMenu = GetMenu(hWnd);\r
+\r
+       if ( !hMenu || !(hMenu = GetSubMenu(hMenu, 1)) ||\r
+            !(hMenu = GetSubMenu(hMenu, 4)) )\r
+               return -1;\r
+\r
+       CheckMenuItem(hMenu, IDM_DBGFATAL+debuglevel,\r
+               MF_BYCOMMAND | MF_UNCHECKED);\r
+       debuglevel = NewLevel;\r
+       CheckMenuItem(hMenu,IDM_DBGFATAL+debuglevel,\r
+               MF_BYCOMMAND | MF_CHECKED);\r
+\r
+       return debuglevel;\r
+}\r
+\r
+/**************************************************************/\r
+int GUI_TextWaiting(char *szInBuf,int iLength)\r
+{\r
+return 0;\r
+}
\ No newline at end of file
diff --git a/src/win32/Win32GUI.rc b/src/win32/Win32GUI.rc
new file mode 100644 (file)
index 0000000..cfb3468
--- /dev/null
@@ -0,0 +1,409 @@
+//Microsoft Developer Studio generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#define APSTUDIO_HIDDEN_SYMBOLS\r
+#include "windows.h"\r
+#undef APSTUDIO_HIDDEN_SYMBOLS\r
+#include "resource.h"\r
+#include "winver.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.S.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "#include ""windows.h""\r\n"\r
+    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"\r
+    "#include ""resource.h""\r\n"\r
+    "#include ""winver.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE DISCARDABLE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+#endif    // English (U.S.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (U.K.) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)\r
+#ifdef _WIN32\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK\r
+#pragma code_page(1252)\r
+#endif //_WIN32\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Menu\r
+//\r
+\r
+MENU_POPUP MENU DISCARDABLE \r
+BEGIN\r
+    POPUP "popup"\r
+    BEGIN\r
+        POPUP "&System"\r
+        BEGIN\r
+            MENUITEM "Ircd.&Conf",                  65535\r
+            MENUITEM "Ircd.&Motd",                  IDM_IRCDMOTD\r
+            MENUITEM "Ircd.R&ules",                 IDM_IRCDRULES\r
+            MENUITEM SEPARATOR\r
+            MENUITEM "&Rehash",                     IDM_REHASH\r
+        END\r
+    END\r
+    POPUP """popup"""\r
+    BEGIN\r
+        POPUP "&System"\r
+        BEGIN\r
+            MENUITEM "Ircd.&Conf",                  65535\r
+            MENUITEM "Ircd.&Motd",                  IDM_IRCDMOTD\r
+            MENUITEM "Ircd.R&ules",                 IDM_IRCDRULES\r
+            MENUITEM SEPARATOR\r
+            MENUITEM "&Rehash",                     IDM_REHASH\r
+        END\r
+    END\r
+    POPUP "system"\r
+    BEGIN\r
+        MENUITEM "Ircd.&Conf",                  65535\r
+        MENUITEM "Ircd.&Motd",                  IDM_IRCDMOTD\r
+        MENUITEM "Ircd.R&ules",                 IDM_IRCDRULES\r
+        MENUITEM SEPARATOR\r
+        MENUITEM "&Rehash",                     IDM_REHASH\r
+        POPUP "Debug Level"\r
+        BEGIN\r
+            MENUITEM "&Off",                        IDM_DBGOFF\r
+            MENUITEM "&Fatal",                      IDM_DBGFATAL\r
+            MENUITEM "&Error",                      IDM_DBGERROR\r
+            MENUITEM "&Notice",                     IDM_DBGNOTICE\r
+            MENUITEM "&DNS",                        IDM_DBGDNS\r
+            MENUITEM "&Info",                       IDM_DBGINFO\r
+            MENUITEM "N&umerics",                   IDM_DBGNUM\r
+            MENUITEM "&Send",                       IDM_DBGSEND\r
+            MENUITEM "&Debug",                      IDM_DBGDEBUG\r
+            MENUITEM "&Malloc",                     IDM_DBGMALLOC\r
+            MENUITEM "&List",                       IDM_DBGLIST\r
+        END\r
+        POPUP "WinDebugLevel"\r
+        BEGIN\r
+            MENUITEM "1 - Application General",     MM_WINDEBUGLEVEL_0\r
+            MENUITEM "2 - Flow Debug",              MM_WINDEBUGLEVEL_1\r
+            MENUITEM "3 - Extreeme Deatail",        MM_WINDEBUGLEVEL_2\r
+            MENUITEM SEPARATOR\r
+            MENUITEM "Flush Every WinDebug()",      MM_WINDEBUGLEVEL_FLUSH\r
+        END\r
+    END\r
+    POPUP "help"\r
+    BEGIN\r
+        MENUITEM "&Credits...",                 IDM_CREDITS\r
+        MENUITEM "&Dreamforge Credits...",      IDM_DF\r
+        MENUITEM "&License...",                 IDM_LICENSE\r
+        MENUITEM "&About UnrealIRCD/32...",     IDM_ABOUT\r
+    END\r
+END\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Dialog\r
+//\r
+\r
+DLG_IRCDCONF DIALOG DISCARDABLE  0, 0, 294, 159\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "UnrealIRCd Setup"\r
+FONT 9, "MS Sans Serif"\r
+BEGIN\r
+    DEFPUSHBUTTON   "&Save",IDOK,3,143,50,14\r
+    PUSHBUTTON      "&Cancel",IDCANCEL,241,143,50,14\r
+    EDITTEXT        IDC_IRCDCONF,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | \r
+                    ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL\r
+END\r
+\r
+DLG_IRCDRULES DIALOG DISCARDABLE  0, 0, 294, 159\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "UnrealIRCd Setup"\r
+FONT 9, "MS Sans Serif"\r
+BEGIN\r
+    DEFPUSHBUTTON   "&Save",IDOK,3,143,50,14\r
+    PUSHBUTTON      "&Cancel",IDCANCEL,241,143,50,14\r
+    EDITTEXT        IDC_IRCDCONF,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | \r
+                    ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL\r
+END\r
+\r
+DLG_IRCDMOTD DIALOG DISCARDABLE  0, 0, 294, 159\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "UnrealIRCd Setup"\r
+FONT 9, "MS Sans Serif"\r
+BEGIN\r
+    DEFPUSHBUTTON   "&Save",IDOK,3,143,50,14\r
+    PUSHBUTTON      "&Cancel",IDCANCEL,241,143,50,14\r
+    EDITTEXT        IDC_IRCDCONF,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | \r
+                    ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL | WS_HSCROLL\r
+END\r
+\r
+WIRCD DIALOG DISCARDABLE  0, 0, 240, 130\r
+STYLE DS_ABSALIGN | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | \r
+    WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU\r
+CAPTION "Unreal IRCD/32"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    CTEXT           "Ported by Stskeeps <stskeeps@tspre.org> - http://unreal.tspre.org",\r
+                    TXT_PORT,7,120,225,10\r
+    CONTROL         "OBM_wIRCD",IDC_STATIC,"Static",SS_BITMAP,7,7,225,97\r
+    CONTROL         "OBM_bar",IDC_STATIC,"Static",SS_BITMAP,7,105,225,14\r
+END\r
+\r
+WIRCDSTATUS DIALOG DISCARDABLE  0, 0, 400, 164\r
+STYLE DS_ABSALIGN | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | \r
+    DS_CENTERMOUSE | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "IRCd Status"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    CONTROL         "",IDC_STATIC,"Static",SS_BLACKFRAME,230,5,168,97\r
+    LTEXT           "Current Local Users:",TXT_LOCALUSERS,232,7,118,10\r
+    EDITTEXT        EDIT_CLOCAL,310,7,30,10,ES_READONLY\r
+    LTEXT           "Max:",TXT_LOCALMAX,345,7,30,10\r
+    EDITTEXT        EDIT_CLOCALMAX,365,7,30,10,ES_READONLY\r
+    LTEXT           "Current Global Users:",TXT_GLOBALUSERS,232,17,118,10\r
+    EDITTEXT        EDIT_GLOBAL,310,17,30,10,ES_READONLY\r
+    LTEXT           "Max:",TXT_GLOBALMAX,345,17,30,10\r
+    EDITTEXT        EDIT_GLOBALMAX,365,17,30,10,ES_READONLY\r
+    LTEXT           "Users:",TXT_NONINV,232,27,118,10\r
+    EDITTEXT        EDIT_NONINV,310,27,30,10,ES_READONLY\r
+    LTEXT           "Inv:",TXT_INV,345,27,30,10\r
+    EDITTEXT        EDIT_INV,365,27,30,10,ES_READONLY\r
+    LTEXT           "IRC servers networked:",TXT_IRCSERVERS,232,37,118,10\r
+    EDITTEXT        EDIT_IRCSERVERS,310,37,30,10,ES_READONLY\r
+    LTEXT           "IRC operator(s) online:",TXT_IRCOPS,232,47,118,10\r
+    EDITTEXT        EDIT_IRCOPS,310,47,30,10,ES_READONLY\r
+    LTEXT           "Local clients",TXT_MYUSERS,232,57,118,10\r
+    EDITTEXT        EDIT_MYUSERS,310,57,30,10,ES_READONLY\r
+    LTEXT           "Local server links",TXT_MYSERVERS,232,67,118,10\r
+    EDITTEXT        EDIT_MYSERVERS,310,67,30,10,ES_READONLY\r
+    LTEXT           "Channels formed",TXT_CHANNELS,232,77,118,10\r
+    EDITTEXT        EDIT_CHANNELS,310,77,30,10,ES_READONLY\r
+    CTEXT           "Report from dd/mm/yy hh:dd",TXT_WHEN,260,87,120,10\r
+    LTEXT           "[ UnrealIRCd/32 v2.1.7 ] - Release *",TXT_VERSION,7,104,\r
+                    350,10\r
+    LTEXT           "UnrealIRCd/32 GUI is (C) Stskeeps <stskeeps@tspre.org> and {X} <djhype@home.com>",\r
+                    TXT_CRINFO,7,114,350,10\r
+    LTEXT           "UnrealIRCd logo (C) zero9000 (Kevin Alford)",\r
+                    TXT_CRINFO1,7,124,350,10\r
+    LTEXT           "Copying/Ripping this GUI for other wIRCds is NOT allowed unless permission is gained by the authors",\r
+                    TXT_CRINFO2,7,134,350,10\r
+    LTEXT           "The source is placed under the GPL but the look-n-feel may not be copied",\r
+                    TXT_CRINFO3,7,144,350,10\r
+    LTEXT           "- contact stskeeps@tspre.org for more information",TXT_CRINFO4,7,\r
+                    154,350,10\r
+    CONTROL         "OBM_wIRCD",IDC_STATIC,"Static",SS_BITMAP,7,5,225,97\r
+END\r
+\r
+WIRCDABOUT DIALOG DISCARDABLE  0, 0, 400, 164\r
+STYLE DS_ABSALIGN | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | \r
+    DS_CENTERMOUSE | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | \r
+    WS_SYSMENU\r
+CAPTION "About UnrealIRCd/32"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+END\r
+\r
+DLG_STATS DIALOGEX 0, 0, 359, 263\r
+STYLE DS_ABSALIGN | DS_MODALFRAME | DS_3DLOOK | DS_NOFAILCREATE | WS_POPUP | \r
+    WS_VISIBLE | WS_CAPTION | WS_SYSMENU\r
+EXSTYLE WS_EX_TOOLWINDOW\r
+CAPTION "Unreal 3.0 Configuration"\r
+FONT 8, "MS Sans Serif"\r
+BEGIN\r
+    LTEXT           "Current Local Users:",TXT_LOCALUSERS,110,5,65,8\r
+    LTEXT           "Max:",TXT_LOCALMAX,224,5,16,8\r
+    LTEXT           "Current Global Users:",TXT_GLOBALUSERS,115,100,68,8\r
+    LTEXT           "Max:",TXT_GLOBALMAX,224,100,16,8\r
+    LTEXT           "Inv:",TXT_INV,280,5,13,8\r
+    LTEXT           "IRC servers networked:",TXT_IRCSERVERS,110,15,75,8\r
+    LTEXT           "IRC operator(s) online:",TXT_IRCOPS,115,110,71,8\r
+    LTEXT           "Local clients",TXT_MYUSERS,110,25,40,8\r
+    LTEXT           "Local server links",TXT_MYSERVERS,110,34,56,8\r
+    LTEXT           "Channels formed:",TXT_CHANNELS,115,120,56,8\r
+    GROUPBOX        "Global",IDC_STATIC,110,90,175,55\r
+    RTEXT           "",EDIT_GLOBALMAX,245,100,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_GLOBAL,190,100,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_CHANNELS,190,120,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_IRCOPS,190,110,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_CLOCAL,190,5,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_CLOCALMAX,245,5,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_INV,301,5,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_IRCSERVERS,190,15,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_MYUSERS,190,25,25,8,SS_SUNKEN\r
+    RTEXT           "",EDIT_MYSERVERS,190,34,25,8,SS_SUNKEN\r
+    LTEXT           "Maximum Possible users",TXT_LOCALMAXPOS,223,15,77,8\r
+    RTEXT           "",EDIT_LOCALMAXPOS,301,16,25,8,SS_SUNKEN\r
+END\r
+\r
+ABOUTBOX DIALOG DISCARDABLE  0, 0, 294, 159\r
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU\r
+CAPTION "UnrealIRCd About Stuff"\r
+FONT 9, "Lucida Console"\r
+BEGIN\r
+    DEFPUSHBUTTON   "&OK",IDOK,122,143,50,14\r
+    EDITTEXT        IDC_INFOTEXT,0,0,294,140,ES_MULTILINE | ES_AUTOVSCROLL | \r
+                    ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | \r
+                    WS_VSCROLL\r
+END\r
+\r
+\r
+#ifndef _MAC\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+1 VERSIONINFO\r
+ FILEVERSION 3,0,4,2\r
+ PRODUCTVERSION 3,0,0,0\r
+ FILEFLAGSMASK 0x3fL\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x29L\r
+#else\r
+ FILEFLAGS 0x28L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x1L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "080904b0"\r
+        BEGIN\r
+            VALUE "Comments", "Its for windows ->.. dont expect it to be stable :->\0"\r
+            VALUE "CompanyName", "UnrealIRCD\0"\r
+            VALUE "FileDescription", "The Unreal Chat Server for Windows\0"\r
+            VALUE "FileVersion", "3.0.04.02\0"\r
+            VALUE "InternalName", "Unreal-win32\0"\r
+            VALUE "LegalCopyright", "Copyright Â© 2000 Unreal Developer Network\0"\r
+            VALUE "LegalTrademarks", "All rights reserved\0"\r
+            VALUE "OriginalFilename", "wircd.exe\0"\r
+            VALUE "PrivateBuild", "3.0.04.02\0"\r
+            VALUE "ProductName", "The Unreal Chat Server for Windows\0"\r
+            VALUE "ProductVersion", "3.0 Release\0"\r
+            VALUE "SpecialBuild", "For Windows\0"\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x809, 1200\r
+    END\r
+END\r
+\r
+#endif    // !_MAC\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// DESIGNINFO\r
+//\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+GUIDELINES DESIGNINFO DISCARDABLE \r
+BEGIN\r
+    "DLG_IRCDCONF", DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 287\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 152\r
+    END\r
+\r
+    "WIRCD", DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 233\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 119\r
+    END\r
+\r
+    "DLG_STATS", DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 352\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 256\r
+    END\r
+\r
+    "ABOUTBOX", DIALOG\r
+    BEGIN\r
+        LEFTMARGIN, 7\r
+        RIGHTMARGIN, 287\r
+        TOPMARGIN, 7\r
+        BOTTOMMARGIN, 152\r
+    END\r
+END\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Icon\r
+//\r
+\r
+// Icon with lowest ID value placed first to ensure application icon\r
+// remains consistent on all systems.\r
+sysicon                 ICON    DISCARDABLE     "ico00001.ico"\r
+WIRCD                   ICON    DISCARDABLE     "icon1.ico"\r
+sysicondisabled         ICON    DISCARDABLE     "sysicon1.ico"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Bitmap\r
+//\r
+\r
+OBM_WIRCD               BITMAP  DISCARDABLE     "unrealircd.bmp"\r
+OBM_BAR                 BITMAP  DISCARDABLE     "bar.bmp"\r
+#endif    // English (U.K.) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/src/win32/Win32New.h b/src/win32/Win32New.h
new file mode 100644 (file)
index 0000000..a6885c9
--- /dev/null
@@ -0,0 +1,129 @@
+typedef struct {\r
+       unsigned int CurrLoclUsers;\r
+       unsigned int CurrGlobUsers;\r
+       unsigned int MaxLoclUsers;\r
+       unsigned int MaxGlobUsers;\r
+       unsigned int NumUsers; // Eh ??\r
+       unsigned int Invisible;\r
+       unsigned int connections;\r
+       unsigned int NumIRCops;\r
+       unsigned int LocalClients; // Eh??\r
+       unsigned int LocalServers;\r
+       unsigned int chans;\r
+       unsigned int Servers;\r
+\r
+       /* ToBe Added\r
+       int TSsync stuff .... dont know what yet\r
+       */\r
+} WINSTATS, *pWINSTATS;\r
+\r
+typedef struct RichLine\r
+{\r
+       BYTE    *Data;\r
+       WORD    Len;\r
+       struct RichLine *Prev, *Next;\r
+} aRichLine;\r
+\r
+typedef struct AllRichLines\r
+       {\r
+       aRichLine *First, *Current;\r
+       int NumLines;\r
+       } INFRICHLINE;\r
+\r
+\r
+\r
+/**********************************************************\r
+********** Graphy Header (C) David Flynn 2000 ************/\r
+\r
+#define SS_NORM                0x0001  // spincube window styles\r
+#define SS_SLOW             0x0002\r
+#define SS_FAST             0x0003\r
+\r
+#define CCHSTYLE                20  // size of style string, i.e. "SS_ERASE"\r
+\r
+#define NUM_GRAPH_STYLES     2\r
+\r
+\r
+#define GRAPH_EXTRA          4   // number of extra bytes for spincube class\r
+\r
+\r
+#define IDS_REGCLASSFAIL      16\r
+#define IDS_UNREGFAIL         17\r
+#define IDS_DLGBOXFAIL        18\r
+#define IDS_ALLOCFAIL         19\r
+#define IDS_CREATEDCFAIL      20\r
+#define IDS_CREATEBITMAPFAIL  21\r
+#define GWL_GRAPHDATA        0   \r
+// offset of control's instance data\r
+\r
+#define GRAPHCLASS           "Graph"\r
+#define GRAPHDESCRIPTION     "An animated control"\r
+#define GRAPHDEFAULTTEXT     ":-)"\r
+#define GRAPH_EVENT                            1\r
+#define UPDATE_TIMER                   2\r
+#define UPDATE_INTERVAL                        /*60000*/ 30\r
+\r
+typedef struct\r
+{\r
+  HDC      hdcCompat;               // the DC that will contain our off-screen\r
+                                    //   image\r
+  //HBITMAP  hbmSave;                 // Save previous selected bitmap\r
+  //HBITMAP  hbmCompat;               // The bitmap that will contain the actual\r
+                                    //   image, i.e. we will always do our\r
+                                    //   drawing on this bmp & then blt the\r
+                                    //   result to the screen.\r
+  BOOL InitDraw;       //Did we draw once yet?\r
+  int width;            // Width of monitor (= size of history)\r
+  int cpupointer;       // pointer to cpu history\r
+\r
+  HDC DCBack;\r
+  HBITMAP BMBack;\r
+  HBITMAP OldBack;\r
+  HDC DCDblBuff;\r
+  HBITMAP BMDblBuff;\r
+  HBITMAP OldDblBuff;\r
+\r
+  HBITMAP      Background;\r
+  HBITMAP      CPUMap;\r
+  SIZE WindowSize;\r
+  BOOL Border;\r
+  BOOL Grid;\r
+\r
+  COLORREF BorderColor;\r
+  COLORREF BackColor;\r
+  COLORREF GridColor;\r
+  COLORREF CPUColor;\r
+  COLORREF AVGCPUColor;\r
+  COLORREF MEMColor;\r
+  char cpuhistory[2048];\r
+  char BackgroundPath[256];\r
+char CPUMapPath[256];\r
+  int      iOptions;                // Contains the current options for this\r
+                                    //   ctrl, i.e. erase background.\r
+\r
+} GRAPHINFO, *PGRAPHINFO;\r
+\r
+\r
+\r
+/******************************************************************************\\r
+*                                FUNCTION PROTOTYPES\r
+\******************************************************************************/\r
+\r
+LRESULT CALLBACK GraphWndProc    (HWND,  UINT,  WPARAM, LPARAM);\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+DWORD Reserved,dataType,dataLen=8192;\r
+\r
+\r
+\r
+// DoubleBuffer Stuff\r
+void DrawMonitor(HDC hdc, RECT r,HWND);\r
+\r
+\r
+void CreateDblBuff(HWND);\r
+void FreeDblBuff(void);\r
diff --git a/src/win32/bar.bmp b/src/win32/bar.bmp
new file mode 100644 (file)
index 0000000..7e009cc
Binary files /dev/null and b/src/win32/bar.bmp differ
diff --git a/src/win32/ico00001.ico b/src/win32/ico00001.ico
new file mode 100644 (file)
index 0000000..d1a70e5
Binary files /dev/null and b/src/win32/ico00001.ico differ
diff --git a/src/win32/resource.h b/src/win32/resource.h
new file mode 100644 (file)
index 0000000..1b8c60b
--- /dev/null
@@ -0,0 +1,101 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Developer Studio generated include file.\r
+// Used by Win32GUI.rc\r
+//\r
+#define sysicon                         114\r
+#define sysicondisabled                 115\r
+#define IDC_USERID                      1051\r
+#define IDC_REALNAME                    1052\r
+#define IDC_PNICK                       1053\r
+#define IDC_ANICK                       1054\r
+#define IDC_SERVERLIST                  1057\r
+#define IDC_NEWSERVER                   1058\r
+#define IDC_EDITSERVER                  1059\r
+#define IDC_IRCDCONF                    1059\r
+#define IDC_DELSERVER                   1060\r
+#define IDC_SHOW_GLOBOPS                1060\r
+#define IDC_SHOW_WALLOPS                1061\r
+#define IDC_SHOW_HELPOPS                1062\r
+#define IDC_SHOW_SERVNOTICE             1063\r
+#define IDC_INFOTEXT                    1063\r
+#define IDC_INFOTEXT2                   1063\r
+#define IDOK2                           1065\r
+#define IDC_RICHEDIT1                   1070\r
+#define TXT_LOCALUSERS                  1100\r
+#define TXT_LOCALMAX                    1101\r
+#define TXT_GLOBALUSERS                 1102\r
+#define TXT_GLOBALMAX                   1103\r
+#define TXT_IRCSERVERS                  1104\r
+#define TXT_IRCOPS                      1105\r
+#define TXT_NONINV                      1106\r
+#define TXT_LOCALMAXPOS                 1106\r
+#define TXT_INV                         1107\r
+#define TXT_MYUSERS                     1108\r
+#define TXT_MYSERVERS                   1109\r
+#define TXT_CHANNELS                    1110\r
+#define TXT_WHEN                        1111\r
+#define TXT_VERSION                     1112\r
+#define TXT_PORT                        1200\r
+#define TXT_CRINFO                      1301\r
+#define TXT_CRINFO1                     1302\r
+#define TXT_CRINFO2                     1303\r
+#define TXT_CRINFO3                     1304\r
+#define TXT_CRINFO4                     1305\r
+#define EDIT_CLOCAL                     1400\r
+#define EDIT_CLOCALMAX                  1401\r
+#define EDIT_GLOBAL                     1402\r
+#define EDIT_GLOBALMAX                  1403\r
+#define EDIT_IRCSERVERS                 1404\r
+#define EDIT_IRCOPS                     1405\r
+#define EDIT_NONINV                     1406\r
+#define EDIT_LOCALMAXPOS                1406\r
+#define EDIT_INV                        1407\r
+#define EDIT_MYUSERS                    1408\r
+#define EDIT_MYSERVERS                  1409\r
+#define EDIT_CHANNELS                   1410\r
+#define IDM_OPEN                        40001\r
+#define IDM_SAVE                        40002\r
+#define IDM_SAVEAS                      40003\r
+#define IDM_EXIT                        40004\r
+#define IDM_ABOUT                       40005\r
+#define IDM_WINDOWCHILD                 40006\r
+#define IDM_REHASH                      40007\r
+#define IDM_OPTIONS                     40008\r
+#define IDM_CREDITS                     40009\r
+#define IDM_DF                          40010\r
+#define IDM_LICENSE                     40011\r
+#define MM_WINDEBUGLEVEL_0              40016\r
+#define MM_WINDEBUGLEVEL_1              40017\r
+#define MM_WINDEBUGLEVEL_2              40018\r
+#define MM_WINDEBUGLEVEL_FLUSH          40019\r
+#define IDM_DBGOFF                      41099\r
+#define IDM_DBGFATAL                    41100\r
+#define IDM_DBGERROR                    41101\r
+#define IDM_DBGNOTICE                   41103\r
+#define IDM_DBGDNS                      41104\r
+#define IDM_DBGINFO                     41105\r
+#define IDM_DBGNUM                      41106\r
+#define IDM_DBGSEND                     41107\r
+#define IDM_DBGDEBUG                    41108\r
+#define IDM_DBGMALLOC                   41109\r
+#define IDM_DBGLIST                     41110\r
+#define IDM_POPUP                       50000\r
+#define IDM_IRCDRULES                   65530\r
+#define IDM_IRCDMOTD                    65531\r
+#define IDC_VERSION                     65532\r
+#define IDC_VERSION2                    65532\r
+#define IDC_STATIC                      -1\r
+#define IDM_SETUP                       65535\r
+#define IDM_IRCDCONF                    65535\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NO_MFC                     1\r
+#define _APS_NEXT_RESOURCE_VALUE        115\r
+#define _APS_NEXT_COMMAND_VALUE         40020\r
+#define _APS_NEXT_CONTROL_VALUE         1072\r
+#define _APS_NEXT_SYMED_VALUE           104\r
+#endif\r
+#endif\r
diff --git a/src/win32/sysicon1.ico b/src/win32/sysicon1.ico
new file mode 100644 (file)
index 0000000..a7d66b5
Binary files /dev/null and b/src/win32/sysicon1.ico differ
diff --git a/src/win32/unrealircd.bmp.gz b/src/win32/unrealircd.bmp.gz
new file mode 100644 (file)
index 0000000..a429626
Binary files /dev/null and b/src/win32/unrealircd.bmp.gz differ
diff --git a/src/win32/version.c b/src/win32/version.c
new file mode 100644 (file)
index 0000000..8244fd8
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *   IRC - Internet Relay Chat, ircd/version.c
+ *   Copyright (C) 1990 Chelsea Ashley Dyerman
+ *
+ *   This program is free software; you can 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.
+ * 
+ *   : version.c.SH,v 1.8 2000/02/27 11:53:16 stskeeps Exp $
+ */
+
+/*
+ * This file is generated by version.c.SH. Any changes made will go away.
+ */
+
+#include "struct.h"
+#include "version.h"
+#include "license.h"
+
+char *generation = "1";
+char *creation = "Sun Feb 27 2000 at 11:55:29 GMT";
+#define IRCDTOTALVERSION BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9
+char *version = IRCDTOTALVERSION;
+
+/* moved to s_serv.c */
+char *infotext[] = 
+{ 0 };
+
+char *unrealcredits[] =
+{
+       "-=-=-=-=-=-=-=-=-=-= [ " IRCDTOTALVERSION " Credits ] -=-=-=-=-",
+       "The people on this list is people who have helped up through",
+       "the development of UnrealIRCd. The Unreal Team would like to thank",
+       "those people by listing them here:",
+       "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=",
+       "              \2\37The UnrealIRCd Team would like to thank:\2\37",
+       "Nutcais (Phil Hawkins)",
+       "- the original shell for Unreal development, useful comments,",
+       "  being a real IRCbrother for me (Stskeeps) :), learning me a lot",
+       "  about IRC stuff, getting me more and more into IRCd business",
+       "  thanks for the *.tspre.org domain as well :)",
+       "",
+       "\37Local Irelands (http://www.local.ie)\37",
+       "- Thanks for sponsoring UnrealIRCd, test facilities,",
+       "  supporting UnrealIRCd, many new ideas, thanks for making",
+       "  Unreal what it is today:)",
+       "Mick and Sp^",
+       "- Amiga port of Unreal (UnrealIRCd/Amiga), continually strange",
+       "  comments on #UnrealIRCd, being great supporters of Unreal",
+       "  and following Unreal development all the way",
+       "DrBin (Dave) drbin@tspre.org",
+       "- Recoded & made the new UnrealIRCd/32 code, support,"
+       "  finding bugs, and tonnes of other stuff:)",
+       "{X} (Laurie) x@tspre.org",
+       "- Making the main code/design of UnrealIRCd/32 gui",
+       "  bugfounds, etc",
+       "SourceForge.net",
+       "- Good hosting, CVS hosting, FTP etc etc:) - thanks for",
+       "  supporting opensource projects",
+       "",
+       "                         \37Donations to Unreal:\37",
+       "BlueFlame^",
+       " - the first UnrealIRCd donation :)",
+       "   (yes your name can be here too;)",
+       "",
+       "              \37These people have helped alpha/betatesting\37",
+       "zshack, Headbang, Mick, Sp^, WonderWal, bomb, BullFrog, JacobD,",
+       "SirDeath, l33, EiniD, uo, RevPsych and the subgenius.net network,",
+       "^RavenX^, Mich[a]el, {X}, Fish, Shmad, Killer, BrainSCAN, RevNull,",
+       "GoNiS (irc.coreplex.org), Mikey, DrBin, and others",
+       "",
+       "",
+        "                   \2\37Stskeeps would like to thank:\2\37", 
+       "Morrigan             Julie Frederiksen",
+       " - Being a friend, thinking I was cute, uhm laying on a recycle",
+       "   thing.. 'Its the wrong recycle box Julie!', 'you got too cold",
+       "   hands *freezing*', etc ;)",
+       "DJBoxy       *unknown*                *unknown*",
+       " - For getting me up from #wIRCd bringing me to Mp3fansNet and",
+       "   after we linked to Global-IRC.net - and made people choose me",
+       "   as netadmin/ircd coder - Thanx!",
+       "TC           Tabita Clausen           (reallife)",
+       " - Making me smile of my life, talking with me, being a friend",
+       "   always got a pen sharpener when needed=/, accepting some",
+       "   wierdnesses from my side, going to the cinema with me",
+       "   and many other stuff. You'll always be in my heart,",
+       "   sorry for all the things I did or maybe didn't",
+       "   love you :(",
+       "KUFO          John MacKenzie",
+       " - Support, helping me always with getting through my life",
+       "   shells, etc etc ;)",
+       "Sporty_McFly  Cedric",
+       " - Comments, helping me when I got problems with my life and so on",
+        "   *toh* to him - Thanks!",
+       "Del_Monte     K. Hawkes               k.hawkes@zombies.force9.net",
+       " - Is just trying to put the lamer side of things across :cP",
+       "   No. I saw 2 moos. - Well having to input in seconds",
+       "   is fine if you're real quick at maths - but if not - it's a PAIN",
+       "   - Comments, bugfixes, moral support etc.;)",
+       "Skywalker     Chris Morley            skywalker@irc.ru.ac.za",
+       " - Helping me start up ROXnet at first (which brought me",
+       "   into IRCd business.. + Numerous kicks /Kills akills and alike;)",
+       "zero9000      Kevin Alford",
+       " - UnrealIRCd logo, graphics, null desu ;), ideas etc.",
+        "                   \2\37codemastr would like to thank:\2\37", 
+       "",                     
+       "                            \2\37Also thanks to:\2\37",
+       "Enforcer, Andy Church, Mick, Sp^, ShadowMastr, Almaris",
+       "}{, Erik/Dr|zzt, Hedge, Kyle, MissKel, jfc, Fish, kore, Syndicate, Bagge,",
+       "#Coder-Com@Undernet, ^NeVeR^, flygirl^, DannyM, JuliuZ, wah-wah^, Lisa,",
+       "Melisa, NonMortal, Andryan, TomaHawk, Lushes, Skywalker, Merlin, Sporty_McFly,", 
+       "zero9000, #wIRCd@DALnet, comstud, dog3, Dianora, Isomer, and others who arent listed here:)",
+       "",
+       "------------------------------------------------------",
+       "Unreal 3.0 and up is dedicated to Morrigan - Julie Frederiksen",
+       "- a girl who have helped me through anything in my life, hugging",
+       "me at the right times, a definate dedication. Thanks for the kisses",
+       "long phonetalks, waste of my mobilephone ;), crying together",
+       "and making life go on for us both. I will never forget you",
+       "never leave you, love ya forever",
+       "------------------------------------------------------",
+       "This IRCd is dedicated to the love that has always been",
+       "and will always be there - Thanks to the girls & friends that kept me up",
+       "when I was down",
+       0
+};
+char *unrealcreditsold[] = 
+{
+       "------------------------------------------------------",
+       "Unreal 3.0 and up is dedicated to Morrigan - Julie Frederiksen",
+       "- a girl who have helped me through anything in my life, hugging",
+       "me at the right times, a definate dedication. Thanks for the kisses",
+       "long phonetalks, waste of my mobilephone ;), crying together",
+       "and making life go on for us both. I will never forget you",
+       "never leave you, love ya forever",
+       "------------------------------------------------------",
+       "This IRCd is dedicated to the love that has always been",
+       "and will always be there - Thanks to the girls & friends that kept me up",
+       "when I was down",
+       0
+};
+
+char *dalinfotext[] =
+    {
+        "IRC --",
+        "Based on the original code written by Jarkko Oikarinen",
+        "Copyright 1988, 1989, 1990, 1991 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.",
+       "- Any name/comment should never be changed except by the one who made it -",
+       "",
+       "UnrealIRCd contains code developed by:",
+       "Potvin       Chris Wolkowski          potvin@acestar.org",
+       "RogerY       Roger Y.                 rogery@austnet.org",
+       "GZ                                    gz@starchat.net",
+       "binary",
+       "",
+       "",
+       "The following people have helped in making the DALnet ircd",
+        "that is based on irc2.8.21.mu3.2 :",
+        "",
+        "Russell      Russell Miller           russell@dal.net",
+        "Donwulff     Jukka Santala            donwulff@dal.net",
+        "Aetobatus    Michael Sawyer           aetobatus@dal.net",
+        "Dalvenjah    Sven Nielsen             dalvenjah@dal.net",
+        "Skandranon   Michael Graff            explorer@flame.org",
+        "Barubary     -                        barubary@dal.net",
+        "white_dragon Chip Norkus              wd@dal.net",
+        "DuffJ        Dafydd James             duffj@dal.net",
+        "taz          David Kopstain           taz@dal.net",
+        "NikB         Nik Bougalis             nikb@dal.net",
+        "Rakarra      -                        rakarra@dal.net",
+        "DarkRot      Lucas Madar              darkrot@dal.net",
+        "Studded      -                        studded@dal.net",
+        "JoelKatz     David Schwartz           joelkatz@dal.net",
+        "",
+        "This product includes software developed by Colin Plumb.",
+        "",
+        "The following persons have made many changes and enhancements to the",
+        "code and still know how IRC really works if you have questions about it:",
+        "",
+        "Run          Carlo Kid                carlo@runaway.xs4all.nl",
+        "Avalon       Darren Reed              avalon@coombs.anu.edu.au",
+        "msa          Markku Savela            Markku.Savela@vtt.fi",
+        "Wumpus       Greg Lindahl             gl8f@virginia.edu",
+        "WiZ          Jarkko Oikarinen         jto@tolsun.oulu.fi",
+        "Argv         Armin Gruner Armin.Gruner@Informatik.TU-Muenchen.de",
+        "",
+        "Thanks to the following people for help with preparing 2.8",
+        "",
+        "phone        Matthew Green            phone@coombs.anu.edu.au",
+        "Sodapop      Chuck Kane               ckane@ece.uiuc.edu",
+        "Skygod       Matt Lyle                matt@oc.com",
+        "Vesa         Vesa Ruokonen            ruokonen@lut.fi",
+        "Nap          Nicolas PIOCH pioch@poly.polytechnique.fr",
+        "",
+        "Those who helped in prior versions and continue to be helpful:",
+        "",
+        "Stellan Klebom      Dan Goodwin         Mike Bolotski",
+        "Ian Frechette       Markku Jarvinen     Kimmo Suominen",
+        "Jeff Trim           Vijay Subramaniam   Karl Kleinpaste",
+        "Bill Wisner         Tom Davis           Hugo Calendar",
+        "Tom Hopkins         Stephen van den Berg",
+        "Bo Adler            Michael Sandrof     Jon Solomon",
+        "Jan Peterson        Helen Rose          Paul Graham",
+        "",
+        "Thanks also goes to those persons not mentioned here who have added",
+        "their advice, opinions, and code to IRC.",
+        "Thanks also to those who provide the kind sys admins who let me and",
+        "others continue to develop IRC.",
+        "",
+
+        0
+    };
diff --git a/virtual-ip b/virtual-ip
new file mode 100644 (file)
index 0000000..4fc8750
--- /dev/null
@@ -0,0 +1,15 @@
+################################
+####### Virtual IP Help ########  
+################################
+
+It's very simple to setup a virtual ip with this ircd.
+In your ircd.conf your M:line should be: 
+M:Servername.com:Virtual-IP:Server Info:6667
+example:
+M:IRC.SERVER.COM:206.163.45.108:IRC Server:6667
+
+Also in ircd.conf, add P:lines like: P:Virtual-IP:*:*:Port
+example:
+P:206.163.211.108:*:*:6668
+
+[ $Id$ ]
diff --git a/win32 b/win32
new file mode 100644 (file)
index 0000000..742c9df
--- /dev/null
+++ b/win32
@@ -0,0 +1,9 @@
+To do win32 compiling
+- Copy include/win32/setup.h to include/
+- Copy makefile.win32 to Makefile
+- Modify makefile to suit you
+- Modify config.h to suit you 
+- Make settings.h to suit you
+you'll need to unzip src/wircd/unrealircd.bmp.gz as well using winzip
+
+UnrealIRCd is not absolute to compile on Win32 yet