--- /dev/null
+#########################################################################
+# Changes in Serene5.27 (see doc/CHANGES.old for older changes) #
+#########################################################################
+o: Changed StarChat references to Serene
+
+#########################################################################
+# Changes in Serene5.28 (see doc/CHANGES.old for older changes) #
+#########################################################################
+o: /whowas now shows the actual server to normal users.
+o: /whois shows the connection arguments the client used to connect to
+ IRC operators.
+o: Length for QUIT messages increased to 180 characters (up from 120).
+o: Forbid DCC SEND and CHAT functions for unregistered nicks.
--- /dev/null
+#!/bin/sh
+
+# Copyright 1996,1997,1998 Michael Graff <explorer@flame.org>
+# You may distribute this file freely providing this notice
+# remains intact.
+#
+# Modified August 1999 by GZ <gz@starchat.net>
+# InnerFIRE <innerfire@starchat.net>
+
+IRCD_VERSION="Serene5.28"
+CONF_DATE=`date`
+LAST_VERSION="Serene5.27"
+#
+trap "" 13 14 15
+MV=mv
+RM=rm
+SETUP=include/setup.h
+OPTIONS_H=include/options.h
+OPTIONS=Options
+MAKEINST=.install
+AUTO_CONFIG=""
+#
+GLIBCCHECK=undef
+STDLIBH=undef
+STDDEFH=undef
+SYSSYSLOGH=undef
+PARAMH=undef
+UNISTDH=undef
+STRINGH=undef
+STRINGSH=undef
+STRCASECMP=undef
+RUSAGEH=undef
+HINDEX=undef
+STRERROR=undef
+STRTOKEN=define
+STRTOK=define
+INETADDR=define
+INETNTOA=define
+INETNETOF=define
+GETTIMEOFDAY=undef
+LRAND48=undef
+STRTOUL=undef
+LOCALD=define
+NEEDSKIPNAME=""
+CCPATH=''
+HAVE_BZERO=undef
+GETRUSAGE_2=undef
+TIMES_2=undef
+POSIX_NBLOCK=undef
+BSD_NBLOCK=undef
+POSIX_SIGNAL=undef
+BSD_SIGNAL=undef
+TMP=/tmp/.Configtmp$$.c
+EXEC=/tmp/.Configtmp$$
+PLATE=/tmp/.ConPlate$$
+c=''
+n=''
+#
+# Some reasonable defaults
+#
+DEFOPT="-O"
+DEFCFLAGS="$DEFOPT"
+DEFLIBS="none"
+OSNAME="Could not determine Operating System"
+#
+CONTACT_URL="http://www.serenity-irc.net/connect.html"
+CONTACT_EMAIL=""
+SERVICES_NAME="Services.Serenity-IRC.Net"
+KLINE_ADDRESS=""
+ZIP_LINKS="1"
+DPATH="$HOME/ircd"
+SPATH="$HOME/ircd/ircd"
+HUB=""
+CRYPT_OPER_PASSWORD="1"
+CRYPT_ILINE_PASSWORD=$CRYPT_OPER_PASSWORD
+MAXCONNECTIONS="1024"
+
+#
+# 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
+
+case $# in
+ 1 )
+ case "z${1}" in
+ z--help | z-h )
+ echo " -n Use the Options file from a previous setup"
+ echo " "
+ echo " --help display this help and exit"
+ echo " --version output version information and exit"
+ echo " "
+ exit 0 ;;
+ z--version )
+ echo "Config $IRCD_VERSION"; exit 0 ;;
+ z-n )
+ if [ "$LAST_VERSION" != "$IRCD_VERSION" ] ; then
+ echo "You specified the no-questions-asked configure, but the version"
+ echo "of Config which created your Options 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 ;;
+ * ) ;;
+ esac
+ ;;
+ * ) ;;
+esac
+
+if [ "$LAST_VERSION" != "$IRCD_VERSION" ] ; then
+ if [ -r CHANGES ] ; then
+ more CHANGES
+ echo $n "[Enter to begin]"
+ read cc
+ fi
+fi
+
+clear
+
+#
+# Take a wild stab at the OS, and take reasonable defaults for each
+#
+# Include zlib as default for server compression,
+# if they don't want it, they have a backspace key.
+# patched: 5/30/00 Paul de Regt [Ax0n] (deregt@accessnw.net)
+
+OS=`uname -a`
+case "$OS" in
+ *NetBSD*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lcrypt -lz"
+ OSNAME="NetBSD"
+ ;;
+ *FreeBSD*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lcrypt -lz"
+ OSNAME="FreeBSD"
+ ;;
+ *SCO_SV*)
+ DEFCFLAGS="$DEFOPT -DSCOUNIX"
+ DEFLIBS="-lsocket -lz"
+ OSNAME="SCO Openserver"
+ NEEDSKIPNAME="Yep"
+ ;;
+ *OSF1*alpha*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lz"
+ OSNAME="OSF/1 or Digital Unix"
+ ;;
+ *SunOS*4.*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lz"
+ OSNAME="SunOS 4.x"
+ LOCALD=undef
+ ;;
+ *SunOS*5.*)
+ DEFCFLAGS="$DEFOPT -DSOL20"
+ DEFLIBS="-lsocket -lnsl -lresolv -lz"
+ OSNAME="Solaris 2.x (or SunOS 5.x)"
+ LOCALD=undef
+ ;;
+ *Darwin*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lz"
+ OSNAME="Darwin"
+ ;;
+ *Linux*)
+# New, cleaner detection code. -8/15/99 Sean-Paul Rees (sean@dreamfire.net)
+ cat > $TMP << __EOF__
+#include <stdio.h>
+main()
+{
+ #ifdef __GLIBC__
+ printf("%d_%d\n", __GLIBC__, __GLIBC_MINOR__);
+ #else
+ printf("0\n");
+ #endif
+
+ exit(0);
+}
+__EOF__
+#
+# Yes, I know we don't have $CCPATH and $XCFLAGS and such set up yet,
+# but below should work on just about any Linux system
+#
+# Glibc version now correctly detected (major.minor)
+# patched: 8/15/99 Sean-Paul Rees (sean@dreamfire.net)
+#
+ cc $TMP -o $EXEC >/dev/null 2>&1
+ GLIBCVERS=`$EXEC`
+
+ case $GLIBCVERS in
+ 0) # This is Linux without Glibc.
+ OSNAME="Linux"
+ DEFLIBS="-lz"
+ ;;
+ 2*) # Linux with Glibc 2.x
+ OSNAME="Linux (Glibc $GLIBCVERS)"
+ DEFLIBS="-lcrypt -lresolv -lz"
+ ;;
+ esac
+
+ DEFCFLAGS="$DEFOPT"
+ ;;
+ *HP-UX*.09.*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lz"
+ OSNAME="HPUX 9.x"
+ ;;
+ *HP-UX*.10.*)
+ DEFCFLAGS="$DEFOPT"
+ DEFLIBS="-lz"
+ OSNAME="HPUX 10.x"
+ ;;
+esac
+
+echo " "
+echo Operating System: $OSNAME
+echo " "
+
+# Create Makefile if it doesn't exist...
+if [ ! -f Makefile ] ; then
+ cp Makefile.dist Makefile
+fi
+cat << __EOF__
+Welcome to autoconfigure for the Serenity-IRC server version $IRCD_VERSION.
+
+Config will generate a system-specific $SETUP file, a top
+level Makefile 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?"
+ 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 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 /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 $n "Searching for bcopy/bzero/bcmp...$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 "located bcopy/bzero/bcmp"
+ HAVE_BZERO=define
+else
+ echo "No bcopy/bzero/bcmp found"
+ HAVE_BZERO=undef
+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 "gettimeofday found"
+ GETTIMEOFDAY=define
+else
+ echo "No gettimeofday. Trying lrand48."
+cat > $TMP <<__EOF__
+main()
+{
+ int a;
+ a=lrand48();
+}
+__EOF__
+ $COMP >/dev/null 2>&1
+ if [ $? -eq 0 ] ; then
+ echo "lrand48 found"
+ LRAND48=define
+ fi
+fi
+#
+# check for non-blocking fd style available..
+#
+echo 'Checking for POSIX/BSD/SYSV'
+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
+ POSIX_NBLOCK=define
+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
+ BSD_NBLOCK=define
+ 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 'ERROR: FIONBIO not found! No option found!'
+ else
+ echo "Using SysV blocking"
+ fi
+ fi
+fi
+$RM -f $TMP $PLATE $EXEC
+echo "Blocking selected: $BLOCK";
+#
+# reliable signals ?
+#
+echo 'Looking for reliable signals...'
+echo "Checking 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 "'action from POSIX found"
+ POSIX_SIGNAL=define
+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 "No, but you have...$c"
+ $COMP >/dev/null 2>&1
+ $EXEC
+ if [ $? -eq 0 ] ; then
+ echo 'reliable signals found'
+ BSD_SIGNAL=define
+ else
+ echo "unreliable SYSV detected"
+ fi
+fi
+$RM -f $EXEC $TMP
+#
+echo 'Now those strings libraries...'
+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 "you have index()!"
+ HINDEX=define
+else
+ echo "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
+ GETRUSAGE_2=define
+ 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_2=define
+ echo "times()"
+ else
+ echo "couldn't get either ?!"
+ fi
+fi
+#
+# what do we need that isn't here already ?
+#
+echo -n "Looking for strcasecmp..."
+cat > $TMP <<__EOF__
+#$STRINGH STRINGH
+#$STRINGSH STRINGSH
+#ifdef STRINGH
+#include <string.h>
+#endif
+#ifdef STRINGSH
+#include <strings.h>
+#endif
+main()
+{
+ char *s = strcasecmp('a', 'a');
+ exit(0);
+}
+__EOF__
+$COMP >/dev/null 2>&1
+if [ $? -eq 0 ] ; then
+ echo "strcasecmp found"
+ STRCASECMP=define
+else
+ echo "No strcasecmp found"
+fi
+#$RM -f $EXEC $TMP
+echo "Checking for additional components..."
+echo $n "Searching...$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"
+else
+ STRERROR=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
+# dn_skipname passes the small test but won't resolve when ircd is linked.
+# Hmmm...
+if [ $? -ne 0 -o "$OSNAME" = "Linux RedHat 5.0" -o -n "$NEEDSKIPNAME" -o "$GLIBCCHECK" = "define" ] ; 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=res_init.o@" Makefile > Makefile.tmp
+ cp Makefile.tmp Makefile
+ $RM -f Makefile.tmp
+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"
+ STRTOKEN=undef
+else
+ $EXEC
+ if [ $? -ne 0 ] ; then
+ echo $n " strtoken$c"
+ STRTOKEN=undef
+ 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[] = "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"
+ STRTOK=undef
+else
+ $EXEC
+ if [ $? -ne 0 ] ; then
+ echo $n " strtok$c"
+ STRTOK=undef
+ 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"
+ INETADDR=undef
+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"
+ INETNETOF=undef
+fi
+$RM -f $EXEC $TMP
+echo " "
+
+$RM -f $EXEC $TMP $PLATE
+cat > $SETUP <<__EOF__
+#define IRCD_VERSION "$IRCD_VERSION"
+#$PARAMH HAVE_PARAM_H
+#$UNISTDH HAVE_UNISTD_H
+#$STRINGH HAVE_STRING_H
+#$STRINGSH HAVE_STRINGS_H
+#$STDLIBH HAVE_STDLIB_H
+#$STDDEFH HAVE_STDDEF_H
+#$SYSSYSLOGH HAVE_SYSSYSLOG_H
+#$HINDEX HAVE_INDEX
+#$STRERROR HAVE_STRERROR
+#$STRTOKEN HAVE_STRTOKEN
+#$STRTOK HAVE_STRTOK
+#$INETADDR HAVE_INET_ADDR
+#$INETNTOA HAVE_INET_NTOA
+#$INETNETOF HAVE_INET_NETOF
+#$GETTIMEOFDAY GETTIMEOFDAY
+#$LRAND48 HAVE_LRAND48
+#$STRCASECMP HAVE_STRCASECMP
+#$HAVE_BZERO HAVE_BZERO
+#$POSIX_NBLOCK HAVE_POSIX_NBLOCK
+#$BSD_NBLOCK HAVE_BSD_NBLOCK
+#$POSIX_SIGNAL HAVE_POSIX_SIGNALS
+#$BSD_SIGNAL HAVE_BSD_SIGNALS
+#$TIMES_2 HAVE_TIMES_2
+#$GETRUSAGE_2 HAVE_GETRUSAGE_2
+__EOF__
+
+if [ $? -ne 0 -o "$OSNAME" = "Darwin" ] ; then
+echo "#define __Darwin__" >> $SETUP
+fi
+
+#
+# Now, get site specific options.
+#
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+ FOO="$KLINE_ADDRESS"
+ echo " "
+ echo "What is the contact address for connect problems due to the"
+ echo "user being K:lined, shown to the user when they attempt to"
+ echo "connect? This should be a valid email address."
+ echo " "
+ echo "For all servers, note that this message is displayed when"
+ echo "the user is affected by a local K:line or k:line. With"
+ echo "Services-based autokills, the message is set up automatically"
+ echo "by Services to ask the user to email kline@serenity-irc.net. It is"
+ echo "recommended that you set this up to give a valid email address"
+ echo "for the server's admin, not kline@serenity-irc.net."
+ echo $n "[$FOO] -> $c"
+ if [ -z "$AUTO_CONFIG" -o -n "$runonce" -o -z "$FOO" ] ; then
+ read cc
+ else
+ cc=""
+ runonce=Yes
+ fi
+ if [ -z "$cc" ] ; then
+ cc=$FOO
+ fi
+ case "$cc" in
+ *@*.*)
+ KLINE_ADDRESS=$cc
+ FOO="$KLINE_ADDRESS"
+ ;;
+ *)
+ echo " "
+ echo "Read the instructions and try again... You did not enter a"
+ echo "proper email address (user@host.domain)."
+ FOO=""
+ ;;
+ esac
+done
+
+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="$DPATH/ircd"
+ 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
+ echo ""
+ echo "What is your local domain name? This is used for /stats w to"
+ echo "report local clients vs. remote clients."
+ if [ "$LOCALD" = "define" ] ; then
+ echo "Auto-probing local host..."
+ HOSTNAME=`hostname`
+ if [ $? -eq 0 ]; then
+ TEMPHOST="${HOSTNAME#*.}"
+ if [ "${#HOSTNAME}" -ne "${#TEMPHOST}" ]; then
+ FOO="${TEMPHOST}"
+ else
+ echo ""
+ echo "This guess probably isn't right:"
+ FOO="${HOSTNAME}"
+ fi
+ else
+ FOO="$DOMAINNAME"
+ fi
+ else
+ echo "Skipping auto-probe. (Bad OS: $OSNAME)"
+ FOO="configure.this"
+ fi
+ 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
+ FOO=$cc
+done
+DOMAINNAME=$cc
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+ if [ -n "$HUB" ] ; then
+ FOO="Yes"
+ else
+ FOO="No"
+ fi
+ echo ""
+ echo "Are you running as a HUB server?"
+ 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]*)
+ HUB="1"
+ ;;
+ [Nn]*)
+ HUB=""
+ ;;
+ *)
+ echo ""
+ echo "You need to enter either Yes or No here..."
+ echo ""
+ FOO=""
+ ;;
+ esac
+done
+
+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
+CRYPT_ILINE_PASSWORD=$CRYPT_OPER_PASSWORD
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+ if [ -n "$ZIP_LINKS" ] ; then
+ FOO="Yes"
+ else
+ FOO="No"
+ fi
+ echo ""
+ echo "Do you want to enable server compression?"
+ 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]*)
+ ZIP_LINKS="1"
+ ;;
+ [Nn]*)
+ ZIP_LINKS=""
+ ;;
+ *)
+ echo ""
+ echo "You need to enter either Yes or No here..."
+ echo ""
+ FOO=""
+ ;;
+ esac
+done
+
+FOO=""
+runonce=""
+while [ -z "$FOO" ] ; do
+ FOO="$MAXCONNECTIONS"
+ 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
+
+
+cat <<__EOF__
+
+The file "$OPTIONS" was either created or rewritten to contain your
+answers to the above questions.
+
+This file is automatically generated and will be updated each time you
+run Config. You should retain a copy of this to help migrate to future
+versions of the server with ease.
+
+__EOF__
+
+#
+# continue the $SETUP file
+#
+cat >> $SETUP << __EOF__
+#define DPATH "$DPATH"
+#define SPATH "$SPATH"
+#define MAXCONNECTIONS $MAXCONNECTIONS
+__EOF__
+if [ -n "$HUB" ] ; then
+ echo "#define HUB" >> $SETUP
+else
+ echo "#undef HUB" >> $SETUP
+fi
+if [ -n "$CRYPT_OPER_PASSWORD" ] ; then
+ echo "#define CRYPT_OPER_PASSWORD 1" >> $SETUP
+else
+ echo "#undef CRYPT_OPER_PASSWORD" >> $SETUP
+fi
+if [ -n "$CRYPT_ILINE_PASSWORD" ] ; then
+ echo "#define CRYPT_ILINE_PASSWORD 1" >> $SETUP
+else
+ echo "#undef CRYPT_ILINE_PASSWORD" >> $SETUP
+fi
+if [ -n "$CONTACT_URL" ] ; then
+ echo "#define CONTACT_URL \"$CONTACT_URL\"" >> $SETUP
+fi
+if [ -n "$CONTACT_EMAIL" ] ; then
+ echo "#define CONTACT_EMAIL \"$CONTACT_EMAIL\"" >> $SETUP
+fi
+if [ -n "$SERVICES_NAME" ] ; then
+ echo "#define SERVICES_NAME \"$SERVICES_NAME\"" >> $SETUP
+fi
+if [ -n "$KLINE_ADDRESS" ] ; then
+ echo "#define KLINE_ADDRESS \"$KLINE_ADDRESS\"" >> $SETUP
+fi
+if [ -n "$DOMAINNAME" ] ; then
+ echo "#define DOMAINNAME \"$DOMAINNAME\"" >> $SETUP
+else
+ echo "#undef DOMAINNAME" >> $SETUP
+fi
+if [ -n "$ZIP_LINKS" ] ; then
+ echo "#define ZIP_LINKS 1" >> $SETUP
+else
+ echo "#undef ZIP_LINKS" >> $SETUP
+fi
+
+#
+# Create file for make install
+#
+rm -f $MAKEINST
+cat > $MAKEINST << __EOF__
+
+if [ ! -d $DPATH ] ; then
+ mkdir $DPATH
+fi
+
+if [ -f $SPATH ] ; then
+ cp $SPATH $SPATH.old
+fi
+
+if [ -f $DPATH/ircd.pid ] ; then
+ kill -9 \`cat $DPATH/ircd.pid \`
+fi
+
+cp src/ircd $SPATH
+$SPATH
+__EOF__
+#
+chmod 711 $MAKEINST
+#
+# create the persistant file
+#
+rm -f $OPTIONS
+cat > $OPTIONS << __EOF__
+#
+# VERSION: $IRCD_VERSION
+# DATE: $CONF_DATE
+#
+# This file is automatically generated and will be updated each time you
+# run Config. You should retain a copy of this to help migrate to future
+# versions of the server with ease.
+#
+LAST_VERSION="$IRCD_VERSION"
+CONTACT_URL="$CONTACT_URL"
+CONTACT_EMAIL="$CONTACT_EMAIL"
+SERVICES_NAME="$SERVICES_NAME"
+KLINE_ADDRESS="$KLINE_ADDRESS"
+ZIP_LINKS="$ZIP_LINKS"
+DPATH="$DPATH"
+SPATH="$SPATH"
+HUB="$HUB"
+PARANOIA="$PARANOIA"
+CRYPT_OPER_PASSWORD="$CRYPT_OPER_PASSWORD"
+MAXCONNECTIONS="$MAXCONNECTIONS"
+DOMAINNAME="$DOMAINNAME"
+__EOF__
+
+cat <<__EOF__
+
+ Config is complete.
+
+ Before compiling, check the contents of include/config.h for any strange
+ things you usually set. If you want them to be included in the future,
+ ask them to be moved to the setup.h file on remmy@serenity-irc.net.
+
+__EOF__
--- /dev/null
+Installation Procedures for the StarChat IRC Server:
+=======================================================================
+by Alexei Kosut (Lefler) <lefler@dal.net>
+with changes for dal4.3.6 by Mikko Hänninen (Wizzu) <wizzu@dal.net>
+for dal4.3.6
+with changes for dal4.4.11 by Cabal95 (cabal95@dal.net)
+with changes for Star4.10.Spire by GZ (gz@starchat.net)
+=======================================================================
+
+This document describes how to install ircd, the unix daemon that acts as
+an IRC server. Specifically, for the StarChat IRC Network, though some
+information may be applicable to other networks as well.
+
+For more information on StarChat or this server, please see our WWW page at
+<http://www.starchat.net/>, or contact us at sc@starchat.net.
+
+For help with this ircd, try joining #ircd on StarChat. There you will find a friendly
+staff who can help you with most common problems affecting the ircd. If they can't help,
+they'll probably be able to find someone who will. :-)
+
+The StarChat server is available from ftp://utopia.starchat.net/pub/, along with the
+latest copy of this document.
+
+
+=======================================================================
+This version of the StarChat IRC Server 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 should now also compile
+ under Red Hat 5.0
+
+HPUX 9.01 gcc 2.6.3
+
+HPUX 10.01 gcc 2.7-96q3 (Cygnus)
+
+=======================================================================
+Unpacking the Distribution
+
+If you are reading this, you have most likely already done this, but to
+recap:
+
+The StarChat server <ftp:/utopia.starchat.net/pub/Star4.00.tar.gz>
+comes tarred and gzipped. To uncompress it and expand it, use the
+following command at the Unix prompt:
+
+tar -xzf Star4.10.tar.gz
+
+This will create a new directory called Star4.10, 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/options.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 coding@starchat.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. Alternatively, try #ircd
+on StarChat.
+
+BE CERTAIN TO INCLUDE OPERATING SYSTEM INFORMATION (uname -a) AND COMPILER
+VERSION (gcc -v, for instance) IN ALL BUG REPORTS.
+
+Common problems
+===============
+
+If, when you try to compile, something like the following halts make:
+res.o: In function `proc_answer':
+/home/GZ/Star4.10/src/res.c:617: undefined reference to `dn_expand'
+/home/GZ/Star4.10/src/res.c:622: undefined reference to `_getshort'
+/home/GZ/Star4.10/src/res.c:624: undefined reference to `_getshort'
+
+you need to include a separate library. Rerun ./Config and in the space
+where it asks you what additional libraries you would like to include,
+type "-lresolv". If a similar problem occurs referring to 'crypt',
+include the "-lcrypt" library aswell.
+=======================================================================
+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, type:
+ cp example.conf 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 StarChat,
+make sure that you have the following line:
+
+U:services.starchat.net:*:*
+
+If you need help configuring your file, please join StarChat, go to channel
+#ircd, 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!
+
+- GZ
--- /dev/null
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our 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. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, 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 a 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 tell them 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.
+
+ 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 Agreement 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 work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 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
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual 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 General
+ Public License.
+
+ d) 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.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+\f
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 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
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying 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.
+
+ 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.
+\f
+ 7. 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 the 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
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. 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
+
+ 9. 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.
+
+ 10. 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
+ Appendix: 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 humanity, 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) 19yy <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 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.
+
+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) 19xx 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 a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
--- /dev/null
+#/************************************************************************
+#* 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.
+#*/
+
+CC=gcc
+INCLUDEDIR=../include
+
+# [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
+# Recent Linux systems seem to expect this:
+RES=res_init.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 "You have not 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 'Serene IRCD compiled!'
+ @echo ''
+
+clean:
+ @echo 'Cleaning Serene IRCD'
+ @for i in $(SUBDIRS); do \
+ echo "Cleaning $$i";\
+ ( cd $$i; ${MAKE} ${MAKEARGS} clean; ) ; \
+ done
+ @echo ''
+ @echo 'Cleaning complete.'
+ @echo ''
+
+distclean: clean
+ rm -rf include/setup.h Makefile Options .install
+ @echo ''
+ @echo 'Distribution is now fully cleaned.'
+ @echo ''
+depend:
+ @for i in $(SUBDIRS); do \
+ echo "Making dependencies in $$i";\
+ ( cd $$i; ${MAKE} ${MAKEARGS} depend; ) ; \
+ done
+
+install: all
+ @echo "Copying ircd to the right location."
+ ./.install
--- /dev/null
+#! /bin/sh
+
+# @(#)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
--- /dev/null
+#####################################
+# Changes in Star5.18 #
+#####################################
+Remmy:
+o: Leaf servers no longer try to connect to other servers when they are
+ already connected to some other server.
+o: No more Q:Lined nick notices from U lined servers. (for real this
+ time!)
+o: Removed channel mode +p. It led to obscure bugs and no users were using
+ it for legit reasons anyways. Dinosaur feature.
+o: Removed R lines support from the ircd.conf. We have never used them
+ anyways.
+o: Added QUIT messages back to the ircd.
+o: Added support for svsjoin and svspart (/os push and /os part) to the ircd.
+o: The ircd had an incomplete list of supported channel modes it gave
+ out to clients upon connecting. Not sure it makes a difference as
+ it has been like this for over a year, but fixed it anyways.
+
+Siete:
+o: Split up /stats reports for K and Z lines so they no longer should
+ flood us all off. /stats k for K lines, /stats Z for Z lines,
+ /stats K for both. Use /stats z for memory usage.
+
+#########################################################################
+# Changes in Star5.19 (see doc/CHANGES.old for older changes) #
+#########################################################################
+Remmy:
+o: Reading in an ircd.conf in DOS file format will no longer result in
+ strange and unexpected behaviour by the ircd.
+o: Removed pre Star5 support
+o: Some minor spelling fixes
+
+Siete:
+o: Added support for usermode 'j' (NetFounder)
+o: Removed /links and /map notices to IRC Operators
+
+#########################################################################
+# Changes in Star5.20 (see doc/CHANGES.old for older changes) #
+#########################################################################
+Remmy:
+o: Removed many compilation warnings when compiling with -Wall
+o: Channel mode +R was not properly transmitted between servers after a
+ split. Bad!
+
+#########################################################################
+# Changes in Star5.21 (see doc/CHANGES.old for older changes) #
+#########################################################################
+Remmy:
+o: Users could set themselves mode +j (they shouldn't be allowed to).
+
+#########################################################################
+# Changes in Star5.22 (see doc/CHANGES.old for older changes) #
+#########################################################################
+Remmy:
+o: e line support. These can be used to exempt users otherwise caught in
+ a KLINE. Syntax is the same as that of a K line. Can also be used to
+ set exemption AKILLs using services.
+o: No more throttle notices! Now we can all sleep at night again.
+
+#########################################################################
+# Changes in Star5.23 (see doc/CHANGES.old for older changes) #
+#########################################################################
+Remmy:
+o: Removed e line support ;). They interfere with AKILLs in the new setup
+ and as such should not be used.
+o: Removed socks scan. These served little purpose anymore and caused
+ significant delays for people behind a NAT network or firewall.
+o: Simplified the jinx handling in the ircd. This function is much
+ smaller now and no longer supports the old hostjinxes (hardly used
+ anyways).
+
+#########################################################################
+# Changes in Star5.24 (see doc/CHANGES.old for older changes) #
+#########################################################################
+Remmy:
+o: People no longer can take on the nick WebServ when services are down.
+o: Introduced usermode 'w'. This one keeps track of who is and who isn't
+ a valid WebTV user. For use with Services version 0.6.0 and higher.
+o: /map, /links and /whois are available to all again and show servers.
+
+#########################################################################
+# Changes in Star5.25 (see doc/CHANGES.old for older changes) #
+#########################################################################
+o: Introduced channel mode H to require identifaction on certain
+ hostmasks prior to joining a channel. (Remmy)
+o: New and improved hostmasking for usermode +x to better differentiate
+ between numeric IP's. Also hardens the chance on someone finding the
+ real hostmask. (InnerFIRE)
+
+#########################################################################
+# Changes in Star5.26 (see doc/CHANGES.old for older changes) #
+#########################################################################
+o: Removed D,d and L lines support as they weren't being used. (Remmy)
+o: Removed identd support. We don't block users based on ident and not
+ checking may make things faster for firewalled / NAT users. (Remmy)
+o: Users can no longer /whois when jinxed. Quit messages can't be sent by
+ them. (Remmy)
+o: Removed support for the /SERVICES command. /IDENTIFY command no longer
+ forwards to ChanServ. (Remmy)
+o: Changed compilation flags and done some minor cleanups. (Remmy)
+
+
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+ 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.
+
--- /dev/null
+ -- ircd.conf Programming --
+ (written for DALnet release ircd) v1.01 by Roddy Vagg -- <roddy@dal.net>
+ (Updated for StarIRCD 5.26 by Remmy)
+ --------------------
+
+ 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) ......................... H Lines
+ 3.12) ......................... P Lines
+ 3.13) ......................... X lines
+ 3.14) ......................... Summary
+
+ --------------------
+
+1) Introduction:
+
+ If you are running, or planning on running an IRC server for DALnet,
+ you will need to setup an ircd.conf, your ircd.conf must meet the
+ requirements of a linked DALnet server which means it must contain all
+ the standard DALnet lines, these will be listed at the bottom of this
+ document.
+
+ --------------------
+
+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:*:Description Of Your Server:7000
+ The 1st field should be the `real' name of your server, not the short
+ name.
+ The 2nd field is unused at the moment and should be left blank.
+ 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.us.dal.net::Walt's DALnet 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 DALnet 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).
+
+ 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 come in two forms, normal `O' lines, and Local Operator `o' lines.
+ Normal 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.
+
+ DALnet's O:lines have an added field, the "operflag" field. Whereas before,
+ you simply had control over whether an oper was global or local, now it is
+ possible to specify almost all the access an oper has, specifically, by
+ choosing the operflags in their O:line. For more information, read the
+ example.conf located in this directory.
+
+ Syntax:
+
+O:hostname:password:nickname:operflags: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:O: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.
+
+o:*@*:GiJ.E\hGyjhaW:Anyone:o:10
+ This line allows anyone who is running ident to issue the command:
+ `/oper Anyone <password>'
+ This line comes from an ircd that uses encrypted passwords, so the user must
+ have the plaintext password.
+ When this line is used with success, the user will be a Local Operator since
+ the line only has a small `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 stntax 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.
+ 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:*::*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) 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.12) 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.13) X lines [SUGGESTED]
+
+ The /die and /restart commands can occasionally be misused or accidentally
+ typed, causing a lot of trouble as hundreds of users are immediately
+ disconnected and the server is thrown into chaos, sometimes unrestartable
+ for hours. Furthermore, it can be maliciously used (in the case of O:line
+ hacking, it's just about as much damage as you can cause). The X line tries
+ to reduce the risk of this happening by providing passwords for the /die &
+ /restart commands. The format of the X:line is simply:
+
+ Syntax:
+X:password_for_die:password_for_restart
+
+ Example:
+X:foo:bar
+
+ --------------------
+
+3.14) 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!
+ --------------------
+
+[ Some text stolen from original example.conf modified for DALnet ]
+
+ -- Roddy Vagg / <roddy@dal.net>
+
--- /dev/null
+# IRC - Internet Relay Chat, doc/example.conf
+# Copyright (C) 2000, Gerhard Mack
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+# Example ircd.conf file for Star4.00.Velocity or newer.
+#
+#
+# In this file I will explain what the different lines in the ircd.conf file
+# do. You may want to test config changes with chkconf before you try them
+# on your server to prevent disruption to your users due to errors.
+#
+# In this file I use the term "ircd" to designate an irc server (daemon).
+#
+# The following terms can be used to determine if you need a line or not:
+# MANDATORY: The ircd requires the line to operate.
+# NETWORKED: The ircd needs the line when it is linked to one or more other
+# servers
+# SUGGESTED: It would most likely be a good idea if you used this.
+# OPTIONAL: It's up to the person doing the configuration.
+# DISCOURAGED: Probably not a good idea, except in limited circumstances.
+# OBSOLETE: Old, out of date, don't use this
+#
+# NOTE: Many networks will require certain configuration lines to allow
+# their networks to run more smoothly. If you are given lines by
+# the network you are linking to then they should be implemented
+# regardless of this file's recommendation.
+#
+# This file goes through the lines in the order they should be placed in
+# a functional ircd.conf file.
+#
+# NOTE: Keep in mind that this file is read in REVERSE, that means the
+# bottom line is the first one read and the top line is the last.
+# Remember this when you are doing anything that needs to be in
+# a specific order such as I-lines.
+#
+#
+#
+# M: MANDATORY. This line specifies the basic information the server needs
+# about itself to operate.
+#
+# M:server name:IP address:Server description:port
+# Server name is the name the server shows to clients and other servers on
+# the network.
+# IP address tells the server what address on the machine to bind to, if
+# you fill the field with a "*", or leave it empty, it will bind itself to
+# all addresses it finds on the machine.
+# Server description is the description of the server shown to clients and
+# other servers on the network.
+# Port is the default port the server will attach itself to.
+#
+# This line names the server server1.starchat.net and attaches itself to
+# all addresses attached to the machine on port 7000:
+#
+M:Server1.starchat.net:*:Cool new server:7000
+#
+#
+#
+# A: MANDATORY. This is your administration info that is shown when someone
+# on your server types "/admin" This is a good place to keep the information
+# users need to contact someone in charge.
+#
+# ":" Designates a new line, other than that it's pretty much free form.
+#
+# Here is a format often used:
+# A:server's provider:admin: admin's email : coadmin: coadmin's email
+#
+A:Lame1 colocations:admin John Random: email JRandom@lame1.com
+#
+#
+#
+# Y: SUGGESTED. Defines connection class types and behavior.
+# Class is the number representing the Y line, Ping frequency defines the
+# duration between pings. Auto-connect frequency defines how often the server
+# will try to connect to the server defined with the corresponding connection
+# class: max connection defines the maximum number of connections the server
+# will allow using this connection class.
+#
+# Sendq is the maximum space the server will use to buffer outgoing
+# messages. If the sendq is filled, the affected connection is dropped.
+# I reccomend setting this low for clients (prevents flooding) and high
+# for servers.
+#
+# NOTE: The max connections for all Y-lines should add up to the total
+# number of connections the the server can handle MINUS the number of
+# file desrcriptors that are needed for things like wingate checking and one
+# for the config file. ( 5-10 should do)
+#
+# For example: A server compiled for 256 max filedescriptors should have all
+# Y-lines add up to 250 (remove 6 for server internal use)
+#
+#
+# Y:class:ping frequency:auto-connect frequency:max connections:max sendq
+#
+# This is a typical client Y-line no auto-connect, max 20 connections.
+Y:1:60:0:20:100000
+#
+# This is an example of a Y-line that could be used on your primary hub
+#
+Y:40:120:60:1:3000000
+# This is an example of a Y-line that could be used for your secondary hubs
+Y:50:120:0:5:3000000
+#
+#
+#
+# I: MANDATORY. These lines define who can connect to a server, without
+# them no one is able to connect to the server.
+#
+# I:IP mask:password:domain mask::Y-Line (optional)
+#
+# IP Mask is the numeric ip mask (ex 192.168.*) if Arbitrary text is
+# entered such as NOMATCH the I-line will only match based on the domain
+# name and will disallow clients from addresses that lack reverse lookup
+# The password is optional, and is needed to connect using that I line.
+#
+# The domain name is the name returned from a reverse DNS lookup, the Y-line
+# of course is the Y-line that you want to correspond to the connection.
+# NOTE: I-lines are read starting from the bottom passing though each one
+# until a line is found that matches the client's connection if none
+# is found access to the server is denied.
+#
+# This is a I-line that will allow anyone at all to connect.
+I:*@*::*@*::1
+#
+#
+#
+# P: SUGGESTED. Allows you to add ports and addresses/domain sockets other
+# then the one specified in the M-line.
+#
+# P:address:*:*:port
+#
+# To have the server bind all addresses available on a given port leave the
+# leave the field blank.
+# NOTE: if a given port is already in use the server will simply fail to
+# load.
+#
+# This line would have the server look for connections to port 7000 on
+# the address 127.0.0.1
+#
+P:127.0.0.1:*:*:7000
+#
+#
+#
+# O: SUGGESTED. O-lines define who has Oper access on the server. How
+# necessary these line are depend on how well your site is configured and the
+# philosophy of the network you are linked to.
+#
+# O:address:password:nick:flags:Y-line
+#
+# If the server is compiled to use encrypted Oper passwords then you must
+# use mkpasswd to convert the password from plaintext.
+#
+# NOTE: Addresses using the numeric IP address will work even if it
+# resolves.
+#
+# flags:
+# a = can set +a Designates a services oper
+# A = can set +A to set server admin
+# b = can set temp klines using /kline
+# B = can remove temp klines using /unkline
+# c = can use /squit and /connect on locally connected servers
+# C = can use /squit and /connect on any server
+# D = can shut down the server using /die
+# f = can see server flood kills by setting /umode +f
+# g = can send globop messages
+# h = can see helpop requests by setting /umode +h
+# k = can kill clients connected locally
+# K = can kill any clients on the network
+# l = can send locop messages
+# n = can send local server messages (/msg $servername message to users)
+# N = can send global server messages (/msg $*.net message to users)
+# o = designates a local oper includes flags: bBcfghklnruw
+# O = designates a global oper includes flags: CKNo
+# r = can /rehash the server
+# R = can /restart the server
+# u = can see local connects and disconnects using /umode +c
+# w = can send wallops (obsolete)
+#
+# NOTE: Access to everything is: AaDOR
+#
+O:192.168.2.*:notarealpassword:AnOper:OR:10
+#
+#
+#
+# X: SUGGESTED. Sets a password for the /die and /restart commands.
+#
+# X:Die password:Restart password
+#
+X:killme:restartme
+#
+#
+#
+# C: NETWORKED. Connect lines, this line defines who your server can
+# connect to. C-lines must be paired with an N line to work.
+#
+# C:remote address:password:remote server name:port to auto-connect:Y-line
+# The address is the machine's Internet address, the server name is
+# the server's name on irc network as defined by the machine's M-line.
+# They do not have to be the same.
+# NOTE: Using the numeric ip address for the machine's address is slightly
+# faster and more secure then using it's domain name.
+#
+C:192.168.2.1:notarealpassword:hub.starchat.net:7325:45
+#
+#
+#
+# N: NETWORKED. This line defines what servers your server can connect
+# to yours. N-lines must be paired with an C line to work correctly.
+#
+# N:remote address:password:remote server name::Y-line
+# The address is the machine's address on the Internet, the server name is
+# the server's name on irc network as defined by the machine's M-line.
+# They do not have to be the same.
+#
+# NOTE: Using the numeric IP address for the machine's address is slightly
+# faster and more secure then using it's domain name.
+#
+N:192.168.2.1:notarealpassword:hub.starchat.net::40
+#
+#
+#
+# U: NETWORKED. Determines what servers may make changes to things like
+# channel modes without the server sounding alarms or attempting to stop
+# them.
+#
+# U:Server-Name:*:*
+#
+# This line allows services to have the access needed to do it's job.
+#
+U:Services.StarChat.Net:*:*
+#
+#
+#
+# H: NETWORKED. Hub lines. These define what servers a given hub is permitted
+# to connect to the network.
+# H:servers the hub is allowed connect::name
+#
+# NOTE: The name is the name defined in the hub's M-line it might not be the
+# same as it's address.
+#
+# This would allow hub.starchat.net to hub any servers while being directly
+# connected to your server.
+H:*::hub.starchat.net
+#
+# This line would only allow hub2 to have Mexican servers as leaves.
+H:*.mx.*:hub2.starchat.net
+#
+#
+#
+# Q: OPTIONAL. Nick quarantine. This line prevents non opers from using
+# nicks covered by the Q-line.
+#
+# Q::reason:nick
+#
+Q::users may not use services nicks:*serv*
+#
+#
+#
+# q: OBSOLETE. Server quarantine. This line quarantines the specified
+# server, the line must be on ALL SERVERS connected to the network or net
+# spits will occur.
+#
+# q::reason:server
+#
+q::I have no idea why:unknown.starchat.net
+#
+#
+#
+# K: OPTIONAL. Kill Line. K-lines are a means of denying access to
+# certain clients.
+#
+# K-lines work best for addresses that are likely to be banned long term
+# and therefore a temporary kline or akill won't do.
+#
+# K:address:reason:ident
+#
+# Address is the address or mask of the client you wish to ban.
+# NOTE: If you ban an IP address and reverse DNS is successful the
+# domain name returned will be checked and NOT the IP address, any bans
+# on the IP address will be IGNORED. This applies to both Klines
+# and A-kills.
+#
+# The reason field is what is shown to the client on the receiving end
+# of the kline.
+#
+# The ident is checked against what is returned by the users, keep in mind
+# that this is easily changeable, and not useful if you're trying to keep a
+# particular user off the network, although it is a lot more logical for temp
+# K-lines or A-kills since they are more readily changed.
+# This will ban any user from lame.com and tell them it was for mass
+# advertising:
+K:*.lame.com:Mass advertising:*
+#
+# This will ban anyone using the ident Sphere and tell them to get
+# a new script.
+K:*:Get a new script:Sphere
+#
+#
+# Z: DISCOURAGED. Disconnects the client at the earliest stage of connection.
+# useful for preventing annoying server messages by persistent attempted
+# server connections, or getting rid of people ban evading using vhosts.
+#
+# NOTE: 1 The address MUST be a numeric IP or it won't work.
+# NOTE: 2 The last field must be a * or strange things may happen to the
+# server.
+#
+# Z:address:reason:*
+#
+Z:192.168.2.2:not a server:*
--- /dev/null
+OperMOTD.DOC - How to use OperMOTD. (15/06/99)
+
+If you want to use the OperMOTD feature. You will have to copy a file
+named ircd.opermotd to the same location you copied your ircd.conf to.
+Any text you put in that file will be showed when somebody succesfully
+opers up.
+ - GZ
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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.'
+ */
+
+#include "msg.h"
+#define MAXMODEPARAMS (MAXPARA-2) /* Maximum modes processed */
+#define RESYNCMODES 6 /* Max modes per MODE in resync */
+#define MODEPARAMS 6 /* Max modes from user */
+
+#endif
--- /dev/null
+
+#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
+
--- /dev/null
+
+#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, ...);
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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__ */
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#ifndef __common_include__
+#define __common_include__
+
+#include <time.h>
+
+#ifdef HAVE_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifndef PROTO
+#if __STDC__
+# define PROTO(x) x
+#else
+# define PROTO(x) ()
+#endif
+#endif
+
+#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
+
+extern int match PROTO((char *, char *));
+extern int mycmp (char *, char *);
+
+#ifdef NEED_STRTOK
+extern char *strtok PROTO((char *, char *));
+#endif
+#ifndef HAVE_STRTOKEN
+extern char *strtoken PROTO((char **, char *, char *));
+#endif
+#ifndef HAVE_INET_ADDR
+extern unsigned long inet_addr PROTO((char *));
+#endif
+
+#if !defined(HAVE_INET_NTOA) || !defined(HAVE_INET_NETOF) && !defined(SCOUNIX)
+#include <netinet/in.h>
+#endif
+
+#ifndef SCOUNIX /* SCO Openserver has these, but the header files are broken */
+#ifndef HAVE_INET_NTOA
+extern char *inet_ntoa PROTO((struct in_addr));
+#endif
+
+#ifndef HAVE_INET_NETOF
+extern int inet_netof PROTO((struct in_addr));
+#endif
+#endif /* SCOUNIX */
+
+int global_count, max_global_count;
+extern char *myctime PROTO((time_t));
+extern char *strtoken PROTO((char **, char *, char *));
+
+#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);(void)strip_trailing_spaces(x);}while(0)
+
+#ifndef SCOUNIX
+extern u_char tolowertab[], touppertab[];
+#else
+extern unsigned char tolowertab[], touppertab[];
+ /* Typedef for u_char exists and is wrong. */
+#endif
+
+#undef tolower
+#define tolower(c) (tolowertab[(u_char)(c)])
+
+#undef toupper
+#define toupper(c) (touppertab[(u_char)(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
+#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 * */);
+extern char *get_mode_str() ;
+extern int do_snick() ;
+extern int mode_snick() ;
+
+/*
+ * Protocol support text. DO NO CHANGE THIS unless you know what
+ * you are doing.
+ */
+#define PROTOCTL_SUPPORTED "NOQUIT TOKEN WATCH=128 SAFELIST NETWORK=Serenity-IRC CHANMODES=beH,k,l,imnstR MODES=6 MAXCHANNELS=10 NICKLEN=30 MAXBANS=60 EXCEPTS TOPICLEN=307 CHANNELLEN=32 CHARSET=ascii STD=i-d"
+
+#ifdef __FreeBSD__
+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__ */
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, include/config.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.
+ */
+
+#ifndef __config_include__
+#define __config_include__
+
+#include "setup.h"
+
+/*
+ *
+ * NOTICE
+ *
+ * Under normal conditions, you should not have to edit this file. Run
+ * the Config script in the root directory instead!
+ *
+ */
+
+/*
+ * Compression level. 1 is fastest and 9 is slowest.
+ * Do not use a setting above 5 or the ircd will use a lot more
+ * cpu.
+ */
+#ifdef ZIP_LINKS
+#define ZIP_LEVEL 2
+#endif
+
+/*
+ What network are we linked to? Define netwide policy here.
+*/
+
+#define irc_network "Serenity-IRC"
+#define admin_chan "#help"
+#define random_serv "irc.serenity-irc.net"
+#define network_www "http://www.serenity-irc.net"
+#define network_aup "http://www.serenity-irc.net/aup/"
+#define netwide_kline "kline@serenity-irc.net"
+
+
+#define CLIENT_MASKING
+#define MASK_ON_CONNECT
+#define OPER_MASKS
+
+/* undef this to fix *\*!*@* ban bug */
+#undef ESCAPED_MATCHING
+
+#ifdef CLIENT_MASKING
+#define userspace_mask_prefix "Serene"
+#endif
+
+#define USERSPACE_X
+#define userspace_x_prefix "Serene"
+
+/* This will be the maximum length of a quit-message */
+
+#define QUITLEN 180
+
+/* High Traffic Command protection code settings (-GZ)
+ *
+ * HTCTIME Minimum time between sending commands.
+ * HTCTRIGGER Triggers and sends locops when reached.
+ */
+
+#define HTCTIME 5
+#define HTCTRIGGER 15
+
+/* Oper Masks for the hide code */
+#if defined(CLIENT_MASKING) && defined(OPER_MASKS)
+#define ircop_host "IRCop.Serenity-IRC.Net"
+#define admin_host "Admin.Serenity-IRC.Net"
+#define locop_host "Local.Serenity-IRC.Net"
+#define sadmin_host "ServOp.Serenity-IRC.Net"
+#define sroot_host "SRA.Serenity-IRC.Net"
+#define netadmin_host "NetAdmin.Serenity-IRC.Net"
+#endif
+
+/* Additional flags to give FreeBSD's malloc, only play with this if you
+ * know what you're doing.
+ */
+
+#define MALLOC_FLAGS_EXTRA ""
+
+/* Many older Operating Systems are running with insecure TCP stacks.
+ * This allows IP spoofing attacks, which are very difficult for
+ * operators to track down and ban."
+ *
+ * If you have such an old OS you can enable it here but keep in mind that
+ * this will be the least of your security problems.
+ *
+ * Enable this option for any windows version older than 2000
+ */
+
+#undef NOSPOOF
+
+
+/* KLINE_ADDRESS
+ *
+ * This is the email address displayed to the user when they are K:lined
+ * so that they can email someone in the server's administration about it.
+ * It is usually set up by the Config script.
+ *
+ * It should be a valid email address for the users to contact.
+ *
+ * For StarChat servers, note that this message is displayed when the user
+ * is affected by a local K:line or k:line. For Services-based autokills,
+ * the message is set up automatically by Services to ask to email
+ * kline@starchat.net. It is recommended that you set this up to give a valid
+ * email address for the server's admin, not kline@starchat.net.
+ */
+#ifndef KLINE_ADDRESS
+#define KLINE_ADDRESS "clueless-admin@poorly.configured.server"
+#endif
+
+/*
+ * SEEUSERSTATS - Sends a notice to opers set +t that the client is doing
+ * /stats, /admin or /links, #undef'ing this disables it. -ns
+ */
+#define SEEUSERSTATS
+
+/*
+ * Max size arguments to stats/admin/links can be before truncation.
+ * Only applies to notices sent to opers (see above). -Ben
+ */
+#define USERSTATMAX 120
+
+/*
+ * NOTE: It is important to set this to the correct "domain" for your server.
+ * Define this for the correct "domain" that your server is in. This
+ * is important for certain stats. -mlv
+ */
+#ifndef DOMAINNAME
+#define DOMAINNAME "serenity-irc.net"
+#endif
+
+/*
+ * 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 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
+
+/* #undef DEBUGMODE *//* define DEBUGMODE to enable debugging mode.*/
+//#define DEBUGMODE
+
+/*
+ * Defining FORCE_CORE will automatically "unlimit core", forcing the
+ * server to dump a core file whenever it has a fatal error. -mlv
+ * Make sure to check that your shell allows core files.
+ */
+#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.
+ */
+#ifndef DPATH
+#define DPATH "/usr/local/lib/ircd" *//* dir where all ircd stuff is */
+#endif
+#ifndef SPATH
+#define SPATH "/usr/local/bin/ircd" *//* path to server executeable */
+#endif
+#define CPATH "ircd.conf" /* server configuration file */
+#define MPATH "ircd.motd" /* server MOTD file */
+#define OMPATH "ircd.opermotd" /* server IRCop MOTD file */
+#define LUPATH "ircd.lusers" /* server lusers file */
+#define LPATH "debug.log" /* Where the debug file lives, if DEBUGMODE */
+#define PPATH "ircd.pid" /* file for server pid */
+
+/*
+ * 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 this only if you are actually logging -Studded
+#define FNAME_USERLOG "users.log"
+#define FNAME_OPERLOG "opers.log"
+*/
+
+/* 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
+
+/* NO_DEFAULT_INVISIBLE and NO_DEFAULT_HOSTHIDDEN
+ *
+ * When defined, your users will not automatically be attributed with user
+ * mode "i" (i == invisible). Invisibility means people dont showup in
+ * WHO or NAMES unless they are on the same channel as you.
+ * Added the ability to hide a users hostname also as with mode z.
+ * By default this mode needs to be off.
+ */
+
+#define NO_DEFAULT_INVISIBLE
+
+/* NO_DEFAULT_HIDE
+ *
+ * When defined, your users will not automatically be attributed with user
+ * mode "x" (x == hidden host). Hide means people dont show their full
+ * IP when somone wants to see their IP or DNS. buhbye nukes.
+ */
+#ifdef USERSPACE_X
+#undef NO_DEFAULT_HIDE
+#endif
+
+/* If you want your server to save and restore the local/max client count */
+
+#define SAVE_MAXCLIENT_STATS
+
+
+/* What listen() backlog value do you wish to use? Some servers
+ * have problems with more than 5, others work fine with many, many
+ * more.
+ */
+
+#define LISTEN_SIZE 5
+
+/* Define your maximum sendq here */
+
+#define MAXSENDQLENGTH 3000000
+
+/* Define the size of a bufferpool (total of ALL sendq's in use) */
+
+#define BUFFERPOOL (9 * MAXSENDQLENGTH)
+
+/* Define the size of your nickname history for /whowas */
+
+#define NICKNAMEHISTORYLENGTH 500
+
+/* 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
+
+/*
+ * If your server is running as a a HUB Server then define this.
+ * A HUB Server has many servers connect to it at the same as opposed
+ * to a leaf which just has 1 server (typically the uplink). Define this
+ * correctly for performance reasons.
+ */
+/* #define HUB */
+
+/*
+ * 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.
+ */
+#undef 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.
+ */
+#undef USE_SYSLOG
+
+#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 6000
+
+/*
+ * 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
+
+/* Define default Z:line time for SOCKS -taz */
+#define ZLINE_TIME 300
+
+/*
+ * StarChat Mandatory section
+ *
+ * It is VERY important that you DO NOT change any of the settings
+ * in this section for a server that is or will be running on StarChat.
+ * If you feel the need to make a change to one of these settings
+ * please write to coding@starchat.net FIRST to discuss your reasons.
+ */
+
+/* Client connection throttling
+ *
+ * This is based on the ircu version, modified by nikb.
+ * StarChat servers MUST use throttling. The values can
+ * be changed, but shouldn't be without good reason.
+ *
+ * CHECK_CLONE_LIMIT is the number of clients from the
+ * same IP that will be allowed. The CHECK_CLONE_LIMIT + 1'th
+ * client in CHECK_CLONE_PERIOD seconds will be throttled,
+ * and a temp z-line put in place for CHECK_CLONE_DELAY seconds.
+ */
+#define THROTTLE
+#define CHECK_CLONE_LIMIT 3
+#define CHECK_CLONE_PERIOD 15
+#define CHECK_CLONE_DELAY 300
+
+/*
+ * 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
+
+/* 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
+
+/*
+ * Define your network service names here.
+ */
+#define ChanServ "ChanServ"
+#define MemoServ "MemoServ"
+#define NickServ "NickServ"
+#define OperServ "OperServ"
+#define WebServ "WebServ"
+
+/*
+ * End of StarChat Mandatory section
+ */
+
+/* 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 7000 /* 7000 for StarChat */
+
+/*
+ * 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 240 /* Recommended value: 4 minutes */
+#define HANGONGOODLINK 3600 /* Recommended value: 1 hour */
+
+/*
+ * 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 60 /* Recommended value: 60 */
+
+/*
+ * 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 */
+
+#endif /* __config_include__ */
+
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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__ */
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+/*
+ * "h.h". - Headers file.
+ *
+ * Most of the externs and prototypes thrown in here to 'cleanup' things.
+ * -avalon
+ */
+
+extern time_t nextconnect, nextdnscheck, nextping;
+extern aClient *client, me, *local[];
+extern aChannel *channel;
+extern struct stats *ircstp;
+extern int bootopt;
+/* Prototype added to force errors -- Barubary */
+extern time_t check_pings(time_t now, int check_kills);
+
+/* moved here to allow the server to generate new seeds on startup
+ InnerFIRE */
+
+#ifdef NOSPOOF
+extern u_int32_t NOSPOOF_SEED01, NOSPOOF_SEED02 ;
+#endif /* NOSPOOF*/
+
+#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 IP address instead\r\n"
+#define BREPORT_DO_ID "NOTICE AUTH :*** Checking ident...\r\n"
+#define BREPORT_FIN_ID "NOTICE AUTH :*** Received ident 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];
+
+extern int R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns,
+ R_do_id, R_fin_id, R_fail_id;
+
+extern aChannel *find_channel PROTO((char *, aChannel *));
+extern void remove_user_from_channel PROTO((aClient *, aChannel *));
+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 *));
+/* We're going to pass the msg text to can_send() for +c channelmode -Defiant */
+extern int can_send PROTO((aClient *, aChannel *, char *));
+extern int is_chan_op PROTO((aClient *, aChannel *));
+extern int has_voice PROTO((aClient *, aChannel *));
+extern int count_channels PROTO((aClient *));
+extern Ban *is_banned PROTO((aClient *, aChannel *));
+extern Ban *is_banexception PROTO((aClient *, aChannel *)) ;
+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 aJinxItem *jinx;
+extern aJinxItem *find_jinx_userhost PROTO((char *));
+extern aJinxItem *find_jinx_match PROTO((char *, 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_socksexception PROTO((aClient *));
+extern int find_dccblock PROTO((char *));
+extern int find_restrict PROTO((aClient *));
+extern int rehash PROTO((aClient *, aClient *, int));
+// fixme: this is used 2 diffrent ways depending on the file ?
+extern int initconf PROTO((int));
+// extern aConfItem *initconf();
+extern void add_temp_conf();
+extern void inittoken PROTO(());
+extern int do_channel_synch(char *);
+int synchmode;
+int SVSNOOP;
+extern void calc_mask(aClient *) ;
+char *return_host(aClient *, aClient *) ;
+char *return_oper_host(aClient *, aClient *) ;
+char *return_oper_mask (aClient *) ;
+
+/* Related to the z-line timer for SOCKS -taz */
+extern int socks_zline_time;
+extern aEvent *EventList;
+extern aEvent *make_event();
+extern aSynchList *SJSynchList;
+extern aSynchList *make_synchlist();
+extern void free_synchlist(aSynchList *);
+extern void free_event(aEvent *);
+extern void CheckEvents();
+extern void AddEvent();
+extern void RemoveZLine(char *);
+
+extern char *MyMalloc PROTO(()), *MyRealloc PROTO(()) ;
+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 *));
+
+extern int dbufalloc, dbufblocks, debuglevel, errno, h_errno;
+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(());
+extern int read_message PROTO((time_t));
+extern void report_error PROTO((char *, aClient *));
+extern void set_non_blocking PROTO((int, aClient *));
+extern int setup_ping PROTO(());
+extern int ping_server(aClient *, struct hostent *);
+extern void read_ping(aClient *);
+extern void send_ping(aClient *);
+extern void cancel_ping(aClient *, aClient *);
+extern void end_ping(aClient *);
+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 restart PROTO((char *));
+extern void send_channel_modes_sts PROTO((aClient *, aChannel *)); /* New StarChat STS1 resynch code */
+extern void server_reboot PROTO((char *));
+extern void terminate PROTO(()), write_pidfile PROTO(());
+
+extern int send_queued PROTO((aClient *));
+extern void sendto_one();
+extern void sendto_channelops_butone();
+extern void sendto_channelvoice_butone();
+extern void sendto_serv_butone();
+extern void sendto_SNICK_butone();
+extern void sendto_serv_butone_quit();
+extern void sendto_common_channels();
+extern void sendto_channel_butserv();
+extern void sendto_match_servs();
+extern void sendto_match_butone();
+extern void sendto_all_butone();
+extern void sendto_ops();
+extern void sendto_ops_butone();
+extern void sendto_ops_butme();
+extern void sendto_prefix_one();
+extern void sendto_failops_whoare_opers();
+extern void sendto_realops();
+extern void sendto_locfailops();
+extern void sendto_failops();
+extern void sendto_opers();
+extern void sendto_umode();
+
+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 char *hideme PROTO((aClient *, aClient *));
+extern char *maskme PROTO((char *, int));
+extern char *maskmenow PROTO((aClient *, aClient*));
+
+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 aJinxItem *make_jinx 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 int IsMember PROTO((aClient *, 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 int res_init();
+extern u_long cres_mem(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 *));
+
+#ifdef ZIP_LINKS
+extern int zip_init (aClient *);
+extern void zip_free (aClient *);
+extern char *unzip_packet (aClient *, char *, int *);
+extern char *zip_buffer (aClient *, char *, int *, int);
+#endif
+
+
+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 aClient *find_server_wildcard PROTO((char *));
+
+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));
+
+void count_memory(aClient *, char *);
+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
+extern void get_max_users(void);
+extern void strip_trailing_spaces(char *) ;
+
+/* From channel.c */
+extern void send_list(aClient *, int);
+
+extern void serv_info(aClient *, char *);
+extern int str2array(char **, char *, char *);
+extern void CheckBandwidth(void);
+int max_connection_count, max_client_count;
+long max_sendqs,max_recvqs;
+extern int find_services(void);
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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__ */
--- /dev/null
+/*
+ * 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.
+ *
+ * @(#)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__
+extern __u_l inet_addr(char *);
+extern char *inet_ntoa(char *);
+extern __u_l inet_netof (struct in_addr);
+extern __u_l inet_makeaddr(int , int);
+extern __u_l inet_network(char *);
+extern __u_l inet_lnaof(struct in_addr);
+#else
+extern __u_l inet_addr();
+extern char *inet_ntoa();
+#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
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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
+ */
+
+ /* When tokens are all used we'll continue with AA etc. - GZ */
+
+#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_STATS "STATS" /* STAT */
+#define TOK_STATS "2" /* 50 */
+#define MSG_HELP "HELP" /* 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_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_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_SVSMODE "SVSMODE" /* SVSMODE */
+#define TOK_SVSMODE "n" /* 109 */
+#define MSG_SAMODE "SAMODE" /* SAMODE */
+#define TOK_SAMODE "o" /* 110 */
+#define MSG_ZLINE "ZLINE" /* ZLINE */
+#define TOK_ZLINE "q" /* 112 */
+#define MSG_UNZLINE "UNZLINE" /* UNZLINE */
+#define TOK_UNZLINE "r" /* 113 */
+#define MSG_OPERMOTD "OPERMOTD" /* OPERMOTD */
+#define TOK_OPERMOTD "s" /* 114 */
+#define MSG_JINX "JINX" /* JINX */
+#define TOK_JINX "t" /* 115 */
+#define MSG_UNJINX "UNJINX" /* UNJINX */
+#define TOK_UNJINX "u" /* 116 */
+#define MSG_RPING "RPING" /* RPING */
+#define TOK_RPING "v" /* 117 */
+#define MSG_RPONG "RPONG" /* RPONG */
+#define TOK_RPONG "w" /* 118 */
+#define MSG_UPING "UPING" /* UPING */
+#define TOK_UPING "x" /* 119 */
+#define MSG_MAP "MAP" /* MAP */
+#define TOK_MAP "{" /* 122 */
+#define MSG_SJOIN "SJOIN" /* SJOIN */
+#define TOK_SJOIN "|" /* 123 */
+#define MSG_SNICK "SNICK" /* SNICK */
+#define TOK_SNICK "}" /* 124 */
+#define MSG_KNOCK "KNOCK" /* KNOCK */
+#define TOK_KNOCK "~" /* 125 */
+#define MSG_MKILL "MKILL" /* MKILL */
+#define TOK_MKILL "=" /* 126 */
+#define MSG_GLINE "GLINE" /* GLINE */
+#define TOK_GLINE "1" /* 127 */
+/** We are running out of 8bit tokens. We'll switch to 16bit
+ ** tokens from here. -GZ
+ **/
+#define MSG_SVSJOIN "SVSJOIN" /* SVSJOIN */
+#define TOK_SVSJOIN "!!" /* 8481 */
+#define MSG_SVSPART "SVSPART" /* SVSPART */
+#define TOK_SVSPART "!\"" /* 8482 */
+#define MSG_AKILLEX "AKILLEX" /* AKILLEX */
+#define TOK_AKILLEX "!#" /* 8483 */
+#define MSG_RAKILLEX "RAKILLEX" /* RAKILLEX */
+#define TOK_RAKILLEX "!$" /* 8484 */
+
+#define MAXPARA 15
+
+extern int m_private(), m_topic(), m_join(), m_part(), m_mode(), m_svsmode();
+extern int m_ping(), m_pong(), 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_akillex(), m_rakillex(), m_zline(), m_unzline();
+extern int m_gnotice(), m_goper(), m_globops(), m_locops(), m_unsqline();
+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_stats();
+extern int m_version(), m_help();
+extern int m_nickserv(), m_operserv(), m_chanserv(), m_memoserv(), m_services(), m_identify();
+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_userhost(), m_ison(), m_watch();
+extern int m_rehash(), m_restart(), m_die(), m_dns(), m_hash();
+extern int m_noshortn(),m_noshortc(),m_noshortm(),m_noshorto();
+extern int m_opermotd(),m_jinx(),m_unjinx();
+extern int m_rping(), m_rpong(), m_uping();
+extern int m_knock(), m_sjoin(), m_snick();
+extern int m_map(), m_mkill();
+extern int m_svsjoin(), m_svspart();
+
+#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_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_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_chanserv, 0, 1, 1, TOK_CHANSERV,0L },
+ { MSG_NICKSERV,m_nickserv, 0, 1, 1, TOK_NICKSERV,0L },
+ { MSG_NS, m_nickserv, 0, 1, 1, TOK_NICKSERV,0L },
+ { MSG_OPERSERV,m_operserv, 0, 1, 1, TOK_OPERSERV,0L },
+ { MSG_OS, m_operserv, 0, 1, 1, TOK_OPERSERV,0L },
+ { MSG_MEMOSERV,m_memoserv, 0, 1, 1, TOK_MEMOSERV,0L },
+ { MSG_MS, m_memoserv, 0, 1, 1, TOK_MEMOSERV,0L },
+ { MSG_IDENTIFY,m_identify, 0, 1, 1, TOK_IDENTIFY,0L },
+ { MSG_HELP, 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_LOCOPS, m_locops, 0, 1, 1, TOK_LOCOPS, 0L },
+#undef USE_SERVICES
+ { 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_OPERMOTD, m_opermotd, 0, MAXPARA, 1, TOK_OPERMOTD, 0L },
+ { MSG_JINX, m_jinx, 0, MAXPARA, 1, TOK_JINX, 0L },
+ { MSG_UNJINX, m_unjinx, 0, MAXPARA, 1, TOK_UNJINX, 0L },
+ { MSG_RPING, m_rping, 0, MAXPARA, 1, TOK_RPING, 0L },
+ { MSG_RPONG, m_rpong, 0, MAXPARA, 1, TOK_RPONG, 0L },
+ { MSG_UPING, m_uping, 0, MAXPARA, 1, TOK_UPING, 0L },
+ { MSG_SJOIN, m_sjoin, 0, MAXPARA, 1, TOK_SJOIN, 0L },
+ { MSG_SNICK, m_snick, 0, MAXPARA, 1, TOK_SNICK, 0L },
+ { MSG_KNOCK, m_knock, 0, MAXPARA, 1, TOK_KNOCK, 0L },
+ { MSG_MAP, m_map, 0, MAXPARA, 1, TOK_MAP, 0L },
+ { MSG_MKILL, m_mkill, 0, MAXPARA, 1, TOK_MKILL, 0L },
+ { MSG_SVSJOIN, m_svsjoin, 0, MAXPARA, 1, TOK_SVSJOIN, 0L },
+ { MSG_SVSPART, m_svspart, 0, MAXPARA, 1, TOK_SVSPART, 0L },
+ { MSG_AKILLEX, m_akillex, 0, MAXPARA, 1, TOK_AKILLEX, 0L },
+ { MSG_RAKILLEX, m_rakillex, 0, MAXPARA, 1, TOK_RAKILLEX, 0L },
+ { (char *) 0, (int (*)()) 0 , 0, 0, 0, {0}, 0L}
+};
+#else
+extern struct Message msgtab[];
+extern struct Message *msgmap[256];
+#endif
+#endif /* __msg_include__ */
--- /dev/null
+/*
+ * 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.
+ *
+ * @(#)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)
+#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); \
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+/*
+ * Reserve numerics 000-099 for server-client connections where the client
+ * is local to the server. If any server is passed a numeric in this range
+ * from another server then it is remapped to 100-199. -avalon
+ */
+#define RPL_WELCOME 001
+#define RPL_YOURHOST 002
+#define RPL_CREATED 003
+#define RPL_MYINFO 004
+#define RPL_PROTOCTL 005
+#define RPL_MAP 006
+#define RPL_MAPEND 007
+
+/*
+ * 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_CANNOTKNOCK 410
+#define ERR_NORECIPIENT 411
+#define ERR_NOTEXTTOSEND 412
+#define ERR_NOTOPLEVEL 413
+#define ERR_WILDTOPLEVEL 414
+#define ERR_SERVICESUP 415
+
+#define ERR_UNKNOWNCOMMAND 421
+#define ERR_NOMOTD 422
+#define ERR_NOADMININFO 423
+#define ERR_FILEERROR 424
+
+#define ERR_NONICKNAMEGIVEN 431
+#define ERR_ERRONEUSNICKNAME 432
+#define ERR_NICKNAMEINUSE 433
+#define ERR_SERVICENAMEINUSE 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_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_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_NEEDREGGEDNICKTOMSG 479
+#define ERR_NOPRIVILEGES 481
+#define ERR_CHANOPRIVSNEEDED 482
+#define ERR_CANTKILLSERVER 483
+#define ERR_ISROOT 484 /* Undernet extension was ERR_ISCHANSERVICE */
+
+
+#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_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_WHOISADMIN 308 /* redundant due to dreamforge changes in /whois reply */
+#define RPL_WHOISSADMIN 309 /* shall we remove these? They're not doing anything */
+#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_WHOISCONNECTION 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_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_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_EXBANLIST 379
+#define RPL_EXBANLISTEND 380
+
+#define RPL_YOUREOPER 381
+#define RPL_REHASHING 382
+#define RPL_YOURESERVICE 383
+#define RPL_MYPORTIS 384
+#define RPL_NOTOPERANYMORE 385
+
+#define RPL_HOSTRESTRICTLIST 386
+#define RPL_HOSTRESTRICTLISTEND 387
+
+#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
+/* Related to SOCKS zline timer -taz */
+#define RPL_STATSFLINE 223
+
+#define RPL_SERVICEINFO 231
+#define RPL_ENDOFSERVICES 232
+#define RPL_SERVICE 233
+#define RPL_SERVLIST 234
+#define RPL_SERVLISTEND 235
+#define RPL_JINX 236
+#define RPL_STATSJINX 237
+#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
+
+/*
+ * 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_WATCHCLEAR 608
+
+#define RPL_OMOTDSTART 609
+#define RPL_OMOTD 610
+#define RPL_ENDOFOMOTD 611
+#define RPL_WHOWASIP 612
+#define RPL_STATSGZLINE 613
+#define RPL_WHOISMODES 614
+#define RPL_MAPMORE 615
+#define RPL_POLICY 616
+#define ERR_HTCTOOFAST 617
+#define ERR_NEEDIDTODCC 618
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, include/patchlevel.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 1, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * PATCHes
+ *
+ * Only put here ADDED special stuff, for instance: ".mu3" or ".ban"
+ * Please start the patchlevel with a '.'
+ *
+ * IMPORTANT: We've copied the patch-scheme from u2.9, note the new
+ * format - it isn't neccessary to edit this manually !!!
+ * If you do, be sure you know what you are doing!
+ *
+ * For patch developers:
+ * To make a diff of your patch, edit any of the below lines containing
+ * a "" (an EMPTY string). Your patch will then succeed, with only an
+ * offset, on the first empty place in the users patchlevel.h.
+ * Do not change anyother line, the '\' are to make sure that the 'fuzz'
+ * will stay 0. --Run
+ *
+ */
+
+#define PATCH1 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH2 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH3 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH4 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH5 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH6 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH7 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#define PATCH8 \
+ \
+ \
+ \
+ ""
+
+/*
+ * Deliberate empty lines
+ */
+
+#ifdef DEBUGMODE
+#define PATCH9 ".debug"
+#else
+#define PATCH9 ""
+#endif
+
+/*
+ * Deliberate empty lines
+ */
+
--- /dev/null
+/*
+ * irc2.7.2/ircd/res.h (C)opyright 1992 Darren Reed.
+ */
+#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;
+#ifdef __alpha
+ u_int ttl; /* time to live */
+#else
+ u_long ttl; /* time to live */
+#endif
+ 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;
+ struct hent he;
+ } ResRQ;
+
+typedef struct cache {
+ time_t expireat;
+ time_t ttl;
+ struct hostent he;
+ 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__ */
--- /dev/null
+/*
+ * 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.
+ *
+ * @(#)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();
+
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+/*
+ * 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
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#ifndef __struct_include__
+#define __struct_include__
+
+#include "config.h" /* Get SEEUSERSTATS */
+#include "common.h"
+#include "sys.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifdef HAVE_STDDEF_H
+# include <stddef.h>
+#endif
+
+#ifdef USE_SYSLOG
+# include <syslog.h>
+#ifdef HAVE_SYSSYSLOG_H
+# include <sys/syslog.h>
+# endif
+#endif
+#ifdef pyr
+#include <sys/time.h>
+#endif
+
+typedef struct SqlineItem aSqlineItem;
+typedef struct JinxItem aJinxItem;
+typedef struct ConfItem aConfItem;
+typedef struct Notify aNotify;
+typedef struct Client aClient;
+/* Related to SOCKS zline timer -taz */
+typedef struct Event aEvent;
+typedef struct SynchList aSynchList;
+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 CloneItem aClone;
+
+#ifdef ZIP_LINKS
+typedef struct Zdata aZdata;
+#include <zlib.h>
+#endif
+
+#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 ARGLEN 132 /* Argument length for events -taz */
+#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 BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */
+#define MAXRECIPIENTS 20
+#define MAXKILLS 20
+#define MAXBANS 60
+#define MAXBANLENGTH 1024
+#define MAXSILES 5
+#define MAXSILELENGTH 128
+
+#define READBUF_SIZE 32000
+
+/*
+ * 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_PING -7 /* for UPING -GZ */
+#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 */
+
+/* This is where we are defining server capabilities from now on -GZ */
+
+#define VERSION_STAR5II 0x00000001
+/* When all servers >= Star5.19 this can be pulled */
+
+#define VERSION_ZIPLINKS 0x00000002
+
+#ifdef ZIP_LINKS
+#define VERSION_SEND (VERSION_STAR5II|VERSION_ZIPLINKS)
+#else
+#define VERSION_SEND (VERSION_STAR5II)
+#endif
+/*
+ * 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_AVAILABLE 0x1000 */
+/* #define FLAGS_AVAILABLE 0x2000 */
+#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 /* UPING SENT */
+#define FLAGS_ASKEDPING 0x100000 /* UPONG GOT*/
+
+//#define FLAGS_SJOIN 0x1000000 /* have SJOIN */
+#define FLAGS_MAP 0x2000000 /* Show this entry in /map */
+#define FLAGS_JOINING 0x4000000 /* Prevent user from getting killed during JOIN */
+//#define FLAGS_SNICK 0x8000000 /* have SNICK */
+
+/* Need more flags - here's flags2 */
+
+#define FLAGS2_HTC 0x00000001 /* Protect a user from getting killed with dead socket */
+
+/* Dec 26th, 1997 - having a go at
+ * splitting flags into flags and umodes
+ * -DuffJ
+ */
+#define FLAGS2_ZIP 0x00000002
+#define FLAGS2_ZIPFIRST 0x00000004
+#define FLAGS2_CAPAB_ZIP 0x00000008
+#define FLAGS2_CBURST 0x00000010
+
+#define UMODE_INVISIBLE 0x0001 /* makes user invisible */
+#define UMODE_OPER 0x0002 /* Operator */
+#define UMODE_WEBTV 0x0004 /* WebTV user */
+#define UMODE_FAILOP 0x0008 /* Shows some global messages */
+/* mode 0x0010 available */
+#define UMODE_REGMSGONLY 0x0020 /* Only registered users may message */
+
+#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 */
+
+/* Related to SEEUSERSTATS -Studded */
+#define UMODE_STATS 0x4000 /* Receive notice when users do /stats, et al */
+#define UMODE_HIDE 0x8000 /* Admin,Oper usermask-hiding */
+#define UMODE_WHOIS 0x10000 /* See USERHOST,WHOIS */
+#define UMODE_NETADMIN 0x20000 /* Network Admin */
+#define UMODE_SROOT 0x40000 /* Services Root */
+#define UMODE_IDENTIFY 0x80000 /* Identified */
+#define SEND_UMODES (UMODE_INVISIBLE|UMODE_OPER|UMODE_WEBTV|UMODE_FAILOP|UMODE_SADMIN|UMODE_ADMIN|UMODE_HIDE|UMODE_WHOIS|UMODE_NETADMIN|UMODE_SROOT|UMODE_IDENTIFY|UMODE_REGMSGONLY)
+#define ALL_UMODES (SEND_UMODES|UMODE_SERVNOTICE|UMODE_LOCOP|UMODE_KILLS|UMODE_CLIENT|UMODE_FLOOD|UMODE_STATS)
+#define FLAGS_ID (FLAGS_DOID|FLAGS_GOTID)
+
+#define PROTO_NOQUIT 0x1 /* Negotiated NOQUIT protocol */
+#define PROTO_TOKEN 0x2 /* Negotiated TOKEN protocol */
+
+/*
+ * flags macros.
+ */
+#ifdef SEEUSERSTATS
+#define IsStatsF(x) ((x)->umodes & UMODE_STATS)
+#else
+#define IsStatsF(x) (0)
+#endif
+#define IsKillsF(x) ((x)->umodes & UMODE_KILLS)
+#define IsClientF(x) ((x)->umodes & UMODE_CLIENT)
+#define IsFloodF(x) ((x)->umodes & UMODE_FLOOD)
+#define IsAdmin(x) ((x)->umodes & UMODE_ADMIN)
+#define IsSAdmin(x) ((x)->umodes & UMODE_SADMIN)
+#define IsSRoot(x) ((x)->umodes & UMODE_SROOT)
+#define IsNetAdmin(x) ((x)->umodes & UMODE_NETADMIN)
+
+#define SendFailops(x) ((x)->umodes & UMODE_FAILOP)
+#define IsHidden(x) ((x)->umodes & UMODE_HIDE)
+#define AcceptsRegisteredOnly(x) ((x)->umodes & UMODE_REGMSGONLY)
+#define IsWmode(x) ((x)->umodes & UMODE_WHOIS)
+#define IsOper(x) ((x)->umodes & UMODE_OPER)
+#define IsLocOp(x) ((x)->umodes & UMODE_LOCOP)
+#define IsInvisible(x) ((x)->umodes & UMODE_INVISIBLE)
+#define IsAnOper(x) ((x)->umodes & (UMODE_OPER|UMODE_LOCOP))
+#define IsIdentified(x) ((x)->umodes & UMODE_IDENTIFY)
+#define IsPerson(x) ((x)->user && IsClient(x))
+#define IsPrivileged(x) (IsAnOper(x) || IsServer(x))
+#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 GotCapab(x) ((x)->flags & FLAGS_GOTCAPAB)
+#ifdef NOSPOOF
+#define IsNotSpoof(x) ((x)->nospoof == 0)
+#else
+#define IsNotSpoof(x) (1)
+#endif
+
+#ifdef SEEUSERSTATS
+#define SetStatsF(x) ((x)->umodes |= UMODE_STATS)
+#endif
+#define SetKillsF(x) ((x)->umodes |= UMODE_KILLS)
+#define SetClientF(x) ((x)->umodes |= UMODE_CLIENT)
+#define SetFloodF(x) ((x)->umodes |= UMODE_FLOOD)
+#define SetHidden(x) ((x)->umodes |= UMODE_HIDE)
+#define SetIdentified(x) ((x)->umodes |= UMODE_IDENTIFY)
+#define SetOper(x) ((x)->umodes |= UMODE_OPER)
+#define SetLocOp(x) ((x)->umodes |= UMODE_LOCOP)
+#define SetInvisible(x) ((x)->umodes |= UMODE_INVISIBLE)
+#define SetWmode(x) ((x)->umodes |= UMODE_WHOIS)
+#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 SetHaveSJOIN(x) ((x)->flags |= FLAGS_SJOIN)
+#define SetHaveSNICK(x) ((x)->flags |= FLAGS_SNICK)
+#define SetCapab(x) ((x)->flags |= FLAGS_GOTCAPAB)
+#define DoingAuth(x) ((x)->flags & FLAGS_AUTH)
+
+#define NoNewLine(x) ((x)->flags & FLAGS_NONL)
+
+#ifdef SEEUSERSTATS
+#define ClearStatsF(x) ((x)->umodes &= ~UMODE_STATS)
+#endif
+#define ClearAdmin(x) ((x)->umodes &= ~UMODE_ADMIN)
+#define ClearSAdmin(x) ((x)->umodes &= ~UMODE_SADMIN)
+#define ClearSRoot(x) ((x)->umodes &= ~UMODE_SROOT)
+#define ClearNetAdmin(x) ((x)->umodes &= ~UMODE_NETADMIN)
+
+#define ClearKillsF(x) ((x)->umodes &= ~UMODE_KILLS)
+#define ClearClientF(x) ((x)->umodes &= ~UMODE_CLIENT)
+#define ClearFloodF(x) ((x)->umodes &= ~UMODE_FLOOD)
+#define ClearFailops(x) ((x)->umodes &= ~UMODE_FAILOP)
+#define ClearHidden(x) ((x)->umodes &= ~UMODE_HIDE)
+#define ClearIdentified(x) ((x)->umodes &= ~UMODE_IDENTIFY)
+#define ClearWmode(x) ((x)->umodes &= ~UMODE_WHOIS)
+#define ClearOper(x) ((x)->umodes &= ~UMODE_OPER)
+#define ClearInvisible(x) ((x)->umodes &= ~UMODE_INVISIBLE)
+#define ClearDNS(x) ((x)->flags &= ~FLAGS_DOINGDNS)
+#define ClearAuth(x) ((x)->flags &= ~FLAGS_AUTH)
+#define ClearHaveSJOIN(x) ((x)->flags &= ~FLAGS_SJOIN)
+#define ClearHaveSNICK(x) ((x)->flags &= ~FLAGS_SNICK)
+#define ClearCapab(x) ((x)->flags &= ~FLAGS_GOTCAPAB)
+
+#define ClearAccess(x) ((x)->flags &= ~FLAGS_CHKACCESS)
+#define ClearBlocked(x) ((x)->flags &= ~FLAGS_BLOCKED)
+
+/*
+ * ProtoCtl options
+ */
+#define DontSendQuit(x) ((x)->proto & PROTO_NOQUIT)
+#define IsToken(x) ((x)->proto & PROTO_TOKEN)
+
+#define SetNoQuit(x) ((x)->proto |= PROTO_NOQUIT)
+#define SetToken(x) ((x)->proto |= PROTO_TOKEN)
+
+#define ClearNoQuit(x) ((x)->proto &= ~PROTO_NOQUIT)
+#define ClearToken(x) ((x)->proto &= ~PROTO_TOKEN)
+
+
+#define MaskHost(x) ((x)->user->mask)
+#define IsJinxed(x) ((x)->jinx)
+#define SetJinx(x) ((x)->jinx = 1)
+#define ClearJinx(x) ((x)->jinx = 0)
+/*
+ * 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 */
+
+/* 0x00000010 available */
+
+#define OFLAG_GLOBOP 0x00000020 /* Oper can send /GlobOps */
+#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_SADMIN 0x00080000 /* Oper can be a services admin */
+#define OFLAG_ZLINE 0x00100000 /* Oper can use /zline and /unzline */
+
+#define OFLAG_LOCAL (OFLAG_REHASH|OFLAG_GLOBOP|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 OPCanRehash(x) ((x)->oflag & OFLAG_REHASH)
+#define OPCanDie(x) ((x)->oflag & OFLAG_DIE)
+#define OPCanRestart(x) ((x)->oflag & OFLAG_RESTART)
+#define OPCanGlobOps(x) ((x)->oflag & OFLAG_GLOBOP)
+#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 OPCanUModeC(x) ((x)->oflag & OFLAG_UMODEC)
+#define OPCanUModeF(x) ((x)->oflag & OFLAG_UMODEF)
+
+#define OPSetRehash(x) ((x)->oflag |= OFLAG_REHASH)
+#define OPSetDie(x) ((x)->oflag |= OFLAG_DIE)
+#define OPSetRestart(x) ((x)->oflag |= OFLAG_RESTART)
+#define OPSetGlobOps(x) ((x)->oflag |= OFLAG_GLOBOP)
+#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 OPSetUModeC(x) ((x)->oflag |= OFLAG_UMODEC)
+#define OPSetUModeF(x) ((x)->oflag |= OFLAG_UMODEF)
+#define OPSetZLine(x) ((x)->oflag |= OFLAG_ZLINE)
+
+#define OPClearRehash(x) ((x)->oflag &= ~OFLAG_REHASH)
+#define OPClearDie(x) ((x)->oflag &= ~OFLAG_DIE)
+#define OPClearRestart(x) ((x)->oflag &= ~OFLAG_RESTART)
+#define OPClearGlobOps(x) ((x)->oflag &= ~OFLAG_GLOBOP)
+#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 OPClearAdmin(x) ((x)->oflag &= ~OFLAG_ADMIN)
+#define OPClearSAdmin(x) ((x)->oflag &= ~OFLAG_SADMIN)
+#define OPClearUModeC(x) ((x)->oflag &= ~OFLAG_UMODEC)
+#define OPClearUModeF(x) ((x)->oflag &= ~OFLAG_UMODEF)
+#define OPClearZLine(x) ((x)->oflag &= ~OFLAG_ZLINE)
+
+/*
+ * 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 */
+
+/*
+ * UPING Start
+ */
+
+#define ClearPing(x) ((x)->flags &= ~FLAGS_PING)
+#define ClearAskedPing(x) ((x)->flags &= ~FLAGS_ASKEDPING)
+#define SetAskedPing(x) ((x)->flags |= FLAGS_ASKEDPING)
+#define AskedPing(x) ((x)->flags & FLAGS_ASKEDPING)
+#define DoPing(x) ((x)->flags & FLAGS_PING)
+#define IsPing(x) ((x)->status == STAT_PING)
+#define SetPing(x) ((x)->status = STAT_PING)
+
+/*
+ * 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
+#define CONF_CLASS 0x0400
+#define CONF_SERVICE 0x0800
+/* #define CONF_AVAILABLE 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_AVAILABLE 0x200000 */
+/* #define CONF_AVAILABLE 0x400000 */
+#define CONF_MISSING 0x800000
+#define CONF_SADMIN 0x1000000
+#define CONF_DRPASS 0x2000000 /* DIE/RESTART pass - NikB */
+#define CONF_ZTIME 0x4000000 /* zline timer -taz */
+#define CONF_NZCONNECT_SERVER 0x8000000
+/* #define CONF_AVAILABLE 0x10000000 */
+#define CONF_DCCBLOCK 0x20000000 /* Blocking of specific DCC transfers */
+#define CONF_KILLEXEMPT 0x40000000 /* Exemption of K-Line */
+
+#define CONF_OPS (CONF_OPERATOR | CONF_LOCOP)
+#define CONF_SERVER_MASK (CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER| \
+ CONF_NZCONNECT_SERVER)
+#define CONF_CLIENT_MASK (CONF_CLIENT | CONF_SERVICE | CONF_OPS | \
+ CONF_SERVER_MASK)
+#define CONF_QUARANTINE (CONF_QUARANTINED_SERVER|CONF_QUARANTINED_NICK)
+
+#define IsIllegal(x) ((x)->status & CONF_ILLEGAL)
+#define IsTemp(x) ((x)->tmpconf)
+
+/* jinx structures */
+struct JinxItem {
+ unsigned int status;
+ char *userhost;
+ char *reason;
+ struct JinxItem *next;
+};
+
+#ifdef ZIP_LINKS
+
+#define ZIP_MINIMUM 4096
+#define ZIP_MAXIMUM 8192
+
+
+struct Zdata {
+ z_stream *in; /* input zip stream data */
+ z_stream *out; /* output zip stream data */
+ char inbuf[ZIP_MAXIMUM]; /* incoming zipped buffer */
+ char outbuf[ZIP_MAXIMUM]; /* outgoing (unzipped) buffer */
+ int incount; /* size of inbuf content */
+ int outcount; /* size of outbuf content */
+};
+#endif
+
+/*
+ * 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 host[HOSTLEN+1];
+ char mask[HOSTLEN+1];
+ char server[HOSTLEN+1];
+// char hidden[5]; /* Used for /whowas masking -GZ */
+ /*
+ ** In a perfect world the 'server' name
+ ** should not be needed, a pointer to the
+ ** client describing the server is enough.
+ ** Unfortunately, in reality, server may
+ ** not yet be in links while USER is
+ ** introduced... --msa
+ ** No. We are going to assume the server
+ ** is there. There is no good reason at
+ ** all that we should get a NICK line
+ ** before a SERVER line. -- Aeto
+ ** BUT, it is hiddenin aClient! -- Aeto
+ */
+#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 */
+#ifdef LIST_DEBUG
+ aClient *bcptr;
+#endif
+};
+
+/* SJOIN synch structure */
+struct SynchList {
+ char nick[NICKLEN];
+ int deop;
+ int devoice;
+ int op;
+ int voice;
+ aSynchList *next, *prev;
+};
+
+/* Related to zline timer for SOCKS -taz */
+struct Event {
+ void (*func)(char *);
+ char arg[ARGLEN+1];
+ u_int32_t exectime;
+ aEvent *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;
+#ifdef USE_SERVICES
+ aService *service;
+#endif
+ int hashv; /* raw hash value (according to ircu) -- was
+ * added so that UPING would work. Dreamforge
+ * 4.6.7b Not needed in b ? I dunno they said so.
+ */
+ 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 */
+ time_t lasthtc; /* Time the user used a high traffic command for the last time */
+ int htccount; /* Counter for HTC commands */
+ int htcignore; /* flag for HTC ignore on/off */
+ u_char targets[MAXTARGETS]; /* Hash values of current targets */
+ long flags; /* client flags */
+ long flags2; /* more 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 */
+ 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 version[REALLEN+1]; /* version of the client (servers only) -GZ */
+ int jinx; /* Tag for jinx */
+ int cc; /* Cline client-check for connect -GZ */
+// char hidden[5]; /* Used for /whowas masking -GZ */
+ 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 */
+ char sup_server[HOSTLEN+1], sup_host[HOSTLEN+1];
+ 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 */
+ long receiveK; /* Statistics: total k-bytes received */
+ long u_receiveK; /* Statistics: Uncompressed lengths */
+ long u_sendK;
+ u_short u_sendB;
+ u_short u_receiveB;
+ long previousSQK; /* Statistics: used for bandwith-meter */
+ long previousRQK; /* Statistics: used for bandwith-meter */
+ long deltaSQK; /* Statistics: used for bandwith-meter */
+ long deltaRQK; /* Statistics: used for bandwith-meter - GZ */
+ u_short sendB; /* counters to count upto 1-k lots of bytes */
+ long connectQ; /* The count of bytes sent during connect */
+ u_short receiveB; /* sent and received. */
+ aClient *acpt; /* listening client which we accepted from */
+ Link *confs; /* Configuration record associated */
+#ifdef ZIP_LINKS
+ aZdata *zip;
+#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_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 {
+ unsigned int mode;
+ int limit;
+ char key[KEYLEN+1];
+};
+
+/* 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;
+ union {
+ aClient *cptr;
+ aChannel *chptr;
+ aConfItem *aconf;
+ aNotify *nptr;
+ aName *whowas;
+ char *cp;
+ } value;
+};
+
+struct SBan {
+ struct SBan *next;
+ char *banstr;
+ char *who;
+ time_t when;
+};
+
+/* 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;
+ Ban *banlist;
+ Ban *exbanlist;
+ Ban *hostrestrictlist;
+ char chname[1];
+};
+
+#define CAP_ZIP 0x0001
+
+#define IsCapable(x, cap) ((x)->caps & (cap))
+#define SetCapable(x, cap) ((x)->caps |= (cap))
+#define ClearCap(x, cap) ((x)->caps &= ~(cap))
+
+/*
+** 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_OVERLAP (CHFL_CHANOP|CHFL_VOICE)
+
+/* Channel Visibility macros */
+
+#define MODE_CHANOP CHFL_CHANOP
+#define MODE_VOICE CHFL_VOICE
+#define MODE_SECRET 0x0008
+#define MODE_MODERATED 0x0010
+#define MODE_TOPICLIMIT 0x0020
+#define MODE_INVITEONLY 0x0040
+#define MODE_NOPRIVMSGS 0x0080
+#define MODE_KEY 0x0100
+#define MODE_BAN 0x0200
+#define MODE_LIMIT 0x0400
+#define MODE_RGSTR 0x0800
+#define MODE_RGSTRONLY 0x1000
+/* Colour-removing mode -Defiant */
+#define MODE_NOCOLORS 0x2000
+#define MODE_HOSTRESTRICT 0x4000
+#define MODE_EXBAN 0x8000
+/*
+ * mode flags which take another parameter (With PARAmeterS)
+ */
+#define MODE_WPARAS (MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_EXBAN|MODE_HOSTRESTRICT|MODE_KEY|MODE_LIMIT)
+/*
+ * Undefined here, these are used in conjunction with the above modes in
+ * the source.
+#define MODE_DEL 0x40000000
+#define MODE_ADD 0x80000000
+ */
+
+#define HoldChannel(x) (!(x))
+/* name invisible */
+#define SecretChannel(x) ((x) && ((x)->mode.mode & MODE_SECRET))
+/* channel visible */
+#define ShowChannel(v,c) (PubChannel(c) || IsSAdmin(v) || IsMember((v),(c)))
+#define PubChannel(x) ((!x) || ((x)->mode.mode &\
+ (MODE_SECRET)) == 0)
+
+#define IsChannelName(name) ((name) && ((*(name) == '#') || (*(name) == '&') || ((*(name) == '+') && (*(name + 1) != '#'))))
+#define IsModelessChannel(name) ((name) && (*(name) == '+'))
+
+/* 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))
+
+/* 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
+#define ASYNC_PING 4 /* for UPING */
+
+/* misc variable externs */
+
+extern char *version, *infotext[];
+extern char *generation, *creation;
+
+/* misc defines */
+
+#define FLUSH_BUFFER -2
+#define UTMP "/etc/utmp"
+#define COMMA ","
+
+/* IRC client structures */
+
+#define UDPPORT "7007" /* For UPING */
+
+struct DSlink {
+ struct DSlink *next;
+ struct DSlink *prev;
+ union {
+ aClient *cptr;
+ struct Channel *chptr;
+ struct ConfItem *aconf;
+ char *cp;
+ } value;
+};
+
+#endif /* __struct_include__ */
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef __sys_include__
+#define __sys_include__
+#ifdef ISC202
+#include <net/errno.h>
+#else
+#include <sys/errno.h>
+#endif
+
+#include "setup.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+
+#ifndef HAVE_STRCASECMP
+#define strcasecmp mycmp
+#endif
+#ifndef HAVE_INDEX
+#define index strchr
+#define rindex strrchr
+/*
+extern char *index PROTO((char *, char));
+extern char *rindex PROTO((char *, char));
+*/
+#endif
+
+#ifndef HAVE_BZERO
+#define bzero(a,b) memset(a,0,b)
+#define bcopy(a,b,c) memcpy(b,a,c)
+#define bcmp memcmp
+#endif
+
+#ifdef HAVE_GETRUSAGE_2
+# define GETRUSAGE_2
+#else
+# ifdef HAVE_TIMES_2
+# define TIMES_2
+# endif /* HAVE_TIMES_2 */
+#endif /* GETRUSAGE_2 */
+
+#ifdef HAVE_POSIX_NBLOCK
+# define NBLOCK_POSIX
+#else /* HAVE_POSIX_NBLOCK */
+# ifdef HAVE_BSD_NBLOCK
+# define NBLOCK_BSD
+# else
+# define NBLOCK_SYSV
+# endif /* HAVE_BSD_NBLOCK */
+#endif /* HAVE_POSIX_NBLOCK */
+
+#ifdef HAVE_POSIX_SIGNALS
+# define POSIX_SIGNALS
+#else
+# ifdef HAVE_BSD_SIGNALS
+# define BSD_RELIABLE_SIGNALS
+# else
+# define SYSV_UNRELIABLE_SIGNALS
+# endif /* HAVE_BSD_SIGNALS */
+#endif /* HAVE_POSIX_SIGNALS */
+
+#ifdef AIX
+# include <sys/select.h>
+# include <sys/machine.h>
+# define BSD_INCLUDES
+# if BYTE_ORDER == BIG_ENDIAN
+# define BIT_ZERO_ON_LEFT
+# endif
+# if BYTE_ORDER == LITTLE_ENDIAN
+# define BIT_ZERO_ON_RIGHT
+# endif
+#endif
+
+
+#ifdef __hpux
+#define HPUX
+#endif
+
+
+#if defined(HPUX )|| defined(AIX)
+#include <time.h>
+#ifdef AIX
+#include <sys/time.h>
+#endif
+#else
+#include <sys/time.h>
+#endif
+
+#if !defined(DEBUGMODE)
+# define MyFree(x) if ((x) != NULL) free(x)
+#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
+
+#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 sgi
+#define SGI
+#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
+
+/*
+ * Different name on NetBSD, FreeBSD, BSDI, OpenBSD and Linux
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__bsdi__) || defined(__OpenBSD__) || defined(__linux__) || defined(SOL20) || defined(__Darwin__)
+#define dn_skipname __dn_skipname
+#endif
+
+extern VOIDSIG dummy();
+
+#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 USE_VARARGS
+#include <varargs.h>
+#endif
+#define MOTD MPATH
+#define LUSERS LUPATH
+#define OMOTD OMPATH
+#define MYNAME SPATH
+#define CONFIGFILE CPATH
+#define IRCD_PIDFILE PPATH
+
+#ifndef KLINE_TEMP
+#define KLINE_PERM 0
+#define KLINE_TEMP 1
+#define KLINE_AKILL 2
+#endif
+
+#ifdef DEBUGMODE
+extern void debug();
+# define Debug(x) debug x
+# define LOGFILE LPATH
+#else
+# define Debug(x) ;
+# define LOGFILE "/dev/null"
+#endif
+
+/*
+ * safety margin so we can always have one spare fd, for motd or
+ * whatever else. -4 allows "safety" margin of 1 and space reserved.
+ */
+
+#define MAXCLIENTS (MAXCONNECTIONS-4)
+
+#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
+
+
+#endif /* __sys_include__ */
--- /dev/null
+/****************************************************************************
+ * 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.
+ ****************************************************************************/
+
+/* 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 *));
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+/*
+ * 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;
+ char ww_nick[NICKLEN+1];
+ char ww_info[REALLEN+1];
+ char ww_ip[35];
+ char ww_mask[HOSTLEN+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__ */
--- /dev/null
+#************************************************************************
+#* 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.
+#*/
+
+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 masking.o s_bsd.o s_conf.o \
+ s_debug.o s_err.o s_misc.o s_numeric.o s_ping.o s_serv.o s_user.o s_zip.o \
+ whowas.o userload.o md5.o $(RES) $(STRTOUL)
+
+SRC=$(OBJS:%.o=%.c)
+
+MAKE = make 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'IRCDLIBS=${IRCDLIBS}' \
+ 'LDFLAGS=${LDFLAGS}' 'IRCDMODE=${IRCDMODE}'
+
+MKDIR=mkdir
+CHMOD=chmod
+CHOWN=chown
+CHGRP=chgrp
+DPATH=../
+IRCDMODE=0700
+IRCDOWN=irc
+IRCDGRP=irc
+MPATH=../ircd.motd
+INSTALL=../bsdinstall
+
+MV=mv
+GREP=grep
+SHELL=/bin/sh
+CC=__oops__
+
+all: build
+
+build: ircd chkconf
+
+ircd: parenttest $(OBJS)
+ @${SHELL} version.c.SH
+ ${CC} ${CFLAGS} -c version.c;
+ $(CC) $(CFLAGS) $(OBJS) version.o $(LDFLAGS) $(IRCDLIBS) -o ircd
+ chmod $(IRCDMODE) ircd
+
+parenttest:
+ @if [ "${CC}" = "__oops__" ]; then \
+ echo ""; echo ""; echo "";\
+ echo "*** Run make from the parent directory ***"; \
+ echo ""; echo "";echo "";\
+ exit 1; \
+ fi
+
+chkconf: ../include/struct.h ../include/config.h ../include/sys.h \
+ ../include/common.h chkconf.c
+ $(CC) $(CFLAGS) -DCR_CHKCONF -o chkmatch.o -c match.c
+ $(CC) $(CFLAGS) -o support.o -c support.c
+ $(CC) $(CFLAGS) chkconf.c chkmatch.o support.o \
+ $(LDFLAGS) $(IRCDLIBS) -o chkconf
+
+clean:
+ $(RM) -f *.o *~ *.sav *.save core ircd version.c chkconf
+
+cleandir: clean
+
+install: build
+ @if [ ! -d ${DPATH} -a ! -f ${DPATH} ]; then \
+ echo "Creating directory ${DPATH}"; \
+ ${MKDIR} ${DPATH}; \
+ ${CHMOD} 700 ${DPATH}; \
+ ${CHOWN} ${IRCDOWN} ${DPATH}; \
+ ${CHGRP} ${IRCDGRP} ${DPATH}; \
+ fi
+ @echo "Installing new ircd as ${BINDIR}/ircd :"
+ ${INSTALL} -m ${IRCDMODE} -o ${IRCDOWN} -g ${IRCDGRP} ircd ${BINDIR}/ircd
+ ${INSTALL} -s -m 700 -o ${IRCDOWN} -g ${IRCDGRP} chkconf ${BINDIR}
+ ${INSTALL} -m 600 -o ${IRCDOWN} -g ${IRCDGRP} ../doc/example.conf ${DPATH}
+ ( cd ${DPATH}; \
+ ${TOUCH} ${MPATH}; \
+ ${CHOWN} ${IRCDOWN} ${MPATH}; \
+ ${CHGRP} ${IRCDGRP} ${MPATH}; )
+
+
+depend: parenttest
+ @if [ -f Makefile.bak ]; then \
+ echo "make depend: First remove src/Makefile.bak"; \
+ else \
+ ( ${MV} Makefile Makefile.bak; \
+ ${GREP} -A1 -B1000 '^# DO NOT DELETE THIS LINE' Makefile.bak > Makefile;\
+ ${CC} ${CFLAGS} -MM ${SRC} >> Makefile; ) \
+ fi
+
+.SUFFIXES: .c .o
+
+.c.o:
+ ${CC} ${CFLAGS} -c $< -o $@
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+hash.o: hash.c
+bsd.o: bsd.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/h.h
+dbuf.o: dbuf.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h
+packet.o: packet.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/msg.h ../include/h.h
+send.o: send.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/h.h
+match.o: match.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h
+parse.o: parse.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/msg.h ../include/numeric.h \
+ ../include/h.h
+support.o: support.c ../include/config.h ../include/setup.h \
+ ../include/struct.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h
+channel.o: channel.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/channel.h \
+ ../include/msg.h ../include/hash.h ../include/h.h
+class.o: class.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/h.h
+hash.o: hash.c ../include/numeric.h ../include/struct.h \
+ ../include/config.h ../include/setup.h \
+ ../include/common.h ../include/sys.h ../include/class.h \
+ ../include/dbuf.h ../include/whowas.h ../include/hash.h \
+ ../include/h.h
+ircd.o: ircd.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/userload.h \
+ ../include/h.h
+list.o: list.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/h.h ../include/numeric.h
+res.o: res.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/res.h ../include/numeric.h \
+ ../include/h.h ../include/nameser.h ../include/resolv.h \
+ ../include/inet.h
+masking.o: masking.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/msg.h \
+ ../include/channel.h ../include/userload.h ../include/h.h
+s_bsd.o: s_bsd.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/res.h ../include/numeric.h \
+ ../include/patchlevel.h ../include/inet.h ../include/nameser.h \
+ ../include/resolv.h ../include/sock.h ../include/h.h
+s_conf.o: s_conf.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/channel.h \
+ ../include/msg.h ../include/inet.h ../include/h.h
+s_debug.o: s_debug.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/hash.h \
+ ../include/h.h
+s_err.o: s_err.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h
+s_misc.o: s_misc.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/userload.h \
+ ../include/h.h
+s_numeric.o: s_numeric.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/h.h
+s_ping.o: s_ping.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/patchlevel.h \
+ ../include/sock.h ../include/h.h
+s_serv.o: s_serv.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/msg.h \
+ ../include/channel.h ../include/userload.h ../include/h.h
+s_user.o: s_user.c ../include/config.h ../include/setup.h \
+ ../include/struct.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/msg.h \
+ ../include/channel.h ../include/userload.h ../include/h.h
+s_zip.o: s_zip.c ../include/config.h ../include/setup.h \
+ ../include/struct.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/msg.h \
+ ../include/channel.h ../include/userload.h ../include/h.h
+whowas.o: whowas.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/numeric.h ../include/h.h
+userload.o: userload.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/userload.h ../include/h.h
+md5.o: md5.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h
+map.o: map.c ../include/struct.h ../include/config.h \
+ ../include/setup.h ../include/common.h \
+ ../include/sys.h ../include/class.h ../include/dbuf.h \
+ ../include/whowas.h ../include/h.h ../include/numeric.h
--- /dev/null
+
+
+/************************************************************************
+ * 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>
+#include <sys/socket.h>
+
+extern int errno; /* ...seems that errno.h doesn't define this everywhere */
+#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__linux__) && !defined(__Darwin__)
+extern char *sys_errlist[];
+#endif
+
+#ifdef DEBUGMODE
+int writecalls = 0, writeb[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+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
+}
+
+
+/*
+ ** 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
+ 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
+ */
+ if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN ||
+ errno == ENOBUFS)) {
+ retval = 0;
+ SetBlocked (cptr);
+ }
+ else if (retval > 0) {
+#ifdef pyr
+ (void) gettimeofday (&cptr->lw, NULL);
+#endif
+ ClearBlocked (cptr);
+ }
+#ifdef DEBUGMODE
+ if (retval < 0) {
+ writeb[0]++;
+ Debug ((DEBUG_ERROR, "write error (%s) to %s",
+ sys_errlist[errno], cptr->name));
+
+ }
+ else if (retval == 0)
+ writeb[1]++;
+ else if (retval < 16)
+ writeb[2]++;
+ else if (retval < 32)
+ writeb[3]++;
+ else if (retval < 64)
+ writeb[4]++;
+ else if (retval < 128)
+ writeb[5]++;
+ else if (retval < 256)
+ writeb[6]++;
+ else if (retval < 512)
+ writeb[7]++;
+ else if (retval < 1024)
+ writeb[8]++;
+ else
+ writeb[9]++;
+#endif
+ if (retval > 0) {
+ cptr->sendB += retval;
+ me.sendB += retval;
+ if (cptr->sendB > 1023) {
+ cptr->sendK += (cptr->sendB >> 10);
+ cptr->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
+ }
+ if (acpt != &me) {
+ acpt->sendB += retval;
+ if (acpt->sendB > 1023) {
+ acpt->sendK += (acpt->sendB >> 10);
+ acpt->sendB &= 0x03ff;
+ }
+ }
+ else if (me.sendB > 1023) {
+ me.sendK += (me.sendB >> 10);
+ me.sendB &= 0x03ff;
+ }
+ }
+ return (retval);
+}
--- /dev/null
+#!/bin/sh
+
+# DALnet RCS/CVS identification:
+# $Id: buildm4,v 1.1.1.1 2001/10/22 19:27:09 remmy Exp $
+
+# 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.
+
+#
+# If only this was a perl script...*sigh*
+#
+IRCDDIR=$1
+M4=$IRCDDIR/ircd.m4
+/bin/rm -f $M4
+egrep "^#def[^P]*PATCHLEVEL" ../include/patchlevel.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_
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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"
+
+aChannel *channel = NullChn;
+aSynchList *SJSynchList = NULL;
+
+static void add_invite PROTO ((aClient *, aChannel *));
+static int can_join PROTO ((aClient *, aChannel *, char *));
+static void channel_modes PROTO ((aClient *, char *, char *, aChannel *));
+static int check_channelmask PROTO ((aClient *, aClient *, char *));
+static int add_banid PROTO ((aClient *, aChannel *, char *));
+static int del_banid PROTO ((aChannel *, char *));
+static int find_banid PROTO ((aChannel *, char *));
+static int add_exbanid PROTO ((aClient *, aChannel *, char *));
+static int del_exbanid PROTO ((aChannel *, char *));
+static int find_exbanid PROTO ((aChannel *, char *));
+static int add_hostrestrictid PROTO ((aClient *, aChannel *, char *));
+static int del_hostrestrictid PROTO ((aChannel *, char *));
+static int find_hostrestrictid PROTO ((aChannel *, char *));
+static int have_ops PROTO ((aChannel *));
+static int set_mode PROTO ((aClient *, aClient *, aChannel *, int,
+ char **, char *, char *, int *, int));
+static void sub1_from_channel PROTO ((aChannel *));
+
+void clean_channelname PROTO ((char *));
+void del_invite PROTO ((aClient *, aChannel *));
+int check_for_target_limit (aClient *, void *, const char *); /* from s_user.c */
+
+int sendmodeto_one (aClient *, char *, char *, char *, char *, time_t);
+
+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];
+
+/*
+ * return the length (>=0) of a chain of links.
+ */
+static int list_length (lp)
+ Link *lp;
+{
+ 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;
+ int *chasing;
+{
+ 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;
+}
+
+/*
+ * 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;
+{
+ Ban *ban;
+ 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 = time (NULL);
+ chptr->banlist = ban;
+ return 0;
+}
+
+/*
+ * del_banid - delete an id belonging to cptr
+ */
+static int del_banid (chptr, banid)
+ aChannel *chptr;
+ char *banid;
+{
+ Ban **ban;
+ 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;
+{
+ Ban **ban;
+
+ if (!banid)
+ return -1;
+ for (ban = &(chptr->banlist); *ban; ban = &((*ban)->next))
+ if (!mycmp (banid, (*ban)->banstr))
+ return 1;
+ return 0;
+}
+
+/*
+ * Exception Ban Functions (+e)
+ * -Ax0n
+ */
+
+static int add_exbanid (cptr, chptr, banid)
+ aClient *cptr;
+ aChannel *chptr;
+ char *banid;
+{
+ Ban *ban;
+ int cnt = 0, len = 0;
+
+ if (MyClient (cptr))
+ (void) collapse (banid);
+ for (ban = chptr->exbanlist; 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->exbanlist;
+ 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 = time (NULL);
+ chptr->exbanlist = ban;
+ return 0;
+}
+
+static int del_exbanid (chptr, banid)
+ aChannel *chptr;
+ char *banid;
+{
+ Ban **ban;
+ Ban *tmp;
+
+ if (!banid)
+ return -1;
+ for (ban = &(chptr->exbanlist); *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;
+}
+
+static int find_exbanid (chptr, banid)
+ aChannel *chptr;
+ char *banid;
+{
+ Ban **ban;
+
+ if (!banid)
+ return -1;
+ for (ban = &(chptr->exbanlist); *ban; ban = &((*ban)->next))
+ if (!mycmp (banid, (*ban)->banstr))
+ return 1;
+ return 0;
+}
+
+/*
+ * Host Restrict Functions (+H)
+ * -Remmy
+ */
+
+static int add_hostrestrictid (cptr, chptr, banid)
+ aClient *cptr;
+ aChannel *chptr;
+ char *banid;
+{
+ Ban *ban;
+ int cnt = 0, len = 0;
+
+ if (MyClient (cptr))
+ (void) collapse (banid);
+ for (ban = chptr->hostrestrictlist; 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->hostrestrictlist;
+ 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 = time (NULL);
+ chptr->hostrestrictlist = ban;
+ return 0;
+}
+
+static int del_hostrestrictid (chptr, banid)
+ aChannel *chptr;
+ char *banid;
+{
+ Ban **ban;
+ Ban *tmp;
+
+ if (!banid)
+ return -1;
+ for (ban = &(chptr->hostrestrictlist); *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;
+}
+
+static int find_hostrestrictid (chptr, banid)
+ aChannel *chptr;
+ char *banid;
+{
+ Ban **ban;
+
+ if (!banid)
+ return -1;
+ for (ban = &(chptr->hostrestrictlist); *ban; ban = &((*ban)->next))
+ if (!mycmp (banid, (*ban)->banstr))
+ return 1;
+ return 0;
+}
+
+
+/*
+ * IsMember - returns 1 if a person is joined
+ */
+int IsMember (cptr, chptr)
+ aClient *cptr;
+ aChannel *chptr;
+{
+ Link *lp;
+ return (((lp = find_user_link (chptr->members, cptr)))? 1 : 0);
+}
+
+/*
+ * is_banned - returns a pointer to the ban structure if banned else NULL
+ */
+extern Ban *is_banned (cptr, chptr)
+ aClient *cptr;
+ aChannel *chptr;
+{
+ Ban *tmp;
+ char *s, realaddy[NICKLEN + USERLEN + HOSTLEN + 6],
+ fakeaddy[NICKLEN + USERLEN + HOSTLEN + 6];
+ int testem = 0;
+
+ if (!IsPerson (cptr))
+ return NULL;
+ if (strcmp (cptr->user->host, MaskHost (cptr)))
+ testem = 1;
+ s = make_nick_user_host (cptr->name, cptr->user->username,
+ cptr->user->host);
+ strcpy (realaddy, s);
+ s = make_nick_user_host (cptr->name, cptr->user->username,
+ MaskHost (cptr));
+ strcpy (fakeaddy, s);
+ for (tmp = chptr->banlist; tmp; tmp = tmp->next)
+ if ((match (tmp->banstr, realaddy) == 0) ||
+ (testem && (match (tmp->banstr, fakeaddy) == 0)))
+ break;
+ return (tmp);
+
+}
+
+/*
+ * is_banexception - see is_banned(), same diff.
+ */
+extern Ban *is_banexception (cptr, chptr)
+ aClient *cptr;
+ aChannel *chptr;
+{
+ Ban *tmp;
+ char *s, realaddy[NICKLEN + USERLEN + HOSTLEN + 6],
+ fakeaddy[NICKLEN + USERLEN + HOSTLEN + 6];
+ int testem = 0;
+
+ if (!IsPerson (cptr))
+ return NULL;
+ if (strcmp (cptr->user->host, MaskHost (cptr)))
+ testem = 1;
+ s = make_nick_user_host (cptr->name, cptr->user->username,
+ cptr->user->host);
+ strcpy (realaddy, s);
+ s = make_nick_user_host (cptr->name, cptr->user->username,
+ MaskHost (cptr));
+ strcpy (fakeaddy, s);
+ for (tmp = chptr->exbanlist; tmp; tmp = tmp->next)
+ if ((match (tmp->banstr, realaddy) == 0) ||
+ (testem && (match (tmp->banstr, fakeaddy) == 0)))
+ break;
+ return (tmp);
+
+}
+
+/*
+ * is_banexception - see is_banned(), same diff.
+ */
+extern Ban *is_host_restricted (cptr, chptr)
+ aClient *cptr;
+ aChannel *chptr;
+{
+ Ban *tmp;
+ char *s, realaddy[NICKLEN + USERLEN + HOSTLEN + 6],
+ fakeaddy[NICKLEN + USERLEN + HOSTLEN + 6];
+ int testem = 0;
+
+ if (!IsPerson (cptr))
+ return NULL;
+ if (strcmp (cptr->user->host, MaskHost (cptr)))
+ testem = 1;
+ s = make_nick_user_host (cptr->name, cptr->user->username,
+ cptr->user->host);
+ strcpy (realaddy, s);
+ s = make_nick_user_host (cptr->name, cptr->user->username,
+ MaskHost (cptr));
+ strcpy (fakeaddy, s);
+ for (tmp = chptr->hostrestrictlist; tmp; tmp = tmp->next)
+ if ((match (tmp->banstr, realaddy) == 0) ||
+ (testem && (match (tmp->banstr, fakeaddy) == 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;
+{
+ Link *ptr;
+
+ if (who->user) {
+ ptr = make_link ();
+ ptr->value.cptr = who;
+ ptr->flags = flags;
+ ptr->next = chptr->members;
+ chptr->members = ptr;
+ chptr->users++;
+
+ ptr = make_link ();
+ ptr->value.chptr = chptr;
+ ptr->next = who->user->channel;
+ who->user->channel = ptr;
+ who->user->joined++;
+ }
+}
+
+void remove_user_from_channel (sptr, chptr)
+ aClient *sptr;
+ aChannel *chptr;
+{
+ Link **curr;
+ Link *tmp;
+ Link *lp = chptr->members;
+
+ for (; lp && (lp->flags & CHFL_ZOMBIE || lp->value.cptr == sptr);
+ lp = lp->next);
+ for (;;) {
+ for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next)
+ if (tmp->value.cptr == sptr) {
+ *curr = tmp->next;
+ free_link (tmp);
+ break;
+ }
+ for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next)
+ if (tmp->value.chptr == chptr) {
+ *curr = tmp->next;
+ free_link (tmp);
+ break;
+ }
+ 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;
+{
+ 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;
+{
+ Link *lp;
+
+ if (chptr)
+ if ((lp = find_user_link (chptr->members, cptr)))
+ return (lp->flags & CHFL_CHANOP);
+
+ return 0;
+}
+
+int has_voice (cptr, chptr)
+ aClient *cptr;
+ aChannel *chptr;
+{
+ Link *lp;
+
+ if (chptr)
+ if ((lp = find_user_link (chptr->members, cptr)) &&
+ !(lp->flags & CHFL_ZOMBIE))
+ return (lp->flags & CHFL_VOICE);
+
+ return 0;
+}
+
+/* This is used in determining why the user can't send to a channel -Defiant */
+#define CANNOT_SEND_MODERATED 1
+#define CANNOT_SEND_NOPRIVMSGS 2
+#define CANNOT_SEND_NOCOLORS 3
+#define CANNOT_SEND_BAN 4
+
+int can_send (cptr, chptr, msgtext)
+ aClient *cptr;
+ aChannel *chptr;
+ char *msgtext; /* for color checking -Defiant */
+{
+ Link *lp;
+ int member;
+
+ /* Moved check here, kinda faster.
+ * Note IsULine only uses the other parameter. -Donwulff */
+ if (IsULine (cptr, cptr) || IsServer (cptr) || IsSRoot (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)) ||
+ (lp->flags & CHFL_ZOMBIE)))
+ return (CANNOT_SEND_MODERATED);
+
+ if (chptr->mode.mode & MODE_NOPRIVMSGS && !member)
+ return (CANNOT_SEND_NOPRIVMSGS);
+
+ if (chptr->mode.mode & MODE_NOCOLORS)
+ if (strchr (msgtext, 3) != (char) NULL ||
+ strchr (msgtext, 27) != (char) NULL)
+ return (CANNOT_SEND_NOCOLORS);
+
+ if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE)) ||
+ (lp->flags & CHFL_ZOMBIE)) && MyClient (cptr) &&
+ is_banned (cptr, chptr)) {
+ if (!is_banexception (cptr, chptr))
+ return (CANNOT_SEND_BAN);
+ }
+ return 0;
+}
+
+aChannel *find_channel (chname, chptr)
+ char *chname;
+ 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;
+ char *mbuf, *pbuf;
+ aChannel *chptr;
+{
+ *mbuf++ = '+';
+ if (chptr->mode.mode & MODE_SECRET)
+ *mbuf++ = 's';
+ if (chptr->mode.mode & MODE_MODERATED)
+ *mbuf++ = 'm';
+ if (chptr->mode.mode & MODE_TOPICLIMIT)
+ *mbuf++ = 't';
+ if (chptr->mode.mode & MODE_NOCOLORS)
+ *mbuf++ = 'c';
+ if (chptr->mode.mode & MODE_INVITEONLY)
+ *mbuf++ = 'i';
+ if (chptr->mode.mode & MODE_NOPRIVMSGS)
+ *mbuf++ = 'n';
+ if (chptr->mode.mode & MODE_RGSTR)
+ *mbuf++ = 'r';
+ if (chptr->mode.mode & MODE_RGSTRONLY)
+ *mbuf++ = 'R';
+ if (chptr->mode.limit) {
+ *mbuf++ = 'l';
+ if (IsMember (cptr, chptr) || IsServer (cptr) || IsULine (cptr, cptr)
+ || IsSAdmin (cptr))
+ (void) sprintf (pbuf, "%d ", chptr->mode.limit);
+ }
+ if (*chptr->mode.key) {
+ *mbuf++ = 'k';
+ if (IsMember (cptr, chptr) || IsServer (cptr) || IsULine (cptr, cptr)
+ || IsSAdmin (cptr))
+ (void) strcat (pbuf, chptr->mode.key);
+ }
+ *mbuf++ = '\0';
+ return;
+}
+
+static int send_ban_list (cptr, chname, creationtime, top)
+ aClient *cptr;
+ Link *top;
+ char *chname;
+ time_t creationtime;
+{
+ Link *lp;
+ 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) {
+ name = ((Ban *) lp)->banstr;
+
+ if (strlen (parabuf) + strlen (name) + 11 < (size_t) MODEBUFLEN) {
+ if (*parabuf)
+ (void) strcat (parabuf, " ");
+ (void) strcat (parabuf, name);
+ count++;
+ *cp++ = 'b';
+ *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++ = 'b';
+ }
+ count = 0;
+ *cp = '\0';
+ }
+ }
+ return sent;
+}
+
+static int send_exban_list (cptr, chname, creationtime, top)
+ aClient *cptr;
+ Link *top;
+ char *chname;
+ time_t creationtime;
+{
+ Link *lp;
+ 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) {
+ name = ((Ban *) lp)->banstr;
+
+ if (strlen (parabuf) + strlen (name) + 11 < (size_t) MODEBUFLEN) {
+ if (*parabuf)
+ (void) strcat (parabuf, " ");
+ (void) strcat (parabuf, name);
+ count++;
+ *cp++ = 'e';
+ *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++ = 'e';
+ }
+ count = 0;
+ *cp = '\0';
+ }
+ }
+ return sent;
+}
+
+static int send_hostrestrict_list (cptr, chname, creationtime, top)
+ aClient *cptr;
+ Link *top;
+ char *chname;
+ time_t creationtime;
+{
+ Link *lp;
+ 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) {
+ name = ((Ban *) lp)->banstr;
+
+ if (strlen (parabuf) + strlen (name) + 11 < (size_t) MODEBUFLEN) {
+ if (*parabuf)
+ (void) strcat (parabuf, " ");
+ (void) strcat (parabuf, name);
+ count++;
+ *cp++ = 'H';
+ *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++ = 'H';
+ }
+ count = 0;
+ *cp = '\0';
+ }
+ }
+ return sent;
+}
+
+/*
+ * This will send "cptr" a full list of the modes for channel chptr,
+ * using the new StarChat Time Stamp 1 protocol (based on EFnet TS3)
+ */
+
+void send_channel_modes_sts (cptr, chptr)
+ aClient *cptr;
+ aChannel *chptr;
+{
+
+ Link *members;
+ Link *lp;
+ 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
+ strcpy (parabuf, "<none>");
+
+ sprintf (buf, ":%s SJOIN %ld %s %s %s :", me.name,
+ 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++ = '+';
+
+ 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 SJOIN %ld %s %s %s :", me.name,
+ 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, ex-ban list and hostrestrict list */
+
+ *parabuf = '\0';
+ *modebuf = '+';
+ modebuf[1] = '\0';
+
+ send_ban_list (cptr, chptr->chname, chptr->creationtime, chptr->banlist);
+ send_exban_list (cptr, chptr->chname, chptr->creationtime,
+ chptr->exbanlist);
+ send_hostrestrict_list (cptr, chptr->chname, chptr->creationtime,
+ chptr->hostrestrictlist);
+
+ if (modebuf[1] || *parabuf)
+ sendto_one (cptr, ":%s MODE %s %s %s", me.name, chptr->chname,
+ modebuf, parabuf);
+
+ return;
+}
+
+/*
+ ** m_knock
+ ** parv[0] - sender prefix
+ ** parv[1] - channel
+ ** parv[2] - reason
+ **
+ */
+int m_knock (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ 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;
+
+ if (*parv[1] != '#' && *parv[1] != '&') {
+ sendto_one (sptr, err_str (ERR_CANNOTKNOCK),
+ me.name, sptr->name, parv[1], "No such channel");
+
+ return 0;
+ }
+ if (!(chptr = find_channel (parv[1], NullChn))) {
+ sendto_one (sptr, err_str (ERR_CANNOTKNOCK),
+ me.name, sptr->name, parv[1], "No such channel");
+
+ return 0;
+ }
+ if (IsMember (sptr, chptr) == 1) {
+ sendto_one (sptr, err_str (ERR_CANNOTKNOCK),
+ me.name, sptr->name, chptr->chname,
+ "You're already in that channel");
+
+ return 0;
+ }
+ if (is_banned (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_INVITEONLY)) {
+ sendto_one (sptr, err_str (ERR_CANNOTKNOCK),
+ me.name, sptr->name, chptr->chname,
+ "Channel is not invite only");
+
+ return 0;
+ }
+ sendto_channelops_butone (NULL, &me, chptr,
+ ":%s NOTICE @%s :%s wants to join (%s).",
+ me.name, chptr->chname, sptr->name, parv[2]);
+
+ sendto_one (sptr, ":%s NOTICE %s :Knocked on to %s", me.name, sptr->name,
+ chptr->chname);
+
+ return 0;
+}
+
+/*
+ * 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]; Compiler says this is unused */
+ int badop, sendts;
+ aChannel *chptr;
+
+ if (check_registered (cptr))
+ return 0;
+
+ if (!IsPrivileged (cptr)) {
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if (!IsSAdmin (cptr) || parc < 2)
+ return 0;
+
+ chptr = find_channel (parv[1], NullChn);
+ if (chptr == NullChn)
+ return 0;
+
+ sptr->flags &= ~FLAGS_TS8;
+
+ clean_channelname (parv[1]);
+
+ if (check_channelmask (sptr, cptr, parv[1]))
+ return 0;
+
+ sendts = set_mode (cptr, sptr, chptr, parc - 2, parv + 2,
+ modebuf, parabuf, &badop, 1);
+
+ if (strlen (modebuf) > (size_t) 1 || sendts > 0) {
+ if (badop != 2 && strlen (modebuf) > (size_t) 1)
+ sendto_channel_butserv (chptr, sptr, ":%s MODE %s %s %s",
+ me.name, chptr->chname, modebuf, parabuf);
+
+ sendto_match_servs (chptr, cptr, ":%s MODE %s %s %s 1",
+ parv[0], chptr->chname, modebuf, parabuf);
+
+ if (MyClient (sptr)) {
+ sendto_serv_butone (&me, ":%s GLOBOPS :%s used SAMODE (%s %s %s)",
+ me.name, sptr->name, chptr->chname, modebuf,
+ parabuf);
+ sendto_failops_whoare_opers ("from %s: %s used SAMODE (%s %s %s)",
+ me.name, sptr->name, chptr->chname,
+ modebuf, parabuf);
+ }
+ }
+ return 0;
+}
+
+/*
+ * m_mode
+ * parv[0] - sender
+ * parv[1] - channel
+ */
+int m_mode (cptr, sptr, parc, parv)
+ aClient *cptr;
+ aClient *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+ Link *lp;
+
+ static char tmp[MODEBUFLEN];
+ int badop, sendts, listbans;
+ aChannel *chptr;
+
+/* Not needed re change to parse.c
+ 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) {
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes (sptr, modebuf, parabuf, chptr);
+ sendto_one (sptr, rpl_str (RPL_CHANNELMODEIS), me.name, parv[0],
+ chptr->chname, modebuf, parabuf);
+ sendto_one (sptr, rpl_str (RPL_CREATIONTIME), me.name, parv[0],
+ chptr->chname, chptr->creationtime);
+ return 0;
+ }
+ /* Some +v patches (Yes, this is not the right place...so what? }:) -GZ */
+
+ if (parc > 3) {
+
+ if (!strncmp (parv[2], "-v", 2)) {
+ if ((acptr = find_person (parv[3], NULL))) {
+ if (sptr == acptr) {
+ lp = find_user_link (chptr->members, acptr);
+ if (lp) {
+ if (lp->flags & CHFL_VOICE) {
+ lp->flags &= ~CHFL_VOICE;
+ sendto_channel_butserv (chptr, cptr,
+ ":%s MODE %s -v %s",
+ parv[0], chptr->chname,
+ acptr->name);
+ sendto_match_servs (chptr, cptr,
+ ":%s MODE %s -v %s", parv[0],
+ chptr->chname, acptr->name);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* is-not-a-channel-operator-bugfix.
+ * and prevent non-opers from seeing bans from the outside.
+ */
+
+ listbans = 0;
+
+ if ((!(strncmp (parv[2], "+b", 2))) && (parc == 3)
+ && (IsMember (sptr, chptr) || IsAnOper (sptr)))
+ listbans = 1;
+
+ if ((!(strncmp (parv[2], "b", 1))) && (parc == 3)
+ && (IsMember (sptr, chptr) || IsAnOper (sptr)))
+ listbans = 1;
+
+ if ((!(strncmp (parv[2], "+e", 2))) && (parc == 3)
+ && (IsMember (sptr, chptr) || IsAnOper (sptr)))
+ listbans = 1;
+
+ if ((!(strncmp (parv[2], "e", 1))) && (parc == 3)
+ && (IsMember (sptr, chptr) || IsAnOper (sptr)))
+ listbans = 1;
+
+ if ((!(strncmp (parv[2], "+H", 2))) && (parc == 3)
+ && (IsMember (sptr, chptr) || IsAnOper (sptr)))
+ listbans = 1;
+
+ if ((!(strncmp (parv[2], "H", 1))) && (parc == 3)
+ && (IsMember (sptr, chptr) || IsAnOper (sptr)))
+ listbans = 1;
+
+ if (!IsServer (cptr) && !IsULine (cptr, sptr) && !is_chan_op (sptr, chptr)
+ && (listbans == 0)) {
+ sendto_one (sptr, err_str (ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], chptr->chname);
+ return 0;
+ }
+ if (!(sendts = set_mode (cptr, sptr, chptr, parc - 2, parv + 2,
+ modebuf, parabuf, &badop, 0))
+ && !IsULine (cptr, sptr)) {
+ sendto_one (sptr, err_str (ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], chptr->chname);
+ return 0;
+ }
+ if ((badop >= 2) && !IsULine (cptr, sptr)) {
+ int i = 3;
+ *tmp = '\0';
+ while (i < parc) {
+ strcat (tmp, " ");
+ strcat (tmp, parv[i++]);
+ }
+ }
+ if (strlen (modebuf) > (size_t) 1 || sendts > 0) {
+ if (badop != 2 && strlen (modebuf) > (size_t) 1)
+ sendto_channel_butserv (chptr, sptr, ":%s MODE %s %s %s",
+ parv[0], chptr->chname, modebuf, parabuf);
+ /* We send a creationtime of 0, to mark it as a hack --Run */
+ if ((IsServer (sptr) && (badop == 2 || sendts > 0)) ||
+ IsULine (cptr, sptr)) {
+ if (*modebuf == '\0')
+ strcpy (modebuf, "+");
+ if (badop == 2)
+ badop = 2;
+ else
+ sendto_match_servs (chptr, cptr, ":%s MODE %s %s %s %lu",
+ parv[0], chptr->chname, modebuf, parabuf,
+ (badop ==
+ 4) ? (time_t) 0 : chptr->creationtime);
+ }
+ else
+ sendto_match_servs (chptr, cptr, ":%s MODE %s %s %s",
+ parv[0], chptr->chname, modebuf, parabuf);
+ }
+ return 0;
+}
+
+int DoesOp (modebuf)
+ char *modebuf;
+{
+ modebuf--; /* Is it possible that a mode starts with o and not +o ? */
+ while (*++modebuf)
+ if (*modebuf == 'o' || *modebuf == 'v')
+ return (1);
+ return 0;
+}
+
+int sendmodeto_one (cptr, from, name, mode, param, creationtime)
+ 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);
+ return 0;
+}
+
+char *pretty_mask (mask)
+ char *mask;
+{
+ char *cp;
+ char *user;
+ 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);
+}
+
+/*
+ * Check and try to apply the channel modes passed in the parv array for
+ * the client ccptr to channel chptr. The resultant changes are printed
+ * into mbuf and pbuf (if any) and applied to the channel.
+ */
+static int set_mode (cptr, sptr, chptr, parc, parv, mbuf, pbuf, badop, sadmin)
+ aClient *cptr, *sptr;
+ aChannel *chptr;
+ int parc, *badop, sadmin;
+ char *parv[], *mbuf, *pbuf;
+{
+ static Link chops[MAXMODEPARAMS];
+ static int flags[] = {
+ MODE_SECRET, 's',
+ MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n',
+ MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i',
+ MODE_VOICE, 'v', MODE_KEY, 'k',
+ MODE_RGSTR, 'r', MODE_RGSTRONLY, 'R',
+ MODE_NOCOLORS, 'c',
+ 0x0, 0x0
+ };
+
+ Link *lp;
+ Ban *ban;
+ Ban *exban;
+ Ban *hrstrct;
+ char *curr = parv[0], *cp = NULL;
+ int *ip;
+ Link *member, *tmp = NULL;
+ u_int whatt = MODE_ADD, bwhatt = 0;
+ int limitset = 0, chasing = 0, bounce;
+ int nusers = 0, new, len, blen, keychange = 0, opcnt = 0, banlsent = 0;
+ int exbanlsent = 0, hostrestrictlsent = 0;
+ int doesdeop = 0, doesop = 0, hacknotice = 0, change, gotts = 0;
+ aClient *who;
+ Mode *mode, oldm;
+ static char bmodebuf[MODEBUFLEN], bparambuf[MODEBUFLEN], numeric[16];
+ char *bmbuf = bmodebuf, *bpbuf = bparambuf;
+ time_t newtime = (time_t) 0;
+ aConfItem *aconf;
+
+ *mbuf = *pbuf = *bmbuf = *bpbuf = '\0';
+ *badop = 0;
+ if (parc < 1)
+ return 0;
+ mode = &(chptr->mode);
+ bcopy ((char *) mode, (char *) &oldm, sizeof (Mode));
+ /* Mode is accepted when sptr is a channel operator
+ * but also when the mode is received from a server. --Run
+ */
+ new = mode->mode;
+
+ while (curr && *curr) {
+ switch (*curr) {
+ case '+':
+ whatt = MODE_ADD;
+ break;
+ case '-':
+ whatt = MODE_DEL;
+ break;
+ case 'o':
+ case 'v':
+ if (--parc <= 0)
+ break;
+ parv++;
+ *parv = check_string (*parv);
+ if (MyClient (sptr) && opcnt >= MODEPARAMS)
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+ break;
+ /*
+ * Check for nickname changes and try to follow these
+ * to make sure the right client is affected by the
+ * mode change.
+ */
+ if (!(who = find_chasing (sptr, parv[0], &chasing)))
+ break;
+ if (!(member = find_user_link (chptr->members, who))) {
+ sendto_one (cptr, err_str (ERR_USERNOTINCHANNEL),
+ me.name, cptr->name, parv[0], chptr->chname);
+ break;
+ }
+ if (whatt == MODE_ADD) {
+ lp = &chops[opcnt++];
+ lp->value.cptr = who;
+ if ((IsServer (sptr) &&
+ (!(who->flags & FLAGS_TS8) ||
+ ((*curr == 'o') && !(member->flags &
+ (CHFL_SERVOPOK | CHFL_CHANOP))) ||
+ who->from != sptr->from)) ||
+ IsULine (cptr, sptr) || sadmin == 1 ||
+ (!MyClient (sptr) && IsSAdmin (sptr)))
+ *badop = ((member->flags & CHFL_DEOPPED)
+ && (*curr == 'o')) ? 2 : 3;
+ lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
+ lp->flags |= MODE_ADD;
+ }
+ else if (whatt == MODE_DEL) {
+ lp = &chops[opcnt++];
+ lp->value.cptr = who;
+ doesdeop = 1; /* Also when -v */
+ lp->flags = (*curr == 'o') ? MODE_CHANOP : MODE_VOICE;
+ lp->flags |= MODE_DEL;
+ }
+ if (*curr == 'o')
+ doesop = 1;
+ break;
+ case 'k':
+ if (--parc <= 0)
+ break;
+ parv++;
+ /* check now so we eat the parameter if present */
+ if (keychange)
+ break;
+ *parv = check_string (*parv);
+ {
+ u_char *s1, *s2;
+
+ for (s1 = s2 = (u_char *) * parv; *s2; s2++)
+ if ((*s1 = *s2 & 0x7f) > (u_char) 32 && *s1 != ':')
+ s1++;
+ *s1 = '\0';
+ }
+ if (MyClient (sptr) && opcnt >= MODEPARAMS)
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+ break;
+
+ if (whatt == MODE_ADD) {
+ if (*mode->key && !IsServer (cptr) &&
+ !IsULine (cptr, sptr) && sadmin == 0 && !IsSAdmin (sptr))
+ sendto_one (cptr, err_str (ERR_KEYSET),
+ me.name, cptr->name, chptr->chname);
+ else if (!*mode->key || IsServer (cptr) ||
+ IsULine (cptr, sptr) || sadmin == 1
+ || (!MyClient (sptr) && IsSAdmin (sptr))) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ if (strlen (lp->value.cp) > (size_t) KEYLEN)
+ lp->value.cp[KEYLEN] = '\0';
+ lp->flags = MODE_KEY | MODE_ADD;
+ keychange = 1;
+ }
+ }
+ else if (whatt == MODE_DEL) {
+ if (mycmp (mode->key, *parv) == 0 ||
+ IsServer (cptr) || IsULine (cptr, sptr) ||
+ sadmin == 1 || (!MyClient (sptr) && IsSAdmin (sptr))) {
+ lp = &chops[opcnt++];
+ lp->value.cp = mode->key;
+ lp->flags = MODE_KEY | MODE_DEL;
+ keychange = 1;
+ }
+ }
+ break;
+ case 'b':
+ if ((IsRegisteredUser (cptr)) && (!IsMember (cptr, chptr))
+ && (!IsOper (cptr))) {
+ sendto_one (cptr, err_str (ERR_NOTONCHANNEL), me.name,
+ parv[0], chptr->chname);
+ break;
+ }
+ if (--parc <= 0) {
+ if (banlsent) /* Only send it once */
+ break;
+ for (ban = chptr->banlist; ban; ban = ban->next)
+ sendto_one (cptr, rpl_str (RPL_BANLIST),
+ me.name, cptr->name,
+ chptr->chname, ban->banstr, ban->who,
+ ban->when);
+ sendto_one (cptr, rpl_str (RPL_ENDOFBANLIST), me.name,
+ cptr->name, chptr->chname);
+ banlsent = 1;
+ break;
+ }
+
+ parv++;
+ if (BadPtr (*parv))
+ break;
+ if (MyClient (sptr) && opcnt >= MODEPARAMS)
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+ break;
+ /* check for malignantly formed ban */
+ if (strchr (*parv, ':'))
+ break;
+ if (whatt == MODE_ADD) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_ADD | MODE_BAN;
+ }
+ else if (whatt == MODE_DEL) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_DEL | MODE_BAN;
+ }
+ break;
+ case 'e':
+ if ((IsRegisteredUser (cptr)) && (!IsMember (cptr, chptr))
+ && (!IsOper (cptr))) {
+ sendto_one (cptr, err_str (ERR_NOTONCHANNEL), me.name,
+ parv[0], chptr->chname);
+ break;
+ }
+ if (--parc <= 0) {
+ if (exbanlsent) /* Only send it once */
+ break;
+ for (exban = chptr->exbanlist; exban; exban = exban->next)
+ sendto_one (cptr, rpl_str (RPL_EXBANLIST),
+ me.name, cptr->name,
+ chptr->chname, exban->banstr, exban->who,
+ exban->when);
+ sendto_one (cptr, rpl_str (RPL_EXBANLISTEND), me.name,
+ cptr->name, chptr->chname);
+ exbanlsent = 1;
+ break;
+ }
+ parv++;
+ if (BadPtr (*parv))
+ break;
+ if (MyClient (sptr) && opcnt >= MODEPARAMS)
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+ break;
+ /* check for malignantly formed exban */
+ if (strchr (*parv, ':'))
+ break;
+ if (whatt == MODE_ADD) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_ADD | MODE_EXBAN;
+ }
+ else if (whatt == MODE_DEL) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_DEL | MODE_EXBAN;
+ }
+ break;
+ case 'H':
+ if ((IsRegisteredUser (cptr)) && (!IsMember (cptr, chptr))
+ && (!IsOper (cptr))) {
+ sendto_one (cptr, err_str (ERR_NOTONCHANNEL), me.name,
+ parv[0], chptr->chname);
+ break;
+ }
+ if (--parc <= 0) {
+ if (hostrestrictlsent) /* Only send it once */
+ break;
+ for (hrstrct = chptr->hostrestrictlist; hrstrct; hrstrct = hrstrct->next)
+ sendto_one (cptr, rpl_str (RPL_HOSTRESTRICTLIST),
+ me.name, cptr->name,
+ chptr->chname, hrstrct->banstr, hrstrct->who,
+ hrstrct->when);
+ sendto_one (cptr, rpl_str (RPL_HOSTRESTRICTLISTEND), me.name,
+ cptr->name, chptr->chname);
+ hostrestrictlsent = 1;
+ break;
+ }
+ parv++;
+ if (BadPtr (*parv))
+ break;
+ if (MyClient (sptr) && opcnt >= MODEPARAMS)
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+ break;
+ /* check for malignantly formed exban */
+ if (strchr (*parv, ':'))
+ break;
+ if (whatt == MODE_ADD) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_ADD | MODE_HOSTRESTRICT;
+ }
+ else if (whatt == MODE_DEL) {
+ lp = &chops[opcnt++];
+ lp->value.cp = *parv;
+ lp->flags = MODE_DEL | MODE_HOSTRESTRICT;
+ }
+ break;
+ case 'l':
+ /*
+ * limit 'l' to only *1* change per mode command but
+ * eat up others.
+ */
+ if (limitset) {
+ if (whatt == MODE_ADD && --parc > 0)
+ parv++;
+ break;
+ }
+ if (whatt == MODE_DEL) {
+ limitset = 1;
+ nusers = 0;
+ break;
+ }
+ if (--parc > 0) {
+ if (BadPtr (*parv))
+ break;
+ if (MyClient (sptr) && opcnt >= MODEPARAMS)
+ break;
+ if (opcnt >= MAXMODEPARAMS)
+ break;
+ if (!(nusers = atoi (*++parv)))
+ continue;
+ lp = &chops[opcnt++];
+ lp->flags = MODE_ADD | MODE_LIMIT;
+ limitset = 1;
+ break;
+ }
+ sendto_one (cptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, cptr->name, "MODE +l");
+ break;
+ case 'r':
+ if (IsServer (cptr)) {
+ if (whatt == MODE_DEL)
+ new &= ~MODE_RGSTR;
+ else
+ new |= MODE_RGSTR;
+ }
+ else
+ sendto_one (cptr, err_str (ERR_ONLYSERVERSCANCHANGE),
+ me.name, cptr->name, chptr->chname);
+ break;
+ case 'i': /* falls through for default case */
+ if (whatt == MODE_DEL)
+ while ((lp = chptr->invites))
+ del_invite (lp->value.cptr, chptr);
+ default:
+ for (ip = flags; *ip; ip += 2)
+ if (*(ip + 1) == *curr)
+ break;
+
+ if (*ip) {
+ if (whatt == MODE_ADD)
+ new |= *ip;
+ else
+ new &= ~*ip;
+ }
+ else if (!IsServer (cptr) && !IsULine (cptr, sptr))
+ sendto_one (cptr, err_str (ERR_UNKNOWNMODE),
+ me.name, cptr->name, *curr);
+ break;
+ }
+ curr++;
+ /*
+ * Make sure mode strings such as "+m +t +i" are parsed
+ * fully.
+ */
+ if (!*curr && parc > 0) {
+ curr = *++parv;
+ parc--;
+ /* If this was from a server, and it is the last
+ * parameter and it starts with a digit, it must
+ * be the creationtime. --Run
+ */
+ if (IsServer (sptr) || IsULine (cptr, sptr)) {
+ if (parc == 1 && isdigit (*curr)) {
+ newtime = atoi (curr);
+ gotts = 1;
+ if (newtime == 0) {
+ *badop = 2;
+ hacknotice = 1;
+ }
+ else if (newtime > chptr->creationtime) { /* It is a net-break ride if we have ops.
+ * bounce modes if we have ops.
+ * --Run
+ */
+ if (doesdeop)
+ *badop = 2;
+ else if (chptr->creationtime == 0
+ || !have_ops (chptr)) {
+ if (chptr->creationtime && doesop);
+/* sendto_ops("NET.RIDE on opless %s from %s",
+ chptr->chname,sptr->name); */
+ if (chptr->creationtime == 0 || doesop)
+ chptr->creationtime = newtime;
+ *badop = 0;
+ }
+ /* Bounce: */
+ else
+ *badop = 1;
+ }
+ else if (doesdeop && newtime < chptr->creationtime)
+ *badop = 2;
+ /* A legal *badop can occur when two
+ * people join simultaneously a channel,
+ * Allow for 10 min of lag (and thus hacking
+ * on channels younger then 10 min) --Run
+ */
+ else if (*badop == 0 ||
+ chptr->creationtime >
+ (time (NULL) - (time_t) 600)) {
+ if (doesop || !have_ops (chptr))
+ chptr->creationtime = newtime;
+ *badop = 0;
+ }
+ break;
+ }
+ }
+ else
+ *badop = 0;
+ }
+ } /* end of while loop for MODE processing */
+
+ if (doesop && newtime == 0 && (IsServer (sptr) || IsULine (cptr, sptr)
+ || sadmin == 1 || (!MyClient (sptr)
+ && IsSAdmin (sptr))))
+ *badop = 2;
+
+ if (*badop >= 2 &&
+ (aconf = find_conf_host (cptr->confs, sptr->name, CONF_UWORLD)))
+ *badop = 4;
+ if (*badop >= 2 && (IsULine (cptr, sptr) || sadmin == 1 ||
+ (!MyClient (sptr) && IsSAdmin (sptr))))
+ *badop = 4;
+
+ /* Fixes channel hacking. Problem before was that it didn't bounce
+ unless user was deopped by server. Now modes from *all*
+ non-chanops are bounced. -- Barubary */
+ if (!IsServer (sptr) && !IsULine (cptr, sptr)
+ && !is_chan_op (sptr, chptr))
+ bounce = 1;
+ else
+ bounce = (*badop == 1 || *badop == 2) ? 1 : 0;
+ if (IsULine (cptr, sptr) || sadmin == 1
+ || (!MyClient (sptr) && IsSAdmin (sptr)))
+ bounce = 0;
+
+ whatt = 0;
+ for (ip = flags; *ip; ip += 2)
+ if ((*ip & new) && !(*ip & oldm.mode)) {
+ if (bounce) {
+ if (bwhatt != MODE_DEL) {
+ *bmbuf++ = '-';
+ bwhatt = MODE_DEL;
+ }
+ *bmbuf++ = *(ip + 1);
+ }
+ else {
+ if (whatt != MODE_ADD) {
+ *mbuf++ = '+';
+ whatt = MODE_ADD;
+ }
+ mode->mode |= *ip;
+ *mbuf++ = *(ip + 1);
+ }
+ }
+ for (ip = flags; *ip; ip += 2)
+ if ((*ip & oldm.mode) && !(*ip & new)) {
+ if (bounce) {
+ if (bwhatt != MODE_ADD) {
+ *bmbuf++ = '+';
+ bwhatt = MODE_ADD;
+ }
+ *bmbuf++ = *(ip + 1);
+ }
+ else {
+ if (whatt != MODE_DEL) {
+ *mbuf++ = '-';
+ whatt = MODE_DEL;
+ }
+ mode->mode &= ~*ip;
+ *mbuf++ = *(ip + 1);
+ }
+ }
+ blen = 0;
+ if (limitset && !nusers && mode->limit) {
+ if (bounce) {
+ if (bwhatt != MODE_ADD) {
+ *bmbuf++ = '+';
+ bwhatt = MODE_ADD;
+ }
+ *bmbuf++ = 'l';
+ (void) sprintf (numeric, "%-15d", mode->limit);
+ if ((cp = index (numeric, ' ')))
+ *cp = '\0';
+ (void) strcat (bpbuf, numeric);
+ blen += strlen (numeric);
+ (void) strcat (bpbuf, " ");
+ }
+ else {
+ if (whatt != MODE_DEL) {
+ *mbuf++ = '-';
+ whatt = MODE_DEL;
+ }
+ mode->mode &= ~MODE_LIMIT;
+ mode->limit = 0;
+ *mbuf++ = 'l';
+ }
+ }
+ /*
+ * Reconstruct "+bkov" chain.
+ */
+ if (opcnt) {
+ int i = 0;
+ char c = 0;
+ u_int prev_whatt = 0;
+
+ for (; i < opcnt; i++) {
+ lp = &chops[i];
+ /*
+ * make sure we have correct mode change sign
+ */
+ if (whatt != (lp->flags & (MODE_ADD | MODE_DEL))) {
+ if (lp->flags & MODE_ADD) {
+ *mbuf++ = '+';
+ prev_whatt = whatt;
+ whatt = MODE_ADD;
+ }
+ else {
+ *mbuf++ = '-';
+ prev_whatt = whatt;
+ whatt = MODE_DEL;
+ }
+ }
+ len = strlen (pbuf);
+ /*
+ * get c as the mode char and tmp as a pointer to
+ * the parameter for this mode change.
+ */
+ switch (lp->flags & MODE_WPARAS) {
+ case MODE_CHANOP:
+ c = 'o';
+ cp = lp->value.cptr->name;
+ break;
+ case MODE_VOICE:
+ c = 'v';
+ cp = lp->value.cptr->name;
+ break;
+ case MODE_BAN:
+ /* I made this a bit more user-friendly (tm):
+ * nick = nick!*@*
+ * nick!user = nick!user@*
+ * user@host = *!user@host
+ * host.name = *!*@host.name --Run
+ */
+ c = 'b';
+ cp = pretty_mask (lp->value.cp);
+ break;
+ case MODE_EXBAN:
+ c = 'e';
+ cp = pretty_mask (lp->value.cp);
+ break;
+ case MODE_HOSTRESTRICT:
+ c = 'H';
+ cp = pretty_mask (lp->value.cp);
+ break;
+ case MODE_KEY:
+ c = 'k';
+ cp = lp->value.cp;
+ break;
+ case MODE_LIMIT:
+ c = 'l';
+ (void) sprintf (numeric, "%-15d", nusers);
+ if ((cp = index (numeric, ' ')))
+ *cp = '\0';
+ cp = numeric;
+ break;
+ }
+
+ if (len + strlen (cp) + 12 > (size_t) MODEBUFLEN)
+ break;
+ switch (lp->flags & MODE_WPARAS) {
+ case MODE_KEY:
+ if (strlen (cp) > (size_t) KEYLEN)
+ *(cp + KEYLEN) = '\0';
+ if ((whatt == MODE_ADD && (*mode->key == '\0' ||
+ mycmp (mode->key, cp) != 0)) ||
+ (whatt == MODE_DEL && (*mode->key != '\0'))) {
+ if (bounce) {
+ if (*mode->key == '\0') {
+ if (bwhatt != MODE_DEL) {
+ *bmbuf++ = '-';
+ bwhatt = MODE_DEL;
+ }
+ (void) strcat (bpbuf, cp);
+ blen += strlen (cp);
+ (void) strcat (bpbuf, " ");
+ blen++;
+ }
+ else {
+ if (bwhatt != MODE_ADD) {
+ *bmbuf++ = '+';
+ bwhatt = MODE_ADD;
+ }
+ (void) strcat (bpbuf, mode->key);
+ blen += strlen (mode->key);
+ (void) strcat (bpbuf, " ");
+ blen++;
+ }
+ *bmbuf++ = c;
+ mbuf--;
+ if (*mbuf != '+' && *mbuf != '-')
+ mbuf++;
+ else
+ whatt = prev_whatt;
+ }
+ else {
+ *mbuf++ = c;
+ (void) strcat (pbuf, cp);
+ len += strlen (cp);
+ (void) strcat (pbuf, " ");
+ len++;
+ if (whatt == MODE_ADD)
+ strncpyzt (mode->key, cp, sizeof (mode->key));
+ else
+ *mode->key = '\0';
+ }
+ }
+ break;
+ case MODE_LIMIT:
+ if (nusers && nusers != mode->limit) {
+ if (bounce) {
+ if (mode->limit == 0) {
+ if (bwhatt != MODE_DEL) {
+ *bmbuf++ = '-';
+ bwhatt = MODE_DEL;
+ }
+ }
+ else {
+ if (bwhatt != MODE_ADD) {
+ *bmbuf++ = '+';
+ bwhatt = MODE_ADD;
+ }
+ (void) sprintf (numeric, "%-15d", mode->limit);
+ if ((cp = index (numeric, ' ')))
+ *cp = '\0';
+ (void) strcat (bpbuf, numeric);
+ blen += strlen (numeric);
+ (void) strcat (bpbuf, " ");
+ blen++;
+ }
+ *bmbuf++ = c;
+ mbuf--;
+ if (*mbuf != '+' && *mbuf != '-')
+ mbuf++;
+ else
+ whatt = prev_whatt;
+ }
+ else {
+ *mbuf++ = c;
+ (void) strcat (pbuf, cp);
+ len += strlen (cp);
+ (void) strcat (pbuf, " ");
+ len++;
+ mode->limit = nusers;
+ }
+ }
+ break;
+ case MODE_CHANOP:
+ case MODE_VOICE:
+ tmp = find_user_link (chptr->members, lp->value.cptr);
+ if (lp->flags & MODE_ADD) {
+ change = (~tmp->flags) & CHFL_OVERLAP & lp->flags;
+ if (change && bounce) {
+ if (lp->flags & MODE_CHANOP)
+ tmp->flags |= CHFL_DEOPPED;
+ if (bwhatt != MODE_DEL) {
+ *bmbuf++ = '-';
+ bwhatt = MODE_DEL;
+ }
+ *bmbuf++ = c;
+ (void) strcat (bpbuf, lp->value.cptr->name);
+ blen += strlen (lp->value.cptr->name);
+ (void) strcat (bpbuf, " ");
+ blen++;
+ change = 0;
+ }
+ else if (change) {
+ tmp->flags |= lp->flags & CHFL_OVERLAP;
+ if (lp->flags & MODE_CHANOP) {
+ tmp->flags &= ~CHFL_DEOPPED;
+ if (IsServer (sptr) || IsULine (cptr, sptr))
+ tmp->flags &= ~CHFL_SERVOPOK;
+ }
+ }
+ }
+ else {
+ change = tmp->flags & CHFL_OVERLAP & lp->flags;
+ if (change && bounce) {
+ if (lp->flags & MODE_CHANOP)
+ tmp->flags &= ~CHFL_DEOPPED;
+ if (bwhatt != MODE_ADD) {
+ *bmbuf++ = '+';
+ bwhatt = MODE_ADD;
+ }
+ *bmbuf++ = c;
+ (void) strcat (bpbuf, lp->value.cptr->name);
+ blen += strlen (lp->value.cptr->name);
+ (void) strcat (bpbuf, " ");
+ blen++;
+ change = 0;
+ }
+ else {
+ tmp->flags &= ~change;
+ if ((change & MODE_CHANOP) &&
+ (IsServer (sptr) || IsULine (cptr, sptr)
+ || sadmin == 1 || (!MyClient (sptr)
+ && IsSAdmin (sptr))))
+ tmp->flags |= CHFL_DEOPPED;
+ }
+ }
+ if (change || *badop == 2 || *badop == 4) {
+ *mbuf++ = c;
+ (void) strcat (pbuf, cp);
+ len += strlen (cp);
+ (void) strcat (pbuf, " ");
+ len++;
+ }
+ else {
+ mbuf--;
+ if (*mbuf != '+' && *mbuf != '-')
+ mbuf++;
+ else
+ whatt = prev_whatt;
+ }
+ break;
+ case MODE_BAN:
+/* Only bans aren't bounced, it makes no sense to bounce last second
+ * bans while propagating bans done before the net.rejoin. The reason
+ * why I don't bounce net.rejoin bans is because it is too much
+ * work to take care of too long strings adding the necessary TS to
+ * net.burst bans -- RunLazy
+ * We do have to check for *badop==2 now, we don't want HACKs to take
+ * effect.
+ */
+/* Not anymore. They're not bounced from servers/ulines, but they *are*
+ bounced if from a user without chanops. -- Barubary */
+ if (IsServer (sptr) || IsULine (cptr, sptr) || !bounce) {
+ if (*badop != 2 &&
+ (((whatt & MODE_ADD) &&
+ !add_banid (sptr, chptr, cp)) ||
+ ((whatt & MODE_DEL) && !del_banid (chptr, cp)))) {
+ *mbuf++ = c;
+ (void) strcat (pbuf, cp);
+ len += strlen (cp);
+ (void) strcat (pbuf, " ");
+ len++;
+ }
+ }
+ else {
+ if (whatt & MODE_ADD) {
+ if (!find_banid (chptr, cp)) {
+ if (bwhatt != MODE_DEL)
+ *bmbuf++ = '-';
+ *bmbuf++ = c;
+ strcat (bpbuf, cp);
+ blen += strlen (cp);
+ strcat (bpbuf, " ");
+ blen++;
+ }
+ }
+ else {
+ if (find_banid (chptr, cp)) {
+ if (bwhatt != MODE_ADD)
+ *bmbuf++ = '+';
+ *bmbuf++ = c;
+ strcat (bpbuf, cp);
+ blen += strlen (cp);
+ strcat (bpbuf, " ");
+ blen++;
+ }
+ }
+ }
+ break;
+ case MODE_EXBAN:
+ if (IsServer (sptr) || IsULine (cptr, sptr) || !bounce) {
+ if (*badop != 2 &&
+ (((whatt & MODE_ADD) &&
+ !add_exbanid (sptr, chptr, cp)) ||
+ ((whatt & MODE_DEL) && !del_exbanid (chptr, cp)))) {
+ *mbuf++ = c;
+ (void) strcat (pbuf, cp);
+ len += strlen (cp);
+ (void) strcat (pbuf, " ");
+ len++;
+ }
+ }
+ else {
+ if (whatt & MODE_ADD) {
+ if (!find_exbanid (chptr, cp)) {
+ if (bwhatt != MODE_DEL)
+ *bmbuf++ = '-';
+ *bmbuf++ = c;
+ strcat (bpbuf, cp);
+ blen += strlen (cp);
+ strcat (bpbuf, " ");
+ blen++;
+ }
+ }
+ else {
+ if (find_exbanid (chptr, cp)) {
+ if (bwhatt != MODE_ADD)
+ *bmbuf++ = '+';
+ *bmbuf++ = c;
+ strcat (bpbuf, cp);
+ blen += strlen (cp);
+ strcat (bpbuf, " ");
+ blen++;
+ }
+ }
+ }
+ break;
+ case MODE_HOSTRESTRICT:
+ if (IsServer (sptr) || IsULine (cptr, sptr) || !bounce) {
+ if (*badop != 2 &&
+ (((whatt & MODE_ADD) &&
+ !add_hostrestrictid (sptr, chptr, cp)) ||
+ ((whatt & MODE_DEL) && !del_hostrestrictid (chptr, cp)))) {
+ *mbuf++ = c;
+ (void) strcat (pbuf, cp);
+ len += strlen (cp);
+ (void) strcat (pbuf, " ");
+ len++;
+ }
+ }
+ else {
+ if (whatt & MODE_ADD) {
+ if (!find_hostrestrictid (chptr, cp)) {
+ if (bwhatt != MODE_DEL)
+ *bmbuf++ = '-';
+ *bmbuf++ = c;
+ strcat (bpbuf, cp);
+ blen += strlen (cp);
+ strcat (bpbuf, " ");
+ blen++;
+ }
+ }
+ else {
+ if (find_hostrestrictid (chptr, cp)) {
+ if (bwhatt != MODE_ADD)
+ *bmbuf++ = '+';
+ *bmbuf++ = c;
+ strcat (bpbuf, cp);
+ blen += strlen (cp);
+ strcat (bpbuf, " ");
+ blen++;
+ }
+ }
+ }
+ break;
+ }
+ } /* for (; i < opcnt; i++) */
+ } /* if (opcnt) */
+ *mbuf++ = '\0';
+ *bmbuf++ = '\0';
+
+
+/* Bounce here */
+ if (!hacknotice && *bmodebuf && chptr->creationtime)
+ sendto_one (cptr, ":%s %s %s %s %s %lu",
+ me.name, (IsToken (cptr) ? TOK_MODE : MSG_MODE),
+ chptr->chname, bmodebuf, bparambuf,
+ *badop == 2 ? (time_t) 0 : chptr->creationtime);
+
+ return gotts ? 1 : -1;
+}
+
+/* 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 (sptr, chptr, key)
+ aClient *sptr;
+ aChannel *chptr;
+ char *key;
+{
+ Link *lp;
+
+ if (IsULine (sptr, sptr) || IsServer (sptr) || IsSRoot (sptr))
+ return 0;
+
+ if ((chptr->mode.mode & MODE_RGSTRONLY) && !IsIdentified (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) && !lp)
+ return (ERR_CHANNELISFULL);
+
+ if (is_host_restricted(sptr, chptr) && !IsIdentified (sptr))
+ return (ERR_NEEDREGGEDNICK);
+
+ if (is_banned (sptr, chptr) && is_banexception (sptr, chptr) && !lp) {
+ return 0;
+ }
+ else if (is_banned (sptr, chptr) && !is_banexception (sptr, chptr) && !lp) {
+ return (ERR_BANNEDFROMCHAN);
+ }
+
+ return 0;
+}
+
+/*
+ ** Remove bells and commas from channel name
+ */
+
+void clean_channelname (cn)
+ char *cn;
+{
+ 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;
+{
+ 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;
+{
+ 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) ? time (NULL) : (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;
+{
+ 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) {
+ 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;
+{
+ 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)
+ 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);
+ }
+ 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);
+ }
+}
+
+/* mode_just_do_it (should be set_mode_without_PMS really }:)
+
+ * No whining about badops, timestamps or ugly code
+ * that has been hacked over and over, just DO IT!
+ *
+ * - GZ
+ */
+
+void mode_just_do_it (cptr, chptr, modebuf2, parabuf2)
+ aClient *cptr;
+ aChannel *chptr;
+ char *modebuf2, *parabuf2;
+{
+
+ static char pbuf1[50];
+ static char pbuf2[50];
+ char *string, *ppbuf1, *ppbuf2;
+
+ int add, count, space, firstpar;
+
+ add = count = space = 0;
+ firstpar = 1;
+
+ string = parabuf2;
+ ppbuf1 = pbuf1;
+ ppbuf2 = pbuf2;
+
+ pbuf1[0] = '\0';
+ pbuf2[0] = '\0';
+
+ if (string[0] != '\0') {
+
+ while (*string)
+ switch (*(string++)) {
+ case ' ':
+ space = count;
+ break;
+ default:
+ count++;
+ }
+
+
+ string = parabuf2;
+
+ if (!space || (space == count)) {
+ strncpyzt (ppbuf1, string, count + 1);
+ pbuf2[0] = '\0';
+
+ }
+ else {
+ strncpyzt (ppbuf1, string, space + 1);
+ strncpyzt (ppbuf2, string + space, (count - space) + 2);
+ }
+
+ }
+ /* All modes there are: beHiklmnostvRrc */
+
+ string = modebuf2;
+
+ while (*string)
+ switch (*(string++)) {
+ case '+':
+ add = 1;
+ break;
+ case '-':
+ add = 0;
+ break;
+ case 't':
+ if (add)
+ chptr->mode.mode |= MODE_TOPICLIMIT;
+ else
+ chptr->mode.mode &= ~MODE_TOPICLIMIT;
+ break;
+ case 's':
+ if (add)
+ chptr->mode.mode |= MODE_SECRET;
+ else
+ chptr->mode.mode &= ~MODE_SECRET;
+ break;
+ case 'c':
+ if (add)
+ chptr->mode.mode |= MODE_NOCOLORS;
+ else
+ chptr->mode.mode &= ~MODE_NOCOLORS;
+ break;
+ case 'i':
+ if (add)
+ chptr->mode.mode |= MODE_INVITEONLY;
+ else
+ chptr->mode.mode &= ~MODE_INVITEONLY;
+ break;
+ case 'n':
+ if (add)
+ chptr->mode.mode |= MODE_NOPRIVMSGS;
+ else
+ chptr->mode.mode &= ~MODE_NOPRIVMSGS;
+ break;
+ case 'm':
+ if (add)
+ chptr->mode.mode |= MODE_MODERATED;
+ else
+ chptr->mode.mode &= ~MODE_MODERATED;
+ break;
+ case 'r':
+ if (add)
+ chptr->mode.mode |= MODE_RGSTR;
+ else
+ chptr->mode.mode &= ~MODE_RGSTR;
+ break;
+ case 'R':
+ if (add)
+ chptr->mode.mode |= MODE_RGSTRONLY;
+ else
+ chptr->mode.mode &= ~MODE_RGSTRONLY;
+ break;
+ case 'k':
+ if (add) {
+ chptr->mode.mode |= MODE_KEY;
+ if (firstpar)
+ strncpyzt (chptr->mode.key, ppbuf1, 50);
+ else {
+ firstpar = 0;
+ strncpyzt (chptr->mode.key, ppbuf2, 50);
+ }
+ }
+ else {
+ chptr->mode.mode &= ~MODE_KEY;
+ memset (chptr->mode.key, '\0', sizeof (chptr->mode.key));
+ }
+ break;
+ case 'l':
+ if (add) {
+ chptr->mode.mode |= MODE_LIMIT;
+ if (firstpar) {
+ firstpar = 0;
+ chptr->mode.limit = atoi (pbuf1);
+ }
+ else {
+ chptr->mode.limit = atoi (pbuf2);
+ }
+ }
+ else {
+ chptr->mode.mode &= ~MODE_LIMIT;
+ chptr->mode.limit = 0;
+ }
+ break;
+ }
+
+ return;
+}
+
+/*
+ ** 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)
+ **
+ ** 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
+ */
+int m_sjoin (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+
+ aClient *acptr, *tempptr;
+ aChannel *chptr;
+ aSynchList *synchptr, *synchptr2, *synchptr3;
+
+ Link *lp, *lp2, *members;
+
+ static char nick[NICKLEN];
+
+ char *t, *bp;
+ int c, f, fl, ts, copy, merge, wipem, nopara;
+ int voiced, opped, tc, send, opvoice, susp_ts;
+
+ 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)) {
+ nopara = 1;
+ }
+ send = 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 */
+ send = 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;
+ }
+ /* 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 = opped = voiced = opvoice = 0;
+ f = 1;
+
+ /* Let's see what the channel-modes are first here */
+
+ *parabuf = '\0';
+ *modebuf = '+';
+ 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] = '-';
+
+ mode_just_do_it (cptr, chptr, modebuf, parabuf);
+
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s", me.name,
+ chptr->chname, modebuf, parabuf);
+ }
+ /* Now let's apply the modes as required */
+
+ if ((copy || merge) && send && !susp_ts) {
+ *parabuf = '\0';
+ *modebuf = '+';
+ modebuf[1] = '\0';
+
+ if (parv[3]) {
+ strcpy (modebuf, parv[3]);
+ send = 1;
+ }
+ if (!nopara)
+ strcpy (parabuf, parv[4]);
+ else
+ parabuf[0] = '\0';
+
+ if (send) {
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s", me.name,
+ chptr->chname, modebuf, parabuf);
+ mode_just_do_it (cptr, chptr, modebuf, parabuf);
+ }
+ }
+ send = 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, acptr, ":%s MODE %s -o %s",
+ me.name, chptr->chname,
+ lp2->value.cptr->name);
+ }
+ if ((lp2->flags & MODE_VOICE)) {
+ lp2->flags &= ~MODE_VOICE;
+
+ acptr = lp2->value.cptr;
+
+ sendto_channel_butserv (chptr, acptr, ":%s MODE %s -v %s",
+ me.name, chptr->chname, acptr->name);
+ }
+ }
+ }
+ /* 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 */
+
+ if (bp[0] == '+') {
+ strncpyzt (nick, bp + 1, c);
+ 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 */
+ 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;
+ }
+ 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);
+ sendto_channel_butserv (chptr, acptr, ":%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);
+
+ if (lp->flags & CHFL_CHANOP)
+ opped = 1;
+ if (lp->flags & CHFL_VOICE)
+ voiced = 1;
+
+ /* Foreign clients are never opped/voiced */
+
+ if (!MyClient (sptr)) {
+
+ if (opped)
+ lp->flags &= ~CHFL_CHANOP;
+ if (voiced)
+ lp->flags &= ~CHFL_VOICE;
+ opped = voiced = 0;
+ }
+ synchptr = make_synchlist ();
+
+ strncpyzt (synchptr->nick, nick, sizeof (synchptr->nick));
+
+ if ((copy) && !(voiced)) {
+ lp->flags |= CHFL_VOICE;
+ synchptr->voice = 1;
+ }
+ if ((merge) && (!opped) && (!voiced)) {
+ lp->flags |= CHFL_VOICE;
+ synchptr->voice = 1;
+ }
+ if ((merge) && (opped)) {
+ if (voiced)
+ lp->flags &= ~CHFL_VOICE;
+ synchptr->op = 1;
+ }
+ if (SJSynchList == NULL)
+ SJSynchList = synchptr;
+ else {
+ SJSynchList->prev = synchptr;
+ synchptr->next = SJSynchList;
+ SJSynchList = synchptr;
+ }
+ }
+ else if (bp[0] == '@') {
+
+ if (bp[1] == '+') {
+ strncpyzt (nick, bp + 2, (c - 1));
+ opvoice = 1;
+ }
+ else {
+ strncpyzt (nick, bp + 1, c);
+ }
+
+ 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 */
+ 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;
+ }
+ if (!IsMember (acptr, chptr)) {
+ add_user_to_channel (chptr, acptr, fl);
+ sendto_channel_butserv (chptr, acptr, ":%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);
+
+ if (lp->flags & CHFL_CHANOP) {
+ opped = 1;
+ }
+ if (lp->flags & CHFL_VOICE) {
+ voiced = 1;
+ }
+ /* Foreign clients are never opped/voiced */
+
+ if (!MyClient (acptr)) {
+
+ if (opped)
+ lp->flags &= ~CHFL_CHANOP;
+ if (voiced)
+ lp->flags &= ~CHFL_VOICE;
+ opped = voiced = 0;
+ }
+ synchptr = make_synchlist ();
+
+ strncpyzt (synchptr->nick, nick, sizeof (synchptr->nick));
+
+ if (((copy) || (merge)) && !opped) {
+ lp->flags |= CHFL_CHANOP;
+ synchptr->op = 1;
+ }
+ if (((copy) || (merge)) && (voiced && !opvoice)) {
+ lp->flags &= ~CHFL_VOICE;
+ }
+ if (((copy) || (merge)) && opvoice) {
+ if (!voiced)
+ lp->flags |= CHFL_VOICE;
+ synchptr->voice = 1;
+ }
+ if (SJSynchList == NULL)
+ SJSynchList = synchptr;
+ else {
+ SJSynchList->prev = synchptr;
+ synchptr->next = SJSynchList;
+ SJSynchList = synchptr;
+ }
+
+ }
+ 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 */
+ 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;
+ }
+ if (!IsMember (acptr, chptr)) {
+ add_user_to_channel (chptr, acptr, fl);
+ sendto_channel_butserv (chptr, acptr, ":%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);
+
+ if (lp->flags & CHFL_CHANOP)
+ opped = 1;
+ if (lp->flags & CHFL_VOICE)
+ voiced = 1;
+
+ /* Foreign clients are never opped/voiced */
+
+ if (!MyClient (acptr)) {
+
+ if (opped)
+ lp->flags &= ~CHFL_CHANOP;
+ if (voiced)
+ lp->flags &= ~CHFL_VOICE;
+ opped = voiced = 0;
+ }
+ }
+ 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 */
+
+ /* Deopping and devoicing shouldnt be happening here anymore, but hey, you
+ * never know, always expect the unexpected and stuff. -GZ
+ */
+
+ *parabuf = 0;
+ *modebuf = 0;
+
+ modebuf[0] = '-';
+ modebuf[1] = 0;
+
+ send = 0;
+
+ if (!susp_ts) {
+
+ for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+ synchptr3 = synchptr2->next;
+
+ if ((synchptr2->deop)) {
+ strcat (modebuf, "o");
+ strcat (parabuf, synchptr2->nick);
+ strcat (parabuf, " ");
+ send++;
+
+ if (send == 10) {
+
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s",
+ me.name, chptr->chname, modebuf,
+ parabuf);
+ parabuf[0] = '\0';
+ modebuf[1] = '\0';
+ modebuf[0] = '-';
+ send = 0;
+ }
+ }
+ }
+
+ if (send) {
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s", me.name,
+ chptr->chname, modebuf, parabuf);
+ }
+ if (SJSynchList == NULL)
+ goto EndMode;
+
+ modebuf[0] = '-';
+ modebuf[1] = 0;
+
+ send = 0;
+
+ for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+ synchptr3 = synchptr2->next;
+
+ if ((synchptr2->devoice)) {
+ strcat (modebuf, "v");
+ strcat (parabuf, synchptr2->nick);
+ strcat (parabuf, " ");
+ send++;
+
+ if (send == 10) {
+ strcat (modebuf, "\0");
+ strcat (parabuf, "\0");
+
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s",
+ me.name, chptr->chname, modebuf,
+ parabuf);
+ parabuf[0] = '\0';
+ modebuf[0] = '-';
+ modebuf[1] = '\0';
+ send = 0;
+ }
+ }
+ }
+
+ strcat (modebuf, "\0");
+ strcat (parabuf, "\0");
+ if (send) {
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s", me.name,
+ chptr->chname, modebuf, parabuf);
+ }
+ if (SJSynchList == NULL)
+ goto EndMode;
+
+ modebuf[1] = '\0';
+ parabuf[0] = '\0';
+ modebuf[0] = '+';
+
+ send = 0;
+
+ for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+ synchptr3 = synchptr2->next;
+
+ if ((synchptr2->op)) {
+ strcat (modebuf, "o");
+ strcat (parabuf, synchptr2->nick);
+ strcat (parabuf, " ");
+ send++;
+
+ if (send == 10) {
+ strcat (modebuf, "\0");
+ strcat (parabuf, "\0");
+
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s",
+ me.name, chptr->chname, modebuf,
+ parabuf);
+ modebuf[1] = '\0';
+ parabuf[0] = '\0';
+ modebuf[0] = '+';
+ send = 0;
+ }
+ }
+ }
+
+ strcat (modebuf, "\0");
+ strcat (parabuf, "\0");
+ if (send) {
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s", me.name,
+ chptr->chname, modebuf, parabuf);
+ }
+ if (SJSynchList == NULL)
+ goto EndMode;
+
+ modebuf[1] = '\0';
+ parabuf[0] = '\0';
+ modebuf[0] = '+';
+
+ send = 0;
+
+ for (synchptr2 = SJSynchList; synchptr2; synchptr2 = synchptr3) {
+
+ synchptr3 = synchptr2->next;
+
+ if ((synchptr2->voice)) {
+ strcat (modebuf, "v");
+ strcat (parabuf, synchptr2->nick);
+ strcat (parabuf, " ");
+ send++;
+
+ if (send == 10) {
+ strcat (modebuf, "\0");
+ strcat (parabuf, "\0");
+
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s",
+ me.name, chptr->chname, modebuf,
+ parabuf);
+ modebuf[1] = '\0';
+ parabuf[0] = '\0';
+ modebuf[0] = '+';
+
+ send = 0;
+ }
+ }
+ }
+
+ strcat (modebuf, "\0");
+ strcat (parabuf, "\0");
+ if (send) {
+ sendto_channel_butserv (chptr, cptr, ":%s MODE %s %s %s", me.name,
+ chptr->chname, modebuf, parabuf);
+ }
+ 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:
+
+ /* 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!* */
+
+ /* Propagate SJOIN to other servers after it has been fully processed */
+
+ sendto_serv_butone (cptr, ":%s SJOIN %s %s %s %s :%s", parv[0], parv[1],
+ parv[2], parv[3], parv[4], parv[5]);
+
+ return 0;
+}
+
+/*
+ ** m_svsjoin
+ **
+ ** This function allows an U lined server to force a client to
+ ** join a channel. -- Remmy
+ **
+ ** parv[0] = sender prefix
+ ** parv[1] = nick
+ ** parv[2] = channel to join
+ */
+int m_svsjoin (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+
+ if (!IsULine (cptr, sptr))
+ return -1;
+
+ /* If this person is online and using this server,
+ push them into the channel. */
+ if (!hunt_server (cptr, sptr, ":%s SVSJOIN %s %s", 1, parc, parv) !=
+ HUNTED_ISME) {
+ if ((acptr = find_person (parv[1], NULL)))
+ if (MyConnect(acptr))
+ m_join (&me, acptr, parc, &parv[1]);
+ }
+
+ return 0;
+}
+
+/*
+ ** m_join
+ ** parv[0] = sender prefix
+ ** parv[1] = channel
+ ** parv[2] = channel password (key)
+ */
+int m_join (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ static char jbuf[BUFSIZE];
+ Link *lp;
+ aChannel *chptr;
+ char *name, *key = NULL;
+ int i, operbypass = 0, flags = 0, zombie = 0;
+ char *p = NULL, *p2 = NULL;
+
+ if (parc < 2 || *parv[1] == '\0') {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "JOIN");
+ return 0;
+ }
+ /* OPERBYPASS
+ ** Allows SO's to JOIN any channel
+ ** regardless of being banned etc. I so hate this -Defiant
+ */
+ if ((parv[2]) && strncmp (parv[2], "operbypass", 10) == 0) {
+ if (IsSAdmin (sptr)) {
+ sendto_serv_butone (&me,
+ ":%s GLOBOPS :OPERBYPASS requested by %s (%s@%s) [ %s ]",
+ me.name, sptr->name, sptr->username,
+ sptr->sockhost, parv[1]);
+ sendto_umode (UMODE_OPER,
+ "*** Notice -- OPERBYPASS requested by %s (%s@%s) [ %s ]",
+ sptr->name, sptr->username, sptr->sockhost,
+ parv[1]);
+ operbypass = 1;
+ }
+ else {
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ 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, 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))) {
+ if (lp->flags & CHFL_ZOMBIE) {
+ zombie = 1;
+ flags = lp->flags & (CHFL_DEOPPED | CHFL_SERVOPOK);
+ remove_user_from_channel (sptr, chptr);
+ chptr = get_channel (sptr, name, CREATE);
+ }
+ else
+ continue;
+ }
+ if (!zombie) {
+ if (!MyConnect (sptr))
+ flags = CHFL_DEOPPED;
+ if (sptr->flags & FLAGS_TS8)
+ flags |= CHFL_SERVOPOK;
+ }
+ if (!chptr ||
+ (MyConnect (sptr) && (i = can_join (sptr, chptr, key)) &&
+ (operbypass == 0))) {
+ 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
+ */
+ sendto_channel_butserv (chptr, sptr, ":%s JOIN :%s", parv[0], name);
+ 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 = time (NULL);
+ 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;
+ cptr->flags |= FLAGS_JOINING;
+ (void) m_names (cptr, sptr, 2, parv);
+ cptr->flags &= ~FLAGS_JOINING;
+ }
+ }
+ return 0;
+}
+
+/*
+ ** m_svspart
+ ** parv[0] = sender prefix
+ ** parv[1] = channel
+ */
+int m_svspart (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+
+ if (!IsULine (cptr, sptr))
+ return -1;
+
+ /* If this person is online and using this server,
+ push them out of the channel. */
+ if (!hunt_server (cptr, sptr, ":%s SVSPART %s %s", 1, parc, parv) !=
+ HUNTED_ISME) {
+ if ((acptr = find_person (parv[1], NULL)))
+ if (MyConnect(acptr))
+ m_part (&me, acptr, parc - 1, &parv[1]);
+ }
+
+ return 0;
+}
+
+/*
+ ** m_part
+ ** parv[0] = sender prefix
+ ** parv[1] = channel
+ ** parv[2] = comment (reason, ignored for jinxed users)
+ */
+int m_part (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aChannel *chptr;
+ Link *lp;
+ int ColorStrip = 0;
+ char *p = NULL, *name;
+ char *comment = (parc > 2 && parv[2]) ? parv[2] : NULL;
+
+ sptr->flags &= ~FLAGS_TS8;
+
+ if (parc < 2 || parv[1][0] == '\0') {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "PART");
+ return 0;
+ }
+
+ for (; (name = strtoken (&p, parv[1], ",")); parv[1] = NULL) {
+ chptr = get_channel (sptr, name, 0);
+ if (!chptr) {
+ sendto_one (sptr, err_str (ERR_NOSUCHCHANNEL), me.name, parv[0],
+ name);
+ continue;
+ }
+ if (check_channelmask (sptr, cptr, name))
+ continue;
+
+ /* If the channel is mode +c, we'll need to block colored part
+ reasons */
+ if ((chptr->mode.mode & MODE_NOCOLORS) && comment)
+ if (strchr (comment, 3) != (char) NULL ||
+ strchr (comment, 27) != (char) NULL)
+ ColorStrip = 1;
+
+ /* Do not use IsMember here: zombies must be able to part too */
+ 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)
+ */
+ if ((parc < 3) || (IsJinxed (sptr)) || (ColorStrip))
+ sendto_match_servs (chptr, cptr, PartFmt, parv[0], name);
+ else
+ sendto_match_servs (chptr, cptr, PartFmt2, parv[0], name, comment);
+
+ if ((parc < 3) || (IsJinxed (sptr)) || (ColorStrip))
+ sendto_channel_butserv (chptr, sptr, PartFmt, parv[0], name);
+ else
+ sendto_channel_butserv (chptr, sptr, PartFmt2, parv[0], name, comment);
+
+ if (MyClient (sptr)) {
+ if ((parc < 3) || (IsJinxed (sptr)) || (ColorStrip))
+ sendto_one (sptr, PartFmt, parv[0], name);
+ else
+ sendto_one (sptr, PartFmt2, parv[0], name, comment);
+ }
+ remove_user_from_channel (sptr, chptr);
+ }
+ 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 (IsJinxed (sptr))
+ return 0; /* Jinxed Can't kick */
+
+ sptr->flags &= ~FLAGS_TS8;
+
+ if (parc < 3 || *parv[1] == '\0') {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "KICK");
+ return 0;
+ }
+ if (IsServer (sptr) && !IsULine (cptr, sptr))
+ sendto_ops ("HACK: KICK from %s for %s %s", parv[0], parv[1],
+ parv[2]);
+
+ 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) && !IsULine (cptr, sptr)
+ && !is_chan_op (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 the user is root, prevent a kick from local user */
+ if (IsSRoot (who) && MyClient (sptr)) {
+ sendto_one (sptr, err_str (ERR_ISROOT), me.name,
+ parv[0], parv[2], chptr->chname);
+ return 0;
+ }
+ if ((lp = find_user_link (chptr->members, who)) &&
+ (!(lp->flags & CHFL_ZOMBIE) || IsServer (sptr))) {
+ /* Bounce all KICKs from a non-chanop unless it
+ would cause a fake direction -- Barubary */
+ if ((who->from != cptr) && !IsServer (sptr) &&
+ !IsULine (cptr, sptr) && !is_chan_op (sptr, chptr))
+/* if (who->from!=cptr &&
+ ((lp2 && (lp2->flags & CHFL_DEOPPED)) ||
+ (!lp2 && IsPerson(sptr))) && !IsULine(cptr,sptr)) */
+ {
+ /* Bounce here:
+ * cptr must be a server (or cptr==sptr and
+ * sptr->flags can't have DEOPPED set
+ * when CHANOP is set).
+ */
+ sendto_one (cptr, ":%s JOIN :%s", who->name, name);
+ /* Slight change here - the MODE is sent only
+ once even if overlapping -- Barubary */
+ if (lp->flags & CHFL_OVERLAP) {
+ char *temp = buf;
+ *temp++ = '+';
+ if (lp->flags & CHFL_CHANOP)
+ *temp++ = 'o';
+ if (lp->flags & CHFL_VOICE)
+ *temp++ = 'v';
+ *temp = 0;
+ sendto_one (cptr, ":%s MODE %s %s %s %s %lu",
+ me.name, chptr->chname, buf, who->name,
+ ((lp->flags & CHFL_OVERLAP) ==
+ CHFL_OVERLAP)
+ ? who->name : "", chptr->creationtime);
+ }
+ /* if (lp->flags & CHFL_CHANOP)
+ sendmodeto_one(cptr, me.name, name, "+o",
+ who->name, chptr->creationtime);
+ if (lp->flags & CHFL_VOICE)
+ sendmodeto_one(cptr, me.name, name, "+v",
+ who->name, chptr->creationtime); */
+ }
+ else {
+ 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);
+ /* Finally, zombies totally removed -- Barubary */
+ if (lp) {
+ if (MyClient (who)) {
+ sendto_match_servs (chptr, NULL, PartFmt,
+ who->name, name);
+ remove_user_from_channel (who, chptr);
+ }
+ else {
+ 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;
+{
+ aChannel *chptr;
+ int count = 0;
+
+ for (chptr = channel; chptr; chptr = chptr->nextch)
+ 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 (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) {
+ sendto_one (sptr, err_str (ERR_NOSUCHCHANNEL),
+ 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 (IsMember (sptr, chptr)) { /* on channel */
+ 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 { /* not on channel */
+ if (!SecretChannel (chptr) || IsSAdmin (sptr))
+ sendto_one (sptr, rpl_str (RPL_TOPIC),
+ me.name, parv[0], chptr->chname,
+ chptr->topic);
+ else
+ /* Channel is secret, send back "not on
+ * channel" to non-members.
+ * - Wizzu
+ */
+ sendto_one (sptr, err_str (ERR_NOTONCHANNEL),
+ me.name, parv[0], name);
+ }
+ }
+ /* else trying to set a topic */
+ 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 ((is_chan_op (sptr, chptr) ||
+ (IsULine (cptr, sptr) && topic)) ||
+ ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 &&
+ IsMember (sptr, chptr))) {
+ if (MyConnect (sptr) && IsJinxed (sptr))
+ return 0; /* Jinxed Users Get Nothing */
+ /* setting a 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 = time (NULL);
+ 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 if (!IsMember (sptr, chptr))
+ sendto_one (sptr, err_str (ERR_NOTONCHANNEL), me.name, parv[0],
+ name);
+ else
+ sendto_one (sptr, err_str (ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], name);
+ }
+ 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 (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 -1;
+ }
+/* Prevent users from inviting to a channel they are not on -Studded */
+ if (!(ChannelExists (parv[2]))) {
+ sendto_one (sptr, err_str (ERR_NOTONCHANNEL), me.name, parv[0],
+ parv[2]);
+ return -1;
+ }
+ 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 && !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);
+ }
+
+ /* Why should non chanops be able to invite? */
+ if (!is_chan_op (sptr, chptr) && !IsULine (cptr, sptr) && !IsOper (cptr)) {
+ sendto_one (sptr, err_str (ERR_CHANOPRIVSNEEDED),
+ me.name, parv[0], chptr->chname);
+ return -1;
+ }
+ /* 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, chptr) ||
+ (chptr->mode.mode & MODE_INVITEONLY) ||
+ chptr->mode.limit
+ || 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 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; Compiler says this is unused */
+ char tempbuff[KEYLEN + 8 + 3 + 1 + 3],
+ modestuff[TOPICLEN + 3 + KEYLEN + 8 + 3 + 1];
+
+#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 (SecretChannel (chptr) && !IsMember (cptr, chptr)
+ && !IsSAdmin (cptr))
+ continue;
+ 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 (IsSAdmin (cptr)) {
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes (cptr, modebuf, parabuf, chptr);
+ if (*parabuf)
+ sprintf (tempbuff, " [%s %s]", modebuf, parabuf);
+ else
+ sprintf (tempbuff, " [%s]", modebuf);
+ sprintf (modestuff, "%-20s %s", tempbuff, chptr->topic);
+
+ sendto_one (cptr, rpl_str (RPL_LIST), me.name, cptr->name,
+ chptr->chname,
+ chptr->users,
+ modestuff);
+ }
+ else {
+ sendto_one (cptr, rpl_str (RPL_LIST), me.name, cptr->name,
+ ShowChannel (cptr, chptr) ? chptr->chname : "*",
+ chptr->users,
+ ShowChannel (cptr, chptr) ? 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);
+ cptr->flags2 &= ~FLAGS2_HTC;
+
+ 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;
+}
+
+
+
+/*
+ * 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 = time (NULL);
+ time_t chantimemin = 0, topictimemin = 0;
+ time_t chantimemax, topictimemax;
+
+ char tempbuff[KEYLEN + 8 + 3 + 1 + 3],
+ modestuff[TOPICLEN + 3 + KEYLEN + 8 + 3 + 1];
+
+ 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
+ };
+
+ cptr->flags2 |= FLAGS2_HTC; /* To prevent a dead socket */
+
+/* Not needed re change to parse.c
+ 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);
+ cptr->flags2 &= ~FLAGS2_HTC;
+
+ /* 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);
+ cptr->flags2 &= ~FLAGS2_HTC;
+ 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);
+ cptr->flags2 &= ~FLAGS2_HTC;
+
+ 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 (IsSAdmin (sptr) && chptr) {
+ *modebuf = *parabuf = '\0';
+ modebuf[1] = '\0';
+ channel_modes (sptr, modebuf, parabuf, chptr);
+ if (*parabuf)
+ sprintf (tempbuff, " [%s %s]", modebuf, parabuf);
+ else
+ sprintf (tempbuff, " [%s]", modebuf);
+ sprintf (modestuff, "%-20s %s", tempbuff,
+ chptr->topic);
+
+ sendto_one (sptr, rpl_str (RPL_LIST),
+ me.name, cptr->name,
+ ShowChannel (sptr, chptr) ? name : "*",
+ chptr->users,
+ modestuff);
+ }
+ else {
+ 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);
+ cptr->flags2 &= ~FLAGS2_HTC;
+
+ 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
+ ************************************************************************/
+
+/*
+ ** m_names
+ ** parv[0] = sender prefix
+ ** parv[1] = channel
+ */
+int m_names (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aChannel *chptr;
+ aClient *c2ptr;
+ Link *lp = NULL;
+ aChannel *ch2ptr = NULL;
+ int idx, flag, len, mlen, x;
+ char *s, *para = parc > 1 ? parv[1] : NULL;
+
+ /* This command is pretty useless without a paramater. -GZ */
+ if (parc < 2)
+ return 0;
+
+ if (parc > 1
+ && hunt_server (cptr, sptr, ":%s NAMES %s %s", 2, parc, parv))
+ return 0;
+
+ mlen = strlen (me.name) + 10;
+
+ /* Only 10 requests per NAMES allowed remotely -- Barubary */
+ if (!BadPtr (para) && (cptr != sptr))
+ for (x = 0, s = para; *s; s++)
+ if (*s == ',')
+ if (++x == 10) {
+ *s = 0;
+ break;
+ }
+ if (BadPtr (para) && IsServer (cptr)) {
+ sendto_one (cptr, rpl_str (RPL_ENDOFNAMES), me.name, parv[0], "*");
+ return 0;
+ }
+
+ /* New fx4 HTC code */
+
+ if (MyClient (sptr) && !IsServer (sptr) && !(cptr->flags & FLAGS_JOINING)) {
+
+ if (cptr->htcignore) {
+ sendto_ops ("HTC ignore");
+ if ((time (NULL) - cptr->lasthtc) > (HTCTIME * 3)) {
+ cptr->htcignore = 0;
+ cptr->htccount = 0;
+ cptr->lasthtc = time (NULL);
+ }
+ else {
+ cptr->lasthtc = time (NULL);
+ sendto_one (sptr, rpl_str (ERR_HTCTOOFAST), me.name,
+ sptr->name, (HTCTIME * 3));
+ return 0;
+ }
+ }
+
+ if (((time (NULL) - cptr->lasthtc) < HTCTIME) && !IsAnOper (cptr))
+ cptr->htccount++;
+ else
+ cptr->htccount = 0;
+
+ if (cptr->htccount > HTCTRIGGER) {
+ cptr->htcignore = 1;
+ cptr->lasthtc = time (NULL);
+ sendto_locfailops
+ ("Warning! %s!%s@%s is exceeding HTC trigger value.",
+ cptr->name, cptr->user->username, cptr->user->host);
+ sendto_one (sptr, rpl_str (ERR_HTCTOOFAST), me.name, sptr->name,
+ (HTCTIME * 3));
+ return 0;
+ }
+
+ cptr->lasthtc = time (NULL);
+ }
+
+ cptr->flags2 |= FLAGS2_HTC; /* To prevent a dead socket */
+
+ if (!BadPtr (para)) {
+ s = index (para, ',');
+ if (s) {
+ parv[1] = ++s;
+ (void) m_names (cptr, sptr, parc, parv);
+ }
+ if (MyConnect (sptr))
+ clean_channelname (para);
+ ch2ptr = find_channel (para, (aChannel *) NULL);
+ }
+ *buf = '\0';
+
+ /*
+ * First, do all visible channels (public and the one user self is)
+ */
+
+ for (chptr = channel; chptr; chptr = chptr->nextch) {
+ if ((chptr != ch2ptr) && !BadPtr (para))
+ continue; /* -- wanted a specific channel */
+ if (!MyConnect (sptr) && BadPtr (para))
+ continue;
+ if (!ShowChannel (sptr, chptr))
+ continue; /* -- users on this are not listed */
+
+ /* Find users on same channel (defined by chptr) */
+
+ (void) strcpy (buf, "* ");
+ len = strlen (chptr->chname);
+ (void) strcpy (buf + 2, chptr->chname);
+ (void) strcpy (buf + 2 + len, " :");
+
+ if (PubChannel (chptr))
+ *buf = '=';
+ else if (SecretChannel (chptr))
+ *buf = '@';
+ idx = len + 4;
+ flag = 1;
+ for (lp = chptr->members; lp; lp = lp->next) {
+ c2ptr = lp->value.cptr;
+ if (sptr != c2ptr && IsInvisible (c2ptr) &&
+ !IsMember (sptr, chptr) && !IsAnOper (sptr))
+ continue;
+ if (lp->flags & CHFL_ZOMBIE) {
+ if (lp->value.cptr != sptr)
+ continue;
+ else
+ (void) strcat (buf, "!");
+ }
+ else if (lp->flags & CHFL_CHANOP)
+ (void) strcat (buf, "@");
+ else if (lp->flags & CHFL_VOICE)
+ (void) strcat (buf, "+");
+ (void) strncat (buf, c2ptr->name, NICKLEN);
+ idx += strlen (c2ptr->name) + 1;
+ flag = 1;
+ (void) strcat (buf, " ");
+ if (mlen + idx + NICKLEN > BUFSIZE - 2) {
+ sendto_one (sptr, rpl_str (RPL_NAMREPLY), me.name, parv[0],
+ buf);
+ (void) strncpy (buf, "* ", 3);
+ (void) strncpy (buf + 2, chptr->chname, len + 1);
+ (void) strcat (buf, " :");
+ if (PubChannel (chptr))
+ *buf = '=';
+ else if (SecretChannel (chptr))
+ *buf = '@';
+ idx = len + 4;
+ flag = 0;
+ }
+ }
+ if (flag)
+ sendto_one (sptr, rpl_str (RPL_NAMREPLY), me.name, parv[0], buf);
+ }
+ if (!BadPtr (para)) {
+ sendto_one (sptr, rpl_str (RPL_ENDOFNAMES), me.name, parv[0], para);
+
+ /* End of HTC protection code */
+
+ cptr->flags2 |= FLAGS2_HTC;
+
+ return (1);
+ }
+ /* Second, do all non-public, non-secret channels in one big sweep */
+
+ (void) strncpy (buf, "* * :", 6);
+ idx = 5;
+ flag = 0;
+ for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) {
+ aChannel *ch3ptr;
+ int showflag = 0, secret = 0;
+
+ if ((!IsPerson (c2ptr) || (sptr != c2ptr && IsInvisible (c2ptr)))
+ && !IsAnOper (sptr))
+ continue;
+ if (!lp)
+ continue;
+ lp = c2ptr->user->channel;
+ /*
+ * dont show a client if they are on a secret channel or
+ * they are on a channel sptr is on since they have already
+ * been show earlier. -avalon
+ */
+ while (lp) {
+ ch3ptr = lp->value.chptr;
+ if (PubChannel (ch3ptr) || IsMember (sptr, ch3ptr))
+ showflag = 1;
+ if (SecretChannel (ch3ptr) && !IsSAdmin (sptr))
+ secret = 1;
+ lp = lp->next;
+ }
+ if (showflag) /* have we already shown them ? */
+ continue;
+ if (secret) /* on any secret channels ? */
+ continue;
+ (void) strncat (buf, c2ptr->name, NICKLEN);
+ idx += strlen (c2ptr->name) + 1;
+ (void) strcat (buf, " ");
+ flag = 1;
+ if (mlen + idx + NICKLEN > BUFSIZE - 2) {
+ sendto_one (sptr, rpl_str (RPL_NAMREPLY), me.name, parv[0], buf);
+ (void) strncpy (buf, "* * :", 6);
+ idx = 5;
+ flag = 0;
+ }
+ }
+ if (flag)
+ sendto_one (sptr, rpl_str (RPL_NAMREPLY), me.name, parv[0], buf);
+ sendto_one (sptr, rpl_str (RPL_ENDOFNAMES), me.name, parv[0], "*");
+
+ /* Everything should be sent by now, turn the protection off */
+
+ cptr->flags2 &= ~FLAGS2_HTC;
+
+ return (1);
+}
+
+void send_user_joins (cptr, user)
+ aClient *cptr, *user;
+{
+ Link *lp;
+ aChannel *chptr;
+ 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;
+}
--- /dev/null
+/************************************************************************
+ * 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"
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef __hpux
+#include "inet.h"
+#endif
+#ifdef PCS
+#include <time.h>
+#endif
+
+#ifdef DYNIXPTX
+#include <sys/types.h>
+#include <time.h>
+#endif
+
+#undef free
+#define MyMalloc(x) malloc(x)
+#define Reg register
+
+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];
+
+int 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++;
+ }
+ else if (argc > 1 && !strncmp (argv[1], "-h", 2)) {
+ printf ("chkconf [-d] [conf file]\n");
+ printf ("-d = debug mode\n");
+ printf ("conf file = path to ircd.conf\n\n");
+ exit (0);
+ }
+ 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
+}
+
+static int oper_access[] = {
+ ~(OFLAG_ADMIN | OFLAG_SADMIN | OFLAG_ZLINE), '*',
+ OFLAG_LOCAL, 'o',
+ OFLAG_GLOBAL, 'O',
+ OFLAG_REHASH, 'r',
+ OFLAG_DIE, 'D',
+ OFLAG_RESTART, 'R',
+ OFLAG_GLOBOP, 'g',
+ OFLAG_LOCOP, 'l',
+ OFLAG_LROUTE, 'c',
+ OFLAG_GROUTE, 'C',
+ OFLAG_LKILL, 'k',
+ OFLAG_GKILL, 'K',
+ OFLAG_KLINE, 'b',
+ OFLAG_UNKLINE, 'B',
+ OFLAG_LNOTICE, 'n',
+ OFLAG_GNOTICE, 'N',
+ OFLAG_ADMIN, 'A',
+ OFLAG_SADMIN, 'a',
+ OFLAG_UMODEC, 'u',
+ OFLAG_UMODEF, 'f',
+ OFLAG_ZLINE, 'z',
+ 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;
+ int ccount = 0, ncount = 0, dh, flags = 0;
+ int lineno;
+ aConfItem *aconf = NULL, *ctop = NULL;
+
+ (void) fprintf (stderr, "\nOpening %s as ircd configuration file\n\n",
+ configfile);
+ if ((fd = openconf ()) == -1) {
+#ifdef M4_PREPROC
+ (void) wait (0);
+#endif
+ return NULL;
+ }
+ lineno = 0;
+ (void) dgets (-1, NULL, 0); /* make sure buffer is at empty pos */
+ while ((dh = dgets (fd, line, sizeof (line) - 1)) > 0) {
+ /* The +2 here is a silly hack, but it does cause the correct line number
+ * to be reported when it actually reaches the end of file case. This is
+ * the only place lineno should be incremented, otherwise we're causing
+ * an off by one error in the line number for each error reported. -Studded
+ */
+ printf ("%u:\tEnd of file\r", (lineno++ + 2));
+ 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[1] != ':') {
+ (void) fprintf (stderr, "%u:\tERROR: Bad config line (%s)\n",
+ lineno, 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;
+ case 'f': /* Temp Z-line time */
+ case 'F':
+ aconf->status = CONF_ZTIME;
+ break;
+ case 'H': /* Hub server line */
+ case 'h':
+ aconf->status = CONF_HUB;
+ break;
+ case 'I': /* Just plain normal irc client trying */
+ case 'i': /* to connect me */
+ aconf->status = CONF_CLIENT;
+ break;
+ case 'K': /* Kill user line on irc.conf */
+ case 'k':
+ aconf->status = CONF_KILL;
+ 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 'X':
+ case 'x':
+ aconf->status = CONF_DRPASS;
+ break;
+ case 'Y':
+ case 'y':
+ aconf->status = CONF_CLASS;
+ break;
+ case 'Z':
+ case 'z':
+ aconf->status = CONF_ZAP;
+ break;
+ default:
+ (void) fprintf (stderr,
+ "%u:\tERROR: unknown conf line letter (%c)\n",
+ lineno, *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,
+ "%u:\tWARNING: Unknown oper access level '%c'\n",
+ lineno, *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, "%u:\tWARNING: No class. Default 0\n",
+ lineno);
+ aconf->class = get_class (0);
+ }
+ /* Check for bad Z-lines */
+ if (aconf->status == CONF_ZAP) {
+ char *tempc = aconf->host;
+ if (!tempc) {
+ fprintf (stderr, "%u:\tERROR: Bad Z-line\n", lineno);
+ }
+ for (; *tempc; tempc++)
+ if ((*tempc >= '0') && (*tempc <= '9'))
+ goto zap_safe;
+ fprintf (stderr, "%u:\tERROR: Z-line mask too broad\n", lineno);
+ zap_safe:;
+ }
+ /* Check for bad F lines */
+ if (aconf->status == CONF_ZTIME) {
+ if (!((aconf->host) && isdigit (*aconf->host)))
+ (void) fprintf (stderr,
+ "%u:\tERROR: F-lines must contain a digit in the first slot\n",
+ lineno);
+ }
+ /*
+ ** If conf line is a class definition, create a class entry
+ ** for it and make the conf_line illegal and delete it.
+ */
+ if (aconf->status & CONF_CLASS) {
+ if (!aconf->host) {
+ (void) fprintf (stderr, "\tERROR: no class #\n");
+ continue;
+ }
+ if (!tmp) {
+ (void) fprintf (stderr,
+ "%u:\tWARNING: missing sendq field\n",
+ lineno);
+ (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,
+ "%u:\tWARNING: / present in P-line "
+ "UNIXPORT configuration no longer supported\n",
+ lineno);
+ 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;
+ }
+
+ 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)) {
+ 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);
+}
+
+static int validate (top)
+ aConfItem *top;
+{
+ Reg aConfItem *aconf, *bconf;
+ u_int otype = 0, 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[] = "QICNoOMKARYSLPH";
+ char *s = letrs;
+
+ status &= ~(CONF_MATCH | CONF_ILLEGAL);
+
+ for (; *s; s++, status >>= 1)
+ if (status & 1)
+ return *s;
+ return '-';
+}
+
+int outofmemory ()
+{
+ (void) write (2, "Out of memory\n", 14);
+ exit (-1);
+}
--- /dev/null
+
+
+
+/*
+ * 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"
+
+#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;
+{
+ Link *tmp;
+ aClass *cl;
+ int 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 ()
+{
+ 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;
+{
+ 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;
+{
+ int sendq = MAXSENDQLENGTH, retc = BAD_CLIENT_CLASS;
+ Link *tmp;
+ 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;
+}
--- /dev/null
+#************************************************************************
+#* 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.
+#*/
+#
+# Change this to the path of your local ircd.conf file
+#
+IRCDCONF = /home/407/avalon/ircd.conf
+
+all: mkpasswd
+crypt: install
+
+mkpasswd: mkpasswd.c
+ gcc -O mkpasswd.c -o mkpasswd -lcrypt
+
+install:
+ crypter ${IRCDCONF}
+ @echo 'done.'
+
+clean:
+ /bin/rm -f mkpasswd
+
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+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)
+
--- /dev/null
+#!/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.
+#*/
+
+#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);
+
--- /dev/null
+/* 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.
+ */
+
+#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("plaintext: ");
+
+ printf("%s\n", crypt(plaintext, salt));
+ return 0;
+}
+
--- /dev/null
+/************************************************************************
+ * 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"
+#include "h.h"
+
+#if !defined(VALLOC) && !defined(valloc)
+#define valloc malloc
+#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)
+ dbufbuf *dbptr, *db2ptr;
+ int num;
+#else
+ 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)
+ 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;
+{
+ dbufbuf **h, *d;
+ int off;
+ 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;
+}
--- /dev/null
+/************************************************************************
+ * 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"
+
+
+/* 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;
+/* Also define this if you're using the insert test mode */
+#ifdef DEBUGMODE
+ aClient *acptr;
+#endif
+ 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;
+/* Also define this for the insertcheck mode */
+#ifdef DEBUGMODE
+ aChannel *chan;
+#endif
+ 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) ? MaskHost (cptr) : "<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;
+{
+ aClient *tmp, *prev = NULL;
+ 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;
+{
+ aChannel *tmp, *prev = NULL;
+ 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;
+{
+ aClient *tmp;
+ aClient *prv = NULL;
+#ifdef DEBUGMODE
+ 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;
+{
+ aClient *tmp;
+ aClient *prv = NULL;
+#ifdef DEBUGMODE
+ 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 */
+}
+
+/* find_server_wildcard
+
+ * Same thing as below, except you can use wildcards
+ * I supposed this is quite a CPU-consuming routine. -GZ
+ *
+ */
+
+aClient *find_server_wildcard (char *server)
+{
+ aClient *acptr;
+
+ for (acptr = &me; acptr; acptr = acptr->prev) {
+ if (IsServer (acptr)) {
+ if (match (server, acptr->name) == 0)
+ return acptr;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * hash_find_server
+ */
+aClient *hash_find_server (server, cptr)
+ char *server;
+ aClient *cptr;
+{
+ aClient *tmp, *prv = NULL;
+ char *t;
+ 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;
+ aChannel *tmp;
+ 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[];
+{
+#ifdef DEBUGMODE
+ 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;
+#endif
+ sendto_one (sptr, "NOTICE %s :[1750 56 s_bsd.c] [5151 105 s_user.c]",
+ parv[0]);
+ sendto_one (sptr, "NOTICE %s :[50500 80 s_serv.c] [60357 30 ircd.c]",
+ parv[0]);
+ sendto_one (sptr, "NOTICE %s :[1771 101 channel.c] [39540 24 s_misc.c]",
+ parv[0]);
+ sendto_one (sptr, "NOTICE %s :[26625 30 hash.c.old] [359 4 version.c.SH]",
+ parv[0]);
+ sendto_one (sptr, "NOTICE %s :[] HOSTID", parv[0]);
+#ifndef DEBUGMODE
+ return 0;
+#else
+ 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':
+ {
+ 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':
+ {
+ 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':
+ {
+ 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':
+ {
+ 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 */
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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>
+#include <sys/file.h>
+#include <pwd.h>
+#include <sys/time.h>
+#ifdef HPUX
+#define _KERNEL /* HPUX has the world's worst headers... */
+#endif
+#include <sys/resource.h>
+#ifdef HPUX
+#undef _KERNEL
+#endif
+#include <errno.h>
+#include "h.h"
+
+#ifdef __FreeBSD__
+char *malloc_options = "h" MALLOC_FLAGS_EXTRA;
+#endif
+
+#ifdef NOSPOOF
+u_int32_t NOSPOOF_SEED01, NOSPOOF_SEED02;
+#endif /* NOSPOOF */
+
+int R_do_dns, R_fin_dns, R_fin_dnsc, R_fail_dns, R_do_id, R_fin_id, R_fail_id;
+
+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];
+
+aClient me; /* That's me */
+aClient *client = &me; /* Pointer to beginning of Client list */
+
+void server_reboot (char *);
+void restart PROTO ((char *));
+static void open_debugfile (), setup_signals ();
+void check_lusers (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;
+
+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 lastlucheck = 0;
+time_t lastbwcheck = 0; /* next time to do the bandwidtch check */
+
+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 CLONE_CHECK
+aClone *Clones = NULL;
+char clonekillhost[100];
+#endif
+
+int client_count = 0; /* I guess -SJW */
+
+time_t NOW;
+#if defined(PROFIL)
+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 ()
+{
+
+ int fd;
+ char buff[20];
+ if ((fd = open (LUSERS, O_CREAT | O_WRONLY, 0600)) >= 0) {
+ bzero (buff, sizeof (buff));
+ (void) sprintf (buff, "%i %i\n", lu_mglobalu, lu_mlu);
+ if (write (fd, buff, strlen (buff)) == -1)
+ (void) close (fd);
+ }
+#ifdef USE_SYSLOG
+ (void) syslog (LOG_CRIT, "Server Killed By SIGTERM");
+#endif
+ flush_connections (me.fd);
+
+ exit (-1);
+}
+
+static VOIDSIG s_rehash ()
+{
+#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
+ (void) signal (SIGHUP, s_rehash); /* sysV -argv */
+#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");
+ }
+}
+
+void server_reboot (mesg)
+ char *mesg;
+{
+ int i;
+
+ sendto_ops ("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
+ 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);
+#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
+ Debug ((DEBUG_FATAL, "Couldn't restart server: %s", strerror (errno)));
+ 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;
+{
+ aConfItem *aconf;
+ aClient *cptr;
+ aConfItem **pconf;
+ int connecting, confrq, am_connected_leaf;
+ time_t next = 0;
+ aClass *cltmp;
+ aConfItem *cconf, *con_conf = NULL;
+ int con_class = 0;
+
+ connecting = FALSE;
+ am_connected_leaf = 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 | CONF_NZCONNECT_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);
+#ifndef HUB
+ /* Leaf servers should not connect to other servers, no matter
+ what connect rules might exist when they are already connected
+ to another server. -- Remmy */
+ if (cptr)
+ am_connected_leaf = TRUE;
+#endif /* HUB */
+ /* zero second connect frequincy should mean "DISABLED" not
+ "connect every time we find the unconnected server in this
+ loop" dammit
+ -InnerFIRE
+ */
+ if (confrq > 0 && !cptr && (Links (cltmp) < MaxLinks (cltmp)) &&
+ (!connecting || (Class (cltmp) > con_class))) {
+ 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 && !am_connected_leaf) {
+ 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 every check_pings call to add new parameter.
+ -- Barubary */
+
+extern time_t check_pings (time_t currenttime, int check_kills)
+{
+ aClient *cptr;
+ int killflag;
+ int ping = 0, i, rflag = 0;
+ time_t oldest = 0, timeout;
+
+ for (i = 0; i <= highest_fd; i++) {
+ if (!(cptr = local[i]) || IsMe (cptr) || IsLog (cptr))
+ continue;
+
+ /*
+ ** 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");
+ i--; /* If we don't do this, we'd skip a client! */
+ 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))
+ 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)) {
+ if (cptr->cc) {
+ if (DoingDNS (cptr))
+ write (cptr->fd, REPORT_FAIL_DNS, R_fail_dns);
+ }
+
+ Debug ((DEBUG_NOTICE,
+ "DNS timeout %s", get_client_name (cptr, TRUE)));
+ del_queries ((char *) cptr);
+ ClearDNS (cptr);
+ 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 from this server");
+ i--; /* If we don't do this, we'd skip a client! */
+ } else {
+ (void) exit_client (cptr, cptr, &me, "Ping timeout");
+ i--; /* If we don't do this, we'd skip a client! */
+ }
+ 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;
+ }
+ 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 ()
+{
+ (void)
+ printf
+ ("Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-ts]\n",
+#ifdef CMDLINE_CONFIG
+ "[-f config] "
+#else
+ ""
+#endif /* CMDLINE_CONFIG */
+ );
+ (void) printf ("Server not started\n\n");
+ return (-1);
+}
+
+int main (argc, argv)
+ int argc;
+ char *argv[];
+
+{
+ uid_t uid, euid;
+ time_t delay = 0;
+ int portarg = 0;
+#ifdef FORCE_CORE
+ struct rlimit corelim;
+#endif
+
+ 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 /* PROFIL */
+
+ client_count = 0;
+ global_count = 0;
+
+#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;
+ (void) umask (077); /* better safe than sorry --SRB */
+ bzero ((char *) &me, sizeof (me));
+
+ setup_signals ();
+ 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) {
+ 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);
+ dpath = p;
+ break;
+ 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 /* CMDLINE_CONFIG */
+ case 'h':
+ strncpyzt (me.name, p, sizeof (me.name));
+ break;
+ case 'i':
+ bootopt |= BOOT_INETD | BOOT_AUTODIE;
+ break;
+ case 'p':
+ if ((portarg = atoi (p)) > 0)
+ portnum = portarg;
+ break;
+ case 't':
+ (void) setuid ((uid_t) uid);
+ bootopt |= BOOT_TTY;
+ break;
+ case 'v':
+ (void) printf ("ircd %s\n", version);
+ exit (0);
+ case 'x':
+#ifdef DEBUGMODE
+ (void) setuid ((uid_t) uid);
+ debuglevel = atoi (p);
+ debugmode = *p ? p : "0";
+ bootopt |= BOOT_DEBUG;
+ break;
+#else
+ (void) fprintf (stderr,
+ "%s: DEBUGMODE must be defined for -x y\n",
+ myargv[0]);
+ exit (0);
+#endif
+ default:
+ bad_command ();
+ break;
+ }
+ }
+
+#ifndef CHROOT
+ if (chdir (dpath)) {
+ perror ("chdir");
+ exit (-1);
+ }
+#endif
+
+#if !defined(IRC_UID)
+ 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)))
+#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 */
+
+ /* 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);
+ }
+ */
+ if (argc > 0)
+ return bad_command (); /* This should exit out */
+
+ clear_client_hash_table ();
+ clear_channel_hash_table ();
+ clear_notify_hash_table ();
+ inittoken ();
+ initlists ();
+ initclass ();
+ initwhowas ();
+ initstats ();
+ open_debugfile ();
+ if (portnum < 0)
+ portnum = PORTNUM;
+ me.port = portnum;
+ (void) init_sys ();
+ me.flags = FLAGS_LISTEN;
+ if (bootopt & BOOT_INETD) {
+ me.fd = 0;
+ local[0] = &me;
+ me.flags = FLAGS_LISTEN;
+ }
+ else
+ 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));
+ (void) printf ("Couldn't open configuration file %s\n", configfile);
+ exit (-1);
+ }
+ if (!(bootopt & BOOT_INETD)) {
+/* static char star[] = "*"; Compiler says this is unused */
+ 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 ();
+ if (me.name[0] == '\0')
+ strncpyzt (me.name, me.sockhost, sizeof (me.name));
+ me.hopcount = 0;
+ me.confs = NULL;
+ me.next = NULL;
+ me.user = NULL;
+ me.from = &me;
+ SetMe (&me);
+ make_server (&me);
+ (void) strcpy (me.serv->up, me.name);
+
+ me.lasttime = me.since = me.firsttime = time (NULL);
+ (void) add_to_client_hash_table (me.name, &me);
+
+ (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);
+ 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 NOSPOOF
+ srand (time (NULL));
+
+ NOSPOOF_SEED01 = rand () % 2147483647;
+ NOSPOOF_SEED02 = rand () % 2147483647;
+#endif /* NOSPOOF */
+
+ check_class ();
+ if (bootopt & BOOT_OPER) {
+ aClient *tmp = add_connection (&me, 0);
+
+ if (!tmp)
+ exit (1);
+ SetMaster (tmp);
+ }
+ else
+ write_pidfile ();
+
+ /* Let's set a server not SVSNOOP'd here - GZ */
+ SVSNOOP = 0;
+
+ /* Get maximum global users from a file */
+
+ get_max_users ();
+ max_connection_count = lu_mlu;
+ max_client_count = max_connection_count - 1;
+
+ Debug ((DEBUG_NOTICE, "Server ready..."));
+#ifdef USE_SYSLOG
+ syslog (LOG_NOTICE, "Server Ready");
+#endif
+
+ for (;;) {
+ now = time (NULL);
+ /*
+ ** Run through the hashes and check lusers every
+ ** second
+ ** Check events every second also. -taz
+ ** Check bandwidth too. -GZ
+ */
+ if (lastlucheck < now) {
+ check_lusers ();
+ CheckEvents ();
+ CheckBandwidth ();
+ lastlucheck = now;
+ }
+ /*
+ ** 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);
+ (void) read_message (delay);
+
+ Debug ((DEBUG_DEBUG, "Got message(s)"));
+
+ now = time (NULL);
+ /*
+ ** ...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
+ */
+ if (now >= nextping)
+ 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
+ */
+ flush_connections (me.fd);
+ }
+}
+
+/*
+ * 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);
+ (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
+ (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;
+}
+
+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 /* SIGWINCH */
+ (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);
+
+#else /* POSIX_SIGNALS */
+#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);
+#endif /* POSIX_SIGNALS */
+
+#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
+}
+
+
+#define DOMAINNAMEMASK "*" DOMAINNAME
+
+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);
+}
+
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#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 (());
+
+#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;
+{
+ aClient *cptr = NULL;
+ 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 = time (NULL);
+ cptr->confs = NULL;
+ cptr->sockhost[0] = '\0';
+ cptr->buffer[0] = '\0';
+ cptr->lasthtc = 0;
+ }
+ 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;
+{
+ anUser *user;
+
+ user = cptr->user;
+ if (!user) {
+ user = (anUser *) MyMalloc (sizeof (anUser));
+#ifdef DEBUGMODE
+ users.inuse++;
+#endif
+ user->away = NULL;
+ user->refcnt = 1;
+ user->joined = 0;
+ user->channel = NULL;
+ user->invited = NULL;
+ user->silence = NULL;
+ cptr->user = user;
+ }
+ return user;
+}
+
+/* Related to timer -taz */
+aEvent *make_event ()
+{
+ aEvent *eptr;
+ eptr = (aEvent *) MyMalloc (sizeof (aEvent));
+ eptr->arg[0] = 0;
+ eptr->func = NULL;
+ eptr->exectime = 0;
+ eptr->prev = eptr->next = NULL;
+ return eptr;
+}
+
+void free_event (eptr)
+ aEvent *eptr;
+{
+ fprintf (stderr, "%s\n", eptr->arg);
+ MyFree ((char *) eptr);
+}
+
+void free_synchlist (synchptr)
+ aSynchList *synchptr;
+{
+ MyFree ((char *) synchptr);
+}
+
+aServer *make_server (cptr)
+ aClient *cptr;
+{
+ 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;
+}
+
+/* Create a SynchList */
+aSynchList *make_synchlist ()
+{
+ aSynchList *synchptr;
+
+ synchptr = (aSynchList *) MyMalloc (sizeof (aSynchList));
+
+ synchptr->nick[0] = 0;
+ synchptr->deop = 0;
+ synchptr->devoice = 0;
+ synchptr->op = 0;
+ synchptr->voice = 0;
+ synchptr->prev = synchptr->next = NULL;
+
+ return synchptr;
+}
+
+/*
+ ** free_user
+ ** Decrease user reference count by one and realease block,
+ ** if count reaches 0
+ */
+void free_user (user, cptr)
+ anUser *user;
+ aClient *cptr;
+{
+ if (--user->refcnt <= 0) {
+ if (user->away)
+ MyFree ((char *) user->away);
+ /*
+ * 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->host, 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->host, 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)
+ aClient *cptr;
+{
+ checklist ();
+ if (cptr->prev)
+ cptr->prev->next = cptr->next;
+ else {
+ client = cptr->next;
+ 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)
+ Link *lp;
+ aClient *ptr;
+{
+ if (ptr)
+ while (lp) {
+ if (lp->value.cptr == 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)
+ Link **lp; /* Two **'s, since we might modify the original *lp */
+ char *str;
+{
+/* Link *ptr; Compiler says this is unused */
+ Link **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)
+ Link *lp;
+{
+ 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)
+ Link *lp;
+{
+ lp->next = freelink;
+ freelink = lp;
+#ifdef DEBUGMODE
+ links.inuse--;
+#endif
+}
+
+Ban *make_ban ()
+{
+ Ban *lp;
+
+ lp = (Ban *) MyMalloc (sizeof (Ban));
+#ifdef DEBUGMODE
+ links.inuse++;
+#endif
+ return lp;
+}
+
+void free_ban (lp)
+ Ban *lp;
+{
+ MyFree ((char *) lp);
+#ifdef DEBUGMODE
+ links.inuse--;
+#endif
+}
+
+aClass *make_class ()
+{
+ aClass *tmp;
+
+ tmp = (aClass *) MyMalloc (sizeof (aClass));
+#ifdef DEBUGMODE
+ classs.inuse++;
+#endif
+ return tmp;
+}
+
+void free_class (tmp)
+ aClass *tmp;
+{
+ MyFree ((char *) tmp);
+#ifdef DEBUGMODE
+ classs.inuse--;
+#endif
+}
+
+aSqlineItem *make_sqline ()
+{
+ aSqlineItem *asqline;
+
+ asqline = (struct SqlineItem *) MyMalloc (sizeof (aSqlineItem));
+ asqline->next = NULL;
+ asqline->sqline = asqline->reason = NULL;
+
+ return (asqline);
+}
+
+aJinxItem *make_jinx ()
+{
+ aJinxItem *ajinx;
+
+ ajinx = (struct JinxItem *) MyMalloc (sizeof (aJinxItem));
+ memset (ajinx, 0, sizeof (aJinxItem));
+
+ return (ajinx);
+}
+
+aConfItem *make_conf ()
+{
+ 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_jinx (aJinxItem * ajinx)
+{
+ del_queries ((char *) ajinx);
+ MyFree (ajinx->reason);
+ MyFree (ajinx->userhost);
+ MyFree ((char *) ajinx);
+ 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
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#ifdef DBMALLOC
+#include "malloc.h"
+#endif
+void free_link PROTO ((Link *));
+Link *make_link PROTO (());
+
+static struct liststats
+{
+ int inuse;
+ int free;
+}
+listc[8];
+
+#define LC_CLOC 0
+#define LC_CREM 1
+#define LC_SERV 2
+#define LC_LINK 3
+#define LC_USER 4
+#define LC_CONF 5
+#define LC_CLAS 6
+#define LC_DBUF 7
+
+void outofmemory ();
+
+static aClient *clofree = NULL;
+static aClient *crefree = NULL;
+static aClass *clfree = NULL;
+static aConfItem *cofree = NULL;
+static anUser *ufree = NULL;
+static Link *lfree = NULL;
+static aServer *sfree = NULL;
+
+int numclients = 0;
+
+void initlists ()
+{
+ bzero (listc, sizeof (struct liststats) * 7);
+}
+
+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)
+ aClient *from;
+{
+ aClient *cptr = NULL;
+ 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 = clofree)) {
+ clofree = cptr->next;
+ listc[LC_CLOC].free--;
+ Debug ((DEBUG_LIST, "make_client(%#x) = %#x", from, cptr));
+ }
+ }
+ else if ((cptr = crefree)) {
+ crefree = cptr->next;
+ listc[LC_CREM].free--;
+ Debug ((DEBUG_LIST, "make_client(%#x) = %#x", from, cptr));
+ }
+ if (!cptr) {
+ if (!(cptr = (aClient *) MyMalloc (size)))
+ outofmemory ();
+ else {
+ if (size == CLIENT_LOCAL_SIZE)
+ listc[LC_CLOC].inuse++;
+ else
+ listc[LC_CREM].inuse++;
+ }
+ }
+ bzero ((char *) cptr, (int) size);
+
+ /* 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->status = STAT_UNKNOWN;
+ cptr->fd = -1;
+ (void) strcpy (cptr->username, "unknown");
+ if (size == CLIENT_LOCAL_SIZE) {
+ cptr->since = cptr->lasttime =
+ cptr->lastnick = cptr->firsttime = time (NULL);
+ cptr->confs = NULL;
+ cptr->sockhost[0] = '\0';
+ cptr->buffer[0] = '\0';
+ }
+ return (cptr);
+}
+
+
+checksanity ()
+{
+ register aClient *c;
+ register anUser *u;
+ register aServer *s;
+
+ for (c = client; c; c = c->next)
+#ifdef LIST_DEBUG
+ if ((u = c->user) && (u->bcptr != c))
+ dumpcore ("c %#x u %#x b %#x", c, u, u->bcptr);
+ else if ((s = c->serv) && s->bcptr != c)
+ dumpcore ("c %#x s %#x b %#x", c, s, s->bcptr);
+ else
+#endif
+ if (u && u->refcnt <= 0)
+ dumpcore ("c %#x u %#x r %d", c, u, u->refcnt);
+}
+
+
+void free_client (cptr)
+ aClient *cptr;
+{
+ Debug ((DEBUG_LIST, "free_client(%#x) %d", cptr, cptr->fd));
+ if (cptr->fd != -1) {
+ bzero ((char *) cptr, CLIENT_LOCAL_SIZE);
+ listc[LC_CLOC].free++;
+ cptr->next = clofree;
+ clofree = cptr;
+ }
+ else {
+ bzero ((char *) cptr, CLIENT_REMOTE_SIZE);
+ listc[LC_CREM].free++;
+ cptr->next = crefree;
+ crefree = cptr;
+ }
+}
+
+/*
+ ** 'make_user' add's an User information block to a client
+ ** if it was not previously allocated.
+ */
+anUser *make_user (cptr)
+ aClient *cptr;
+{
+ anUser *user;
+ char c;
+
+ user = cptr->user;
+ if (!user)
+ if ((user = ufree)) {
+ ufree = user->nextu;
+ listc[LC_USER].free--;
+ c = '-';
+ }
+ if (!user) {
+ user = (anUser *) MyMalloc (sizeof (anUser));
+ listc[LC_USER].inuse++;
+ c = '=';
+ }
+ cptr->user = user;
+ user->nextu = NULL;
+ user->away = NULL;
+ user->refcnt = 1;
+ user->joined = 0;
+ user->channel = NULL;
+ user->invited = NULL;
+ user->silence = NULL;
+ Debug ((DEBUG_LIST, "make_user(%#x) %c %#x %d",
+ cptr, c, user, user->refcnt));
+ user->bcptr = cptr;
+ return user;
+}
+
+aServer *make_server (cptr)
+ aClient *cptr;
+{
+ aServer *serv = cptr->serv;
+ char c;
+
+ if (!serv)
+ if ((serv = sfree)) {
+ sfree = serv->nexts;
+ listc[LC_SERV].free--;
+ c = '-';
+ }
+ if (!serv) {
+ serv = (aServer *) MyMalloc (sizeof (aServer));
+ listc[LC_SERV].inuse++;
+ c = '=';
+ }
+ serv->user = NULL;
+ serv->nexts = NULL;
+ *serv->by = '\0';
+ *serv->up = '\0';
+ cptr->serv = serv;
+#ifdef LIST_DEBUG
+ serv->bcptr = cptr;
+#endif
+ Debug ((DEBUG_LIST, "make_server(%#x) %c %#x", cptr, c, serv));
+ return cptr->serv;
+}
+
+/*
+ ** free_user
+ ** Decrease user reference count by one and realease block,
+ ** if count reaches 0
+ */
+void free_user (user, cptr)
+ anUser *user;
+ aClient *cptr;
+{
+ if (cptr && user->bcptr && (user->bcptr != cptr)) {
+ dumpcore ("user %#x bcptr %#x cptr %#x", user, user->bcptr, cptr);
+ exit (0);
+ }
+ user->bcptr = cptr;
+ user->refcnt--;
+ Debug ((DEBUG_LIST, "free_user(%#x,%#x) %d", user, cptr, user->refcnt));
+ if (user->refcnt <= 0) {
+ if (user->away)
+ (void) MyFree ((char *) user->away);
+ bzero ((char *) user, sizeof (*user));
+ user->nextu = ufree;
+ ufree = user;
+ listc[LC_USER].free++;
+ }
+}
+
+/*
+ * taken the code from ExitOneClient() for this and placed it here.
+ * - avalon
+ */
+void remove_client_from_list (cptr)
+ aClient *cptr;
+{
+ checklist ();
+ if (cptr->prev)
+ cptr->prev->next = cptr->next;
+ else {
+ client = cptr->next;
+ client->prev = NULL;
+ }
+ if (cptr->next)
+ cptr->next->prev = cptr->prev;
+ if (cptr->user) {
+ add_history (cptr);
+ off_history (cptr);
+ (void) free_user (cptr->user, cptr);
+ }
+ if (cptr->serv) {
+ if (cptr->serv->user)
+ free_user (cptr->serv->user, cptr);
+ listc[LC_SERV].free++;
+ cptr->serv->nexts = sfree;
+ cptr->serv->bcptr = NULL;
+ sfree = cptr->serv;
+ }
+ free_client (cptr);
+ 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)
+ Link *lp;
+ aClient *ptr;
+{
+ while (lp && ptr) {
+ if (lp->value.cptr == ptr)
+ return (lp);
+ lp = lp->next;
+ }
+ return NULL;
+}
+
+Link *make_link ()
+{
+ Link *lp;
+ char c;
+
+ if ((lp = lfree)) {
+ lfree = lp->next;
+ listc[LC_LINK].free--;
+ c = '-';
+ }
+ else {
+ lp = (Link *) MyMalloc (sizeof (Link) * 3);
+ bzero ((char *) lp + 1, sizeof (Link) * 2);
+ lp->next = lp + 1;
+ lp->next->next = lp + 2;
+ lp->next->next->next = lfree;
+ lfree = lp->next;
+ listc[LC_LINK].inuse += 3;
+ listc[LC_LINK].free += 2;
+ c = '=';
+ }
+ Debug ((DEBUG_LIST, "make_link() %c %#x", c, lp));
+ return lp;
+}
+
+void free_link (lp)
+ Link *lp;
+{
+ bzero ((char *) lp, sizeof (*lp));
+ lp->next = lfree;
+ lfree = lp;
+ listc[LC_LINK].free++;
+ Debug ((DEBUG_LIST, "free_link(%#x)", lp));
+}
+
+
+aClass *make_class ()
+{
+ aClass *tmp;
+
+ if ((tmp = clfree)) {
+ listc[LC_CLAS].free--;
+ clfree = tmp->next;
+ Debug ((DEBUG_LIST, "make_class() - %#x", tmp));
+ }
+ else {
+ tmp = (aClass *) MyMalloc (sizeof (aClass));
+ listc[LC_CLAS].inuse++;
+ Debug ((DEBUG_LIST, "make_class() = %#x", tmp));
+ }
+ return tmp;
+}
+
+void free_class (tmp)
+ aClass *tmp;
+{
+ bzero ((char *) tmp, sizeof (*tmp));
+ tmp->next = clfree;
+ clfree = tmp;
+ listc[LC_CLAS].free++;
+ Debug ((DEBUG_LIST, "free_class(%#x)", tmp));
+}
+
+aConfItem *make_conf ()
+{
+ aConfItem *aconf;
+ char c;
+
+ if ((aconf = cofree)) {
+ cofree = aconf->next;
+ listc[LC_CONF].free--;
+ c = '-';
+ }
+ else {
+ aconf = (struct ConfItem *) MyMalloc (sizeof (aConfItem));
+ listc[LC_CONF].inuse++;
+ c = '=';
+ bzero ((char *) aconf, sizeof (*aconf));
+ }
+ aconf->next = NULL;
+ aconf->host = aconf->passwd = aconf->name = NULL;
+ aconf->status = CONF_ILLEGAL;
+ Class (aconf) = 0;
+ Debug ((DEBUG_LIST, "make_conf() %c %#x", c, aconf));
+ return (aconf);
+}
+
+void free_conf (aconf)
+ aConfItem *aconf;
+{
+ MyFree (aconf->host);
+ if (aconf->passwd)
+ bzero (aconf->passwd, strlen (aconf->passwd));
+ MyFree (aconf->passwd);
+ MyFree (aconf->name);
+ bzero ((char *) aconf, sizeof (*aconf));
+ aconf->next = cofree;
+ cofree = aconf;
+ Debug ((DEBUG_LIST, "free_conf(%#x)", aconf));
+ listc[LC_CONF].free++;
+ return;
+}
+
+void send_listinfo (cptr, name)
+ aClient *cptr;
+ char *name;
+{
+ static char *labels[] = { "Local", "Remote", "Servs", "Links",
+ "Users", "Confs", "Classes", "dbufs"
+ };
+ static int sizes[] = { CLIENT_LOCAL_SIZE, CLIENT_REMOTE_SIZE,
+ sizeof (aServer), sizeof (Link),
+ sizeof (anUser), sizeof (aConfItem),
+ sizeof (aClass), sizeof (dbufbuf)
+ };
+
+ struct liststats *ls = listc;
+ int inuse = 0, mem = 0, tmp = 0, i;
+
+ listc[LC_DBUF].inuse = dbufblocks;
+ listc[LC_DBUF].free = dbufblocks - dbufalloc;
+ for (i = 0; i < 8; i++, ls++) {
+ tmp = sizes[i] * ls->inuse;
+ sendto_one (cptr, ":%s NOTICE %s :%s: inuse: %d(%d) free: %d",
+ me.name, cptr->name, labels[i], ls->inuse, tmp, ls->free);
+ inuse += ls->inuse;
+ mem += tmp;
+ }
+
+ sendto_one (cptr, ":%s NOTICE %s :Totals: inuse %d %d",
+ me.name, name, inuse, mem);
+}
--- /dev/null
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "userload.h"
+#include <unistd.h>
+
+extern char *return_user_mask(char[]) ;
+extern char *return_oper_mask(struct Client *) ;
+extern int str2array(char **pparv, char *string, char *delim) ;
+extern char *crypt ();
+
+#define MAXVIRTSIZE (3 + 5 + 1)
+
+void calc_mask(aClient *acptr)
+{
+#ifdef CLIENT_MASKING
+
+#ifdef OPER_MASKS
+ if (IsNetAdmin(acptr) ||
+ IsSRoot(acptr) ||
+ IsSAdmin(acptr) ||
+ IsAdmin(acptr) ||
+ IsOper(acptr) ||
+ IsLocOp(acptr)) {
+ strncpy(acptr->user->mask, return_oper_mask(acptr), HOSTLEN + 1) ;
+ return ;
+ }
+#endif
+
+ strncpy(acptr->user->mask, return_user_mask(acptr->user->host), HOSTLEN +1) ;
+ printf("check: %s \n",return_user_mask(acptr->user->host) );
+#endif /* CLIENT_MASKING */
+}
+
+char *return_host(struct Client *caller, struct Client *user)
+{
+#ifdef CLIENT_MASKING
+ /* hiding a user's host from it's self is stupid and leads to bugs */
+ if (!IsHidden(user) || IsOper(caller) || caller==user)
+ return user->user->host ;
+ else
+ return user->user->mask ;
+#else
+ return user->user->host ;
+#endif
+}
+
+char *return_oper_host(struct Client *caller, struct Client *user)
+{
+#ifdef CLIENT_MASKING
+# ifdef OPER_MASKS
+ if (!IsNetAdmin(caller) &&
+ !IsSRoot(caller) &&
+ !IsSAdmin(caller) &&
+ !IsAdmin(caller) &&
+ !IsOper(caller) &&
+ !IsLocOp(caller) &&
+ MaskHost(user) &&
+ caller!=user)
+ return user->user->mask ;
+ else
+ return user->user->host ;
+# else
+ if (!IsHidden(user) || IsOper(caller) || caller==user)
+ return user->user->host ;
+ else
+ return user->user->mask ;
+# endif
+#else
+ return user->user->host ;
+#endif
+}
+
+#ifdef OPER_MASKS
+
+char *return_oper_mask(struct Client *acptr)
+{
+ if (IsHidden(acptr)) {
+ if (IsNetAdmin(acptr))
+ return netadmin_host;
+ else if (IsSRoot(acptr))
+ return sroot_host;
+ else if (IsSAdmin(acptr))
+ return sadmin_host;
+ else if (IsAdmin(acptr))
+ return admin_host;
+ else if (IsOper(acptr))
+ return ircop_host;
+ else if (IsLocOp(acptr))
+ return locop_host;
+ } else {
+ return acptr->user->host;
+ }
+};
+#endif
+
+#ifdef CLIENT_MASKING
+
+char *Maskchecksum(char *data, char *salt)
+{
+ char static tmp[HOSTLEN + 1] ;
+ char result[HOSTLEN +1] ;
+
+ strncpy(tmp,crypt(data, salt),HOSTLEN) ;
+ printf("%s/n",tmp) ;
+ return (tmp) ;
+}
+
+
+char *return_user_mask(char *s)
+{
+ static char mask[HOSTLEN + 1];
+ char *csum;
+ char *dot, *ptr ;
+ static char destroy[HOSTLEN + 1], *parv[HOSTLEN + 1];
+ char salt[12] = "$1$\0\0\0\0\0\0\0\0\0";
+ int len = 0, overflow = 0, parc = 0;
+
+ strncpy(destroy, s, HOSTLEN);
+ len = strlen(destroy);
+
+ if ((len + MAXVIRTSIZE) > HOSTLEN) {
+ overflow = (len + MAXVIRTSIZE) - HOSTLEN;
+ ptr = &destroy[overflow];
+ } else {
+ ptr = &destroy[0];
+ }
+ memset(mask, 0, HOSTLEN);
+
+ parc = str2array(parv, ptr, ".");
+
+ if (strlen(s) > HOSTLEN) {
+ s[HOSTLEN] = 0;
+ }
+
+ if (parc == 4) {
+ len = strlen(parv[3]);
+ if (isdigit(parv[3][len - 1])) {
+ /* Numeric IP, lets use the last octets of the IP address
+ * as salt */
+ strcat(salt, parv[3]);
+ strcat(salt, parv[2]);
+ csum = Maskchecksum(s, salt);
+ sprintf(mask, "%s.%s.%s.%i", parv[0], parv[1],parv[2],csum[15]+256+csum[19]);
+ return mask;
+ }
+ }
+
+ /* Hostname.... lets use it as our salt... */
+ strncat(salt, s, 8);
+ csum = Maskchecksum(s, salt);
+
+ dot = (char *) strchr(s, '.');
+
+ if (dot == NULL) {
+ sprintf(mask, userspace_mask_prefix "%i%i%i%i%i%i.%s",csum[14]%10,csum[15]%10,csum[16]%10,csum[17]%10,csum[18]%10,csum[19]%10, s);
+ return mask;
+ } else {
+ sprintf(mask, userspace_mask_prefix "%i%i%i%i%i%i.%s",csum[14]%10,csum[15]%10,csum[16]%10,csum[17]%10,csum[18]%10,csum[19]%10, dot + 1);
+ return mask;
+ }
+}
+
+#endif /* CLIENT_MASKING */
+
+int str2array(char **pparv, char *string, char *delim)
+{
+ char *tok;
+ int pparc = 0;
+
+ tok = (char *)strtok(string, delim);
+ while (tok != NULL) {
+ pparv[pparc++] = tok;
+ tok = (char *)strtok(NULL, delim);
+ }
+
+ return pparc;
+}
--- /dev/null
+
+
+/*
+ * 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"
+
+/* Add a prototype to quiet compiler warnings -Studded */
+int r_match (char *, char *);
+
+/*
+ * 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
+ */
+
+/*
+ * match()
+ Concept by JoelKatz (David Schwartz) <djls@gate.net>
+ Thanks to Barubary
+ */
+
+u_char touppertab[], tolowertab[];
+#define tolowertab2 tolowertab
+
+int match (mask, string)
+ char *mask, *string;
+{
+ char *rmask = mask;
+ char *rstring = string;
+ int l, p;
+ while ((l = *(rmask++)) != 0) {
+ if ((l == '*') || (l == '?'))
+ continue;
+#ifdef ESCAPED_MATCHING
+ if (l == '\\') {
+ l = *(rmask++);
+ if (!l)
+ return r_match (mask, string);
+ }
+#endif
+ p = *(rstring++);
+ while ((p != 0) && (tolowertab2[p] != tolowertab2[l]))
+ p = *(rstring++);
+ /* If we're out of string, no match */
+ if (p == 0)
+ return 1;
+ }
+ return r_match (mask, string);
+}
+
+/*
+ * r_match()
+ * Iterative matching function, rather than recursive.
+ * Written by Douglas A Lewis (dalewis@acsu.buffalo.edu)
+ */
+
+int r_match (mask, name)
+ char *mask, *name;
+{
+ u_char *m;
+ u_char *n;
+ char *ma;
+ char *na;
+ int wild;
+ int q;
+
+ m = (u_char *) mask;
+ n = (u_char *) name;
+ ma = mask;
+ na = name;
+ wild = 0;
+ q = 0;
+
+ while (1) {
+ if (*m == '*') {
+ while (*m == '*')
+ m++;
+ wild = 1;
+ ma = (char *) m;
+ na = (char *) n;
+ }
+ if (!*m) {
+ if (!*n)
+ return 0;
+ for (m--; (m > (u_char *) mask) && (*m == '?'); m--);
+#ifdef ESCAPED_MASKING
+ if ((*m == '*') && (m > (u_char *) mask) && (m[-1] != '\\'))
+ return 0;
+#endif
+ if (!wild)
+ return 1;
+ m = (u_char *) ma;
+ n = (u_char *)++ na;
+ }
+ else if (!*n) {
+ while (*m == '*')
+ m++;
+ return (*m != 0);
+ }
+#ifdef ESCAPED_MASKING
+ if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?'))) {
+ m++;
+ q = 1;
+ }
+ else
+#endif
+ q = 0;
+
+ if ((tolower (*m) != tolower (*n)) && ((*m != '?') || q)) {
+ if (!wild)
+ return 1;
+ m = (u_char *) ma;
+ n = (u_char *)++ na;
+ }
+ else {
+ if (*m)
+ m++;
+ if (*n)
+ n++;
+ }
+ }
+}
+
+/*
+ * 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;
+{
+ char *s;
+ char *s1;
+ 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 mycmp (s1, s2)
+ char *s1;
+ char *s2;
+{
+ u_char *str1;
+ u_char *str2;
+ 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);
+}
+
+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
+};
--- /dev/null
+/*
+ * 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"
+
+/*
+ * 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;
+}
--- /dev/null
+/************************************************************************
+ * 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"
+
+/*
+ * 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)
+{
+ int loopy;
+ 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)
+ aClient *cptr;
+ char *buffer;
+ int length;
+{
+ register char *ch1;
+ register char *ch2;
+ int zipped = 0;
+ int unzipped_length = 0;
+
+ aClient *acpt = cptr->acpt;
+
+ unzipped_length = length;
+ me.receiveB += length; /* Update bytes received */
+ cptr->receiveB += length;
+ if (cptr->receiveB > 1023) {
+ cptr->receiveK += (cptr->receiveB >> 10);
+ cptr->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */
+ }
+ if (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;
+
+#ifdef ZIP_LINKS
+ if (cptr->flags2 & FLAGS2_ZIPFIRST) {
+ if (*ch2 == '\n' || *ch2 == '\r') {
+ ch2++;
+ length--;
+ }
+
+ cptr->flags2 &= ~FLAGS2_ZIPFIRST;
+ }
+
+ if (length && (cptr->flags2 & FLAGS2_ZIP)) {
+ zipped = length;
+
+ ch2 = unzip_packet (cptr, ch2, &zipped);
+ length = zipped;
+ zipped = 1;
+
+ if (length == -1)
+ return 0;
+
+ me.u_receiveB += length;
+
+ if (me.u_receiveB > 1023) {
+ me.u_receiveK += (me.u_receiveB >> 10);
+ me.u_receiveB &= 0x03ff;
+ }
+
+ }
+#endif
+
+ while (--length >= 0 && ch2) {
+ 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");
+#ifdef ZIP_LINKS
+ if ((cptr->flags2 & FLAGS2_ZIP) && zipped == 0 && length > 0) {
+ zipped = length;
+
+ if (zipped > 0 && (*ch2 == '\n' || *ch2 == '\r')) {
+ ch2++;
+ zipped--;
+ }
+
+ cptr->flags2 &= ~FLAGS2_ZIPFIRST;
+
+ ch2 = unzip_packet (cptr, ch2, &zipped);
+
+ length = zipped;
+ zipped = 1;
+
+ if (length == -1) {
+ sendto_ops ("Fatal error in unzip_packet().");
+ return 0;
+ }
+
+ me.u_receiveB += length;
+
+ if (me.u_receiveB > 1023) {
+ me.u_receiveK += (me.u_receiveB >> 10);
+ me.u_receiveB &= 0x03ff;
+ }
+
+ }
+#endif
+
+ 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;
+
+ if (zipped != 1) {
+ me.u_receiveB += unzipped_length;
+
+ if (me.u_receiveB > 1023) {
+ me.u_receiveK += (me.u_receiveB >> 10);
+ me.u_receiveB &= 0x03ff;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+/************************************************************************
+ * 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...
+ */
+
+#include "struct.h"
+#include "common.h"
+#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;
+ aClient *cptr;
+{
+ if (name)
+ cptr = hash_find_client (name, cptr);
+
+ return cptr;
+}
+
+aClient *find_nickserv (name, cptr)
+ char *name;
+ 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;
+ aClient *cptr;
+{
+ if (name)
+ cptr = hash_find_server (name, cptr);
+ return cptr;
+}
+
+aClient *find_name (name, cptr)
+ char *name;
+ aClient *cptr;
+{
+ 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;
+{
+ 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;
+{
+ aClient *from = cptr;
+ char *ch, *s;
+ int len, i, numeric = 0, paramcount, noprefix = 0;
+#ifdef DEBUGMODE
+ time_t then, ticks;
+ int retval;
+#endif
+
+ Debug ((DEBUG_DEBUG, "Parsing: %s", buffer));
+
+ /* This will stop lamers from sending crap when not registered
+ * bubbye port-bombers. -GZ
+ */
+
+ if (!IsRegistered (cptr)) {
+ cptr->connectQ += strlen (buffer);
+ if (cptr->connectQ > 2000) {
+ sendto_ops
+ ("Connect-flooding from %s. Connection has been closed and IP banned.",
+ cptr->sockhost);
+ add_temp_conf (CONF_ZAP, cptr->sockhost, "Flooding", NULL, 0, 0,
+ KLINE_TEMP);
+ return exit_client (cptr, cptr, &me,
+ "Your host/ip has been banned for flooding");
+ }
+ }
+
+ if (IsDead (cptr))
+ return 0;
+
+ 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';
+ if (ch[1] == '\0' && IsToken (cptr))
+ mptr = msgmap[(u_char) * ch];
+ else
+ for (; mptr->cmd; mptr++)
+ if (mycmp (mptr->cmd, ch) == 0)
+ break;
+
+ 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));
+
+ /* now, lets make sure they use a legit commnd... -nikb */
+ /* There is code in s_serv.c for ADMIN and VERSION and
+ * in s_user.c for NOTICE to limit commands by
+ * unregistered users. -Studded */
+ if ((!IsRegistered (cptr)) &&
+ (((mptr->func != m_user) && (mptr->func != m_nick) &&
+ (mptr->func != m_server) && (mptr->func != m_pong) &&
+ (mptr->func != m_pass) && (mptr->func != m_quit) &&
+ (mptr->func != m_protoctl) && (mptr->func != m_error) &&
+ (mptr->func != m_admin) && (mptr->func != m_version)
+#ifdef NOSPOOF
+ && (mptr->func != m_notice)
+#endif
+ ))) {
+ sendto_one (from, ":%s %d %s :You have not registered",
+ me.name, ERR_NOTREGISTERED, ch);
+ return -1;
+ }
+ 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 = time (NULL);
+
+ /* 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; Compiler says this is unused */
+ /*
+ * 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));
+}
--- /dev/null
+/*
+ * 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>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include "nameser.h"
+#include "resolv.h"
+#include "inet.h" /* inet_addr() */
+
+#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));
+
+extern int errno, h_errno;
+extern int highest_fd;
+extern aClient *local[];
+
+static char hostbuf[HOSTLEN + 1];
+static char dot[] = ".";
+static int incache = 0;
+static CacheTable hashtable[ARES_CACSIZE];
+static aCache *cachetop = NULL;
+static ResRQ *last, *first;
+
+static void rem_cache 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 *));
+
+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 HAVE_LRAND48
+ srand48 (time (NULL));
+#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) {
+ 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));
+ }
+#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;
+{
+ ResRQ **rptr, *r2ptr = NULL;
+ int i;
+ char *s;
+
+ if (!old)
+ return;
+ 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;
+ 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);
+ if (r2ptr->name)
+ MyFree (r2ptr->name);
+ MyFree (r2ptr);
+
+ return;
+}
+
+/*
+ * Create a DNS request record for the server.
+ */
+static ResRQ *make_request (lp)
+ Link *lp;
+{
+ ResRQ *nreq;
+
+ nreq = (ResRQ *) MyMalloc (sizeof (ResRQ));
+ bzero ((char *) nreq, sizeof (ResRQ));
+ nreq->next = NULL; /* where NULL is non-zero ;) */
+ nreq->sentat = time (NULL);
+ 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. */
+ nreq->he.h_addrtype = AF_INET;
+ nreq->he.h_name = NULL;
+ nreq->he.h_aliases[0] = NULL;
+ (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;
+{
+ ResRQ *rptr, *r2ptr;
+ 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;
+ if (now >= tout) {
+ 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:
+ if (cptr->cc)
+ write (cptr->fd, REPORT_FAIL_DNS, R_fail_dns);
+ ClearDNS (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;
+ resend_query (rptr);
+ 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;
+{
+ ResRQ *rptr, *r2ptr;
+
+ for (rptr = first; rptr; rptr = r2ptr) {
+ r2ptr = rptr->next;
+ if (cp == rptr->cinfo.value.cp)
+ rem_request (rptr);
+ }
+}
+
+/*
+ * 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;
+{
+ 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;
+}
+
+/*
+ * find a dns request id (id is determined by dn_mkquery)
+ */
+static ResRQ *find_id (id)
+ int id;
+{
+ 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;
+{
+ aCache *cp;
+
+ reinfo.re_na_look++;
+ if ((cp = find_cache_name (name)))
+ return (struct hostent *) &(cp->he);
+ 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)))
+ return (struct hostent *) &(cp->he);
+ 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;
+ ResRQ *rptr;
+{
+ 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);
+ }
+ /*
+ * 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);
+ }
+ return (query_name (hname, C_IN, T_A, rptr));
+}
+
+/*
+ * Use this to do reverse IP# lookups.
+ */
+static int do_query_number (lp, numb, rptr)
+ Link *lp;
+ struct in_addr *numb;
+ ResRQ *rptr;
+{
+ char ipbuf[32];
+ 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]));
+ if (!rptr) {
+ rptr = make_request (lp);
+ rptr->type = T_PTR;
+ rptr->addr.s_addr = numb->s_addr;
+ bcopy ((char *) &numb->s_addr,
+ (char *) &rptr->he.h_addr, sizeof (struct in_addr));
+ rptr->he.h_length = sizeof (struct in_addr);
+ }
+ return (query_name (ipbuf, C_IN, T_PTR, rptr));
+}
+
+/*
+ * 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 HAVE_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 /* HAVE_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;
+{
+ char *cp, **alias;
+ 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 /* SOL20 */
+ 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);
+ cp += sizeof (rptr->ttl);
+ 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;
+}
+
+
+/*
+ * read a dns reply from the nameserver and process it.
+ */
+struct hostent *get_res (lp)
+ char *lp;
+{
+ static char buf[sizeof (HEADER) + MAXPACKET];
+ HEADER *hptr;
+ struct sockaddr_in sin;
+ int rc, a, len = sizeof (sin), max;
+ ResRQ *rptr = NULL;
+ aCache *cp = NULL;
+
+ 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
+ reinfo.re_replies++;
+ /*
+ * response for an id which we have already received an answer for
+ * just ignore this response.
+ */
+ rptr = find_id (hptr->id);
+ if (!rptr)
+ goto getres_err;
+ /*
+ * 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)));
+
+ if (!rptr->he.h_name) {
+ char badip[128];
+ sprintf (badip, "%s (a = %d)",
+ inetntoa ((char *) &rptr->he.h_addr), a);
+
+ sendto_realops ("WARNING: Error in lookup of %s.", badip);
+ sendto_serv_butone (&me, ":%s GLOBOPS :Error in lookup of %s.",
+ me.name, badip);
+
+ return (struct hostent *) NULL;
+ }
+ /*
+ * 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));
+ }
+ return (struct hostent *) NULL;
+}
+
+static int hash_number (ip)
+ unsigned char *ip;
+{
+ 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;
+{
+ 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)
+ aCache *ocp;
+{
+ aCache *cp = NULL;
+ 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 /* DEBUG */
+ ocp->list_next = cachetop;
+ cachetop = ocp;
+
+ hashv = hash_name (ocp->he.h_name);
+ ocp->hname_next = hashtable[hashv].name_list;
+ hashtable[hashv].name_list = ocp;
+
+ hashv = hash_number ((u_char *) ocp->he.h_addr);
+ 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.",
+ ocp->he.h_name, ocp->he.h_addr_list[0], ocp));
+ Debug ((DEBUG_INFO,
+ "add_to_cache:h1 %d h2 %x lnext %#x namnext %#x numnext %#x",
+ hash_name (ocp->he.h_name), hashv, ocp->list_next,
+ ocp->hname_next, ocp->hnum_next));
+#endif /* DEBUG */
+
+ /*
+ * 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;
+{
+ aCache **cpp, *cp = cachep;
+ char *s, *t, **base;
+ 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;
+ 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));
+ }
+ }
+ return;
+}
+
+static aCache *find_cache_name (name)
+ char *name;
+{
+ aCache *cp;
+ char *s;
+ 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)
+ for (i = 0, s = cp->he.h_name; s; s = cp->he.h_aliases[i++])
+ 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.
+ */
+ 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)) {
+ 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;
+{
+ aCache *cp;
+ 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)
+ for (i = 0; cp->he.h_addr_list[i]; i++)
+ if (!bcmp (cp->he.h_addr_list[i], numb, sizeof (struct in_addr))) {
+ 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...
+ */
+ if (!cp->he.h_addr_list[1])
+ continue;
+ /*
+ * if the first IP# has the same hashnumber as the IP# we
+ * are looking for, its been done already.
+ */
+ 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))) {
+ cainfo.ca_nu_hits++;
+ update_list (rptr, cp);
+ return cp;
+ }
+ }
+ return NULL;
+}
+
+static aCache *make_cache (rptr)
+ ResRQ *rptr;
+{
+ aCache *cp;
+ int i, n;
+ struct hostent *hp;
+ char *s, **t;
+
+ /*
+ ** shouldn't happen but it just might...
+ */
+ if (!rptr->he.h_name || !rptr->he.h_addr.s_addr)
+ return NULL;
+ /*
+ ** Make cache entry. First check to see if the cache already exists
+ ** and if so, return a pointer to it.
+ */
+ 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))))
+ 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));
+
+ 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;
+
+ if (rptr->ttl < 600) {
+ reinfo.re_shortttl++;
+ cp->ttl = 600;
+ }
+ else
+ cp->ttl = rptr->ttl;
+ cp->expireat = time (NULL) + cp->ttl;
+ rptr->he.h_name = NULL;
+
+#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;
+{
+ aCache **cp;
+ struct hostent *hp = &ocp->he;
+ int hashv;
+ 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;
+ }
+ /*
+ * 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);
+ }
+ 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;
+{
+ aCache *cp, *cp2;
+ 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 ()
+{
+ aCache *cp;
+
+ while ((cp = cachetop))
+ rem_cache (cp);
+}
+
+int m_dns (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aCache *cp;
+ int i;
+
+ if (MyOper (sptr) && (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 - time (NULL), cp->ttl,
+ 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]));
+ }
+ 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);
+ h = &c->he;
+ 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;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "common.h"
+#include "sys.h"
+#include "nameser.h"
+
+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;
+}
--- /dev/null
+
+/*-
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include "config.h" /* To get #define SOL20 Vesa */
+#include "sys.h"
+#include "common.h"
+#include "nameser.h"
+#include "resolv.h"
+
+/*
+ * 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
+ */
+int res_init ()
+{
+ register FILE *fp;
+ register char *cp, *dp, **pp;
+ extern u_long inet_addr ();
+ 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;
+ _res.nsaddr.sin_port = htons (NAMESERVER_PORT);
+ _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++;
+ }
+ 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;
+ _res.nsaddr_list[nserv].sin_port = htons (NAMESERVER_PORT);
+ 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);
+ }
+ 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);
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include "config.h"
+#include "sys.h"
+#include "nameser.h"
+#include "resolv.h"
+
+/*
+ * 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);
+}
--- /dev/null
+
+#include <sys/types.h>
+#include <stdio.h>
+#include "nameser.h"
+
+/*
+ * 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);
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "res.h"
+#include "numeric.h"
+#include "patchlevel.h"
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <utmp.h>
+#include <sys/resource.h>
+#if defined(SOL20)
+#include <sys/filio.h>
+#endif
+#if (!defined(SVR3) || defined(sgi) || defined(_SEQUENT_))
+#include <sys/un.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 IN_LOOPBACKNET
+#define IN_LOOPBACKNET 0x7f
+#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 *));
+static void do_dns_async PROTO (()), set_sock_opts PROTO ((int, aClient *));
+static char readbuf[READBUF_SIZE];
+char zlinebuf[BUFSIZE];
+extern char *version;
+
+/*
+ * 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;
+{
+ int errtmp = errno; /* debug may change 'errno' */
+ char *host;
+ int err, len = sizeof (err);
+
+ host = (cptr) ? get_client_name (cptr, FALSE) : "";
+
+ 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) {
+ report_error ("opening stream socket %s:%s", cptr);
+ return -1;
+ }
+ else if (cptr->fd >= MAXCLIENTS) {
+ sendto_ops ("No more connections allowed (%s)", cptr->name);
+ (void) close (cptr->fd);
+ 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);
+ server.sin_port = htons (port);
+ /*
+ * 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);
+ (void) close (cptr->fd);
+ return -1;
+ }
+ }
+ if (getsockname (cptr->fd, (struct sockaddr *) &server, &len)) {
+ report_error ("getsockname failed for %s:%s", cptr);
+ (void) close (cptr->fd);
+ return -1;
+ }
+ if (cptr == &me) { /* KLUDGE to get it work... */
+ char buf[1024];
+
+ (void) sprintf (buf, rpl_str (RPL_MYPORTIS), me.name, "*",
+ ntohs (server.sin_port));
+ (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;
+ cptr->port = (int) ntohs (server.sin_port);
+ (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 ()
+{
+ aClient *cptr;
+ int i;
+ 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 ()
+{
+ int fd;
+#ifdef RLIMIT_FD_MAX
+ struct rlimit limit;
+
+ if (!getrlimit (RLIMIT_FD_MAX, &limit)) {
+#ifdef pyr
+ if (limit.rlim_cur < MAXCONNECTIONS)
+#else
+ if (limit.rlim_max < MAXCONNECTIONS)
+#endif
+ {
+ (void) fprintf (stderr, "ircd fd table too big\n");
+ (void) fprintf (stderr, "Hard Limit: %d IRC max: %d\n",
+ (int) 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",
+ (int) limit.rlim_cur);
+ exit (-1);
+ }
+#endif
+ }
+#endif
+#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(SCOUNIX)
+ (void) setlinebuf (stderr);
+#endif
+#endif
+#endif
+ 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))) {
+ if (fork ())
+ exit (0);
+#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) \
+ || defined(SCOUNIX)
+ (void) setsid ();
+#else
+ (void) setpgrp (0, (int) getpid ());
+#endif
+ (void) close (0); /* fd 0 opened by inetd */
+ local[0] = NULL;
+ }
+ init_dgram:
+ 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)
+ aClient *cptr;
+ char *sockn;
+{
+ struct sockaddr_in sk;
+ int len = sizeof (struct sockaddr_in);
+
+
+ /* If descriptor is a tty, special checking... */
+ if (isatty (cptr->fd)) {
+ 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));
+ cptr->port = (int) ntohs (sk.sin_port);
+
+ 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)
+ aClient *cptr;
+{
+ static char sockname[HOSTLEN + 1];
+ struct hostent *hp = NULL;
+ 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 | CONF_NZCONNECT_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;
+{
+ char *name;
+ 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) {
+ aConfItem *aconf;
+
+ aconf = count_cnlines (lp);
+ if (aconf) {
+ 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;
+ aConfItem *n_conf, *c_conf;
+ struct hostent *hp;
+ int estab;
+{
+ 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_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;
+ }
+
+ sendto_one (cptr, "PROTOCTL %s", PROTOCTL_SUPPORTED);
+
+ 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, "SERVER %s 1 %s_cap%i :%s",
+ my_name_for_link (me.name, aconf), version, VERSION_SEND,
+ me.info);
+
+ 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;
+{
+ aConfItem *aconf;
+ 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 += time (NULL) - 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 += time (NULL) - 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 = time (NULL);
+ aconf->hold += (aconf->hold - cptr->since > HANGONGOODLINK) ?
+ HANGONRETRYDELAY : ConfConFreq (aconf);
+ if (nextconnect > aconf->hold)
+ nextconnect = aconf->hold;
+ }
+
+ if (cptr->fd >= 0) {
+ flush_connections (cptr->fd);
+ local[cptr->fd] = NULL;
+#ifdef ZIP_LINKS
+ if (IsServer (cptr) || IsListening (cptr))
+ zip_free (cptr);
+#endif
+ (void) close (cptr->fd);
+ 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;
+ (void) close (j);
+ 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)
+ 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
+ if (IsServer (cptr))
+#ifdef ZIP_LINKS
+ opt = READBUF_SIZE;
+#else
+ opt = 8192;
+#endif
+ else
+ opt = 4096;
+ 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)
+ {
+ 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, "%2.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;
+{
+ int errtmp = errno, err = 0, len = sizeof (err);
+#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 ((res = fcntl (fd, F_GETFL, 0)) == -1)
+ report_error ("fcntl(fd, F_GETFL) failed for %s:%s", cptr);
+ else if (fcntl (fd, F_SETFL, res | nonb) == -1)
+ report_error ("fcntl(fd, F_SETL, nonb) failed for %s:%s", cptr);
+#endif
+ return;
+}
+
+/*
+ * 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;
+ aConfItem *aconf2 = NULL;
+ 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.
+ */
+ if (isatty (fd)) /* If descriptor is a tty, special checking... */
+ get_sockhost (acptr, cptr->sockhost);
+ else {
+ 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);
+ (void) close (fd);
+ return NULL;
+ }
+ /* don't want to add "Failed in connecting to" here.. */
+ if (aconf && IsIllegal (aconf))
+ goto add_con_refuse;
+ /* Copy ascii address to 'sockhost' just in case. Then we
+ * have something valid to put into error messages...
+ */
+ get_sockhost (acptr, (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;
+ }
+ acptr->port = ntohs (addr.sin_port);
+
+ /* Let's do a check here to see if somebody matches a CN pair.
+ * if they don't, we can send them the connection noticed, because
+ * they have to be a client and we can't send them anything compressed. -GZ
+ */
+
+ for (aconf2 = conf; aconf2; aconf2 = aconf2->next)
+ if (aconf2->status == CONF_CONNECT_SERVER &&
+ (match (inetntoa ((char *) &addr.sin_addr), aconf2->host) == 0
+ || match (inetntoa ((char *) &addr.sin_addr),
+ index (aconf2->host, '@') + 1) == 0))
+ break;
+
+ if (!aconf2) {
+ for (aconf2 = conf; aconf2; aconf2 = aconf2->next)
+ if (aconf2->status == CONF_NOCONNECT_SERVER &&
+ (match (inetntoa ((char *) &addr.sin_addr), aconf2->host)
+ == 0
+ || match (inetntoa ((char *) &addr.sin_addr),
+ index (aconf2->host, '@') + 1) == 0))
+ break;
+ }
+
+ if (!aconf2)
+ acptr->cc = 1;
+
+ if (acptr->cc)
+ write (fd, REPORT_DO_DNS, R_do_dns);
+
+ 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);
+ else if (acptr->cc)
+ write (fd, REPORT_FIN_DNSC, R_fin_dnsc);
+ 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);
+
+ 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)
+ aClient *cptr;
+ fd_set *rfd;
+{
+ int dolen = 0, length = 0, done;
+ time_t now = time (NULL);
+
+ if (FD_ISSET (cptr->fd, rfd) &&
+ !(IsPerson (cptr) && DBufLength (&cptr->recvQ) > 6090)) {
+ errno = 0;
+ 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 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
+ 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->host : "*",
+ 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.
+ */
+int read_message (delay)
+ 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
+ */
+{
+ aClient *cptr;
+ int nfds;
+ struct timeval wait;
+#ifdef pyr
+ struct timeval nowt;
+ u_long us;
+#endif
+ fd_set read_set, write_set;
+ time_t delay2 = delay, now;
+ u_long usec = 0;
+ int res, length, fd, i;
+ int ping = 0;
+ int sockerr;
+
+#ifdef pyr
+ (void) gettimeofday (&nowt, NULL);
+ now = nowt.tv_sec;
+#else
+ now = time (NULL);
+#endif
+
+ for (res = 0;;) {
+
+ FD_ZERO (&read_set);
+ FD_ZERO (&write_set);
+
+ for (i = highest_fd; i >= 0; i--) {
+ if (!(cptr = local[i]))
+ continue;
+ if (IsLog (cptr))
+ continue;
+ if (IsPing (cptr)) {
+ ping++;
+ Debug ((DEBUG_NOTICE, "open ping on %x %d", cptr, i));
+ FD_SET (i, &read_set);
+ if (DoPing (cptr)) {
+ delay2 = 1;
+ if (now > cptr->lasttime)
+ FD_SET (i, &write_set);
+ }
+ else if (cptr->firsttime && now > cptr->firsttime) {
+ FD_CLR (i, &read_set);
+ del_queries ((char *) cptr);
+ end_ping (cptr);
+ }
+ continue;
+ }
+ if (DoingDNS (cptr))
+ 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) ||
+#ifdef ZIP_LINKS
+ ((cptr->flags2 & FLAGS2_ZIP) && (cptr->zip->outcount > 0)) ||
+#endif
+ (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
+ }
+ if (udpfd >= 0)
+ FD_SET (udpfd, &read_set);
+ if (resfd >= 0)
+ FD_SET (resfd, &read_set);
+
+ 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
+ nfds = select (FD_SETSIZE, &read_set, &write_set, 0, &wait);
+#endif
+ if (nfds == -1 && errno == EINTR)
+ return -1;
+ else if (nfds >= 0)
+ break;
+ report_error ("select %s:%s", &me);
+ res++;
+ if (res > 5)
+ restart ("too many select errors");
+ sleep (10);
+ }
+
+ if (udpfd >= 0 && FD_ISSET (udpfd, &read_set)) {
+ polludp ();
+ nfds--;
+ FD_CLR (udpfd, &read_set);
+ }
+ if (resfd >= 0 && FD_ISSET (resfd, &read_set)) {
+ do_dns_async ();
+ nfds--;
+ FD_CLR (resfd, &read_set);
+ }
+ /*
+ * Check fd sets for the ping fd's (if set and valid!) first
+ * because these can not be processed using the normal loops below.
+ * And we want them to be as fast as possible.
+ * -Run
+ */
+ for (i = highest_fd; (ping > 0) && (i >= 0); i--) {
+ if (!(cptr = local[i]))
+ continue;
+ if (!IsPing (cptr))
+ continue;
+ ping--;
+ if ((nfds > 0) && FD_ISSET (cptr->fd, &read_set)) {
+ nfds--;
+ FD_CLR (cptr->fd, &read_set);
+ read_ping (cptr); /* This can MyFree(cptr) ! */
+ }
+ else if ((nfds > 0) && FD_ISSET (cptr->fd, &write_set)) {
+ nfds--;
+ cptr->lasttime = now;
+ FD_CLR (cptr->fd, &write_set);
+ send_ping (cptr); /* This can MyFree(cptr) ! */
+ }
+ }
+
+ if (resfd >= 0 && FD_ISSET (resfd, &read_set)) {
+ do_dns_async ();
+ nfds--;
+ FD_CLR (resfd, &read_set);
+ }
+
+ 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 = time (NULL);
+ /*
+ ** 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);
+ (void) close (fd);
+ break;
+ }
+ /*
+ * Use of add_connection (which never fails :) meLazy
+ */
+ (void) add_connection (cptr, fd);
+ nextping = time (NULL);
+ 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
+ */
+ Debug ((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", i, errno, length));
+
+ /*
+ ** 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"));
+ }
+
+ Debug ((DEBUG_DEBUG, "Going out of read_message"));
+ return 0;
+}
+
+/*
+ * connect_server
+ */
+int connect_server (aconf, by, hp)
+ aConfItem *aconf;
+ aClient *by;
+ struct hostent *hp;
+{
+ struct sockaddr *svp;
+ aClient *cptr, *c2ptr;
+ 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)
+ (void) close (cptr->fd);
+ cptr->fd = -2;
+ free_client (cptr);
+ return -1;
+ }
+ set_non_blocking (cptr->fd, cptr);
+ set_sock_opts (cptr->fd, cptr);
+ (void) signal (SIGALRM, dummy);
+ if (connect (cptr->fd, svp, len) < 0 && errno != EINPROGRESS) {
+ errtmp = errno; /* other system calls may eat errno */
+ 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);
+ (void) close (cptr->fd);
+ cptr->fd = -2;
+ free_client (cptr);
+ errno = errtmp;
+ if (errno == EINTR)
+ errno = ETIMEDOUT;
+ 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);
+ (void) close (cptr->fd);
+ 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 = time (NULL);
+
+ return 0;
+}
+
+static struct sockaddr *connect_inet (aconf, cptr, lenp)
+ aConfItem *aconf;
+ aClient *cptr;
+ int *lenp;
+{
+ static struct sockaddr_in server;
+ 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));
+ server.sin_port = htons (((aconf->port > 0) ? aconf->port : portnum));
+ *lenp = sizeof (server);
+ return (struct sockaddr *) &server;
+}
+
+
+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));
+}
+
+/*
+ ** 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;
+ from.sin_port = htons (7007);
+ from.sin_family = AF_INET;
+
+ if ((udpfd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
+ Debug ((DEBUG_ERROR, "socket udp : %s", strerror (errno)));
+ return -1;
+ }
+ if (setsockopt (udpfd, SOL_SOCKET, SO_REUSEADDR,
+ (OPT_TYPE *) & on, sizeof (on)) == -1) {
+#ifdef USE_SYSLOG
+ syslog (LOG_ERR, "setsockopt udp fd %d : %m", udpfd);
+#endif
+ Debug ((DEBUG_ERROR, "setsockopt so_reuseaddr : %s",
+ strerror (errno)));
+ (void) close (udpfd);
+ 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
+ Debug ((DEBUG_ERROR, "bind : %s", strerror (errno)));
+ (void) close (udpfd);
+ udpfd = -1;
+ return -1;
+ }
+ if (fcntl (udpfd, F_SETFL, FNDELAY) == -1) {
+ Debug ((DEBUG_ERROR, "fcntl fndelay : %s", strerror (errno)));
+ (void) close (udpfd);
+ udpfd = -1;
+ return -1;
+ }
+ return udpfd;
+}
+
+/*
+ * max # of pings set to 15/sec.
+ */
+static void polludp ()
+{
+ 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 = time (NULL);
+ if (now == last)
+ if (++cnt > 14)
+ return;
+ cnt = 0;
+ last = now;
+
+ if (n == -1) {
+ if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
+ return;
+ else {
+ report_error ("udp port recvfrom (%s): %s", &me);
+ return;
+ }
+ }
+ ircstp->is_udp++;
+ if (n < 19)
+ return;
+
+ 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.
+ */
+static void do_dns_async ()
+{
+ static Link ln;
+ aClient *cptr;
+ aConfItem *aconf;
+ struct hostent *hp;
+
+ ln.flags = -1;
+ hp = get_res ((char *) &ln);
+ 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);
+ if (cptr->cc)
+ write (cptr->fd, REPORT_FIN_DNS, R_fin_dns);
+ ClearDNS (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;
+ case ASYNC_PING:
+ cptr = ln.value.cptr;
+ del_queries ((char *) cptr);
+ if (hp) {
+ memcpy (&cptr->ip, hp->h_addr, sizeof (struct in_addr));
+ if (ping_server (cptr, hp) != -1)
+ break;
+ }
+ else {
+ sendto_ops ("Udp ping to %s failed: host lookup",
+ cptr->sockhost);
+ }
+
+ end_ping (cptr);
+ break;
+ default:
+ break;
+ }
+
+ ln.flags = -1;
+ hp = get_res ((char *) &ln);
+ } /* while (hp != NULL) */
+}
--- /dev/null
+
+/************************************************************************
+ * 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
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "channel.h"
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+/* If you have problems with this on your system please mail star-coding@starchat.net
+ #if defined(__hpux) || defined(__FreeBSD__)
+ */
+#include "inet.h"
+/* #endif */
+#if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
+#include <time.h>
+#endif
+
+#include "h.h"
+#define debug 1
+static int lookup_confhost PROTO ((aConfItem *));
+static int advanced_check (char *, int);
+int ZLineExists (char *);
+
+
+aSqlineItem *sqline = NULL;
+aJinxItem *jinx = NULL;
+aConfItem *conf = NULL;
+
+extern char zlinebuf[];
+int socks_zline_time = ZLINE_TIME;
+
+static int del_temp_conf (unsigned int, char *, char *, char *, int, int,
+ unsigned int);
+
+void free_sqline (aSqlineItem *); /* From list.c */
+void free_jinx (aJinxItem *);
+void delist_conf (aConfItem *); /* This one too */
+aJinxItem *make_jinx ();
+/*
+ * 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;
+{
+ 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 */
+{
+ 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);
+}
+
+void RemoveZLine (char *zline)
+{
+ sendto_realops ("Removing temporary z:line (%s)", zline);
+ del_temp_conf (CONF_ZAP, zline, NULL, NULL, 0, 0, 0);
+}
+
+/*
+ * 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;
+{
+ aConfItem *aconf;
+ 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;
+ struct hostent *hp;
+ char *sockhost;
+{
+ aConfItem *aconf;
+ char *hname;
+ 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:
+ get_sockhost (cptr, uhost);
+ 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)
+ Link *lp;
+{
+ 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;
+{
+ 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;
+{
+ 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;
+{
+ 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_admin ()
+{
+ 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 ()
+{
+ 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 ()
+{
+ 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 ()
+{
+ 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;
+{
+ 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 && !mycmp (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;
+{
+ 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;
+{
+ 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;
+ /*
+ ** 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;
+{
+ 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;
+{
+ 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;
+{
+ 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 && !mycmp (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)
+ Link *lp;
+ char *host;
+ int statmask;
+{
+ 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_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;
+{
+ aConfItem *tmp;
+ 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;
+{
+ 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, 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;
+}
+
+/*
+ * ZLineExists
+ * return 1 is zline exists, 0 if it doesn't
+ * -david kopstain
+ */
+
+int ZLineExists (char *name)
+{
+ aConfItem *aconf;
+ for (aconf = conf; aconf; aconf = aconf->next) {
+ if ((aconf->status & CONF_ZAP) && !(aconf->status & CONF_ILLEGAL) &&
+ !BadPtr (aconf->host) && !strcasecmp (aconf->host, name))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * 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;
+{
+ 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;
+{
+ 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;
+{
+ 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] = +/-
+ **
+ ** revamped this code because the original code was kinda wacky. -GZ
+ */
+int m_svsnoop (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+
+ if (!IsULine (cptr, sptr) || parc < 2)
+ return 0;
+
+ sendto_serv_butone (sptr, ":%s SVSNOOP %s %s", parv[0], parv[1], parv[2]);
+
+ if (match (me.name, parv[1])) {
+ return 0;
+ }
+ if (parv[2][0] == '+') {
+ sendto_ops ("This server is now placed in SVSNOOP mode.");
+
+ /* This stuff is broken anyway - let's just try a different and very simple approach.
+ * if SVSNOOP == 1, you cant use m_oper...should do the trick I think.
+ * see m_oper for the rest of the revamp. -GZ
+ *
+ *
+ * for (aconf = conf; aconf; aconf = aconf->next) {
+ * if (aconf->status & CONF_OPERATOR || aconf->status & CONF_LOCOP)
+ * aconf->status = CONF_ILLEGAL;
+ * }
+ */
+ SVSNOOP = 1;
+ }
+ else {
+ SVSNOOP = 0;
+ sendto_ops ("This server is no longer placed in SVSNOOP mode.");
+ }
+ return 0;
+}
+
+/*
+ * 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;
+{
+ aConfItem **tmp = &conf, *tmp2;
+ aClass *cltmp;
+ aClient *acptr;
+ int i;
+ int ret = 0;
+ aEvent *eptr, *eptr2;
+
+ if (sig == 1 && SVSNOOP == 0) {
+ 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;
+ }
+
+ /*
+ * 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);
+ 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 (time (NULL), 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;
+ }
+ /* Remove temporary z-lines */
+ for (eptr = EventList; eptr; eptr = eptr2) {
+ eptr2 = eptr->next;
+ if (eptr->func && eptr->func == RemoveZLine) {
+ if (eptr->prev)
+ eptr->prev->next = eptr->next;
+ else
+ EventList = eptr->next;
+ if (eptr->next)
+ eptr->next->prev = eptr->prev;
+ free_event (eptr);
+ }
+ }
+ 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 ();
+
+static int oper_access[] = {
+ ~(OFLAG_ADMIN | OFLAG_SADMIN | OFLAG_ZLINE), '*',
+ OFLAG_LOCAL, 'o',
+ OFLAG_GLOBAL, 'O',
+ OFLAG_REHASH, 'r',
+ OFLAG_DIE, 'D',
+ OFLAG_RESTART, 'R',
+ OFLAG_GLOBOP, 'g',
+ OFLAG_LOCOP, 'l',
+ OFLAG_LROUTE, 'c',
+ OFLAG_GROUTE, 'C',
+ OFLAG_LKILL, 'k',
+ OFLAG_GKILL, 'K',
+ OFLAG_KLINE, 'b',
+ OFLAG_UNKLINE, 'B',
+ OFLAG_LNOTICE, 'n',
+ OFLAG_GNOTICE, 'N',
+ OFLAG_ADMIN, 'A',
+ OFLAG_SADMIN, 'a',
+ OFLAG_UMODEC, 'u',
+ OFLAG_UMODEF, 'f',
+ OFLAG_ZLINE, 'z',
+ 0, 0
+};
+
+/*
+ ** 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}
+ };
+ 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 (line[i-2] == '\r') { /* Strip DOS type end of lines */
+ line[i-2] = '\n';
+ line[i-1] = '\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;
+ case 'e':
+ case 'E': /* Blocking of DCC transfers -GZ */
+ aconf->status = CONF_DCCBLOCK;
+ break;
+ case 'f':
+ case 'F':
+ aconf->status = CONF_ZTIME;
+ 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 irc.conf */
+ case 'k':
+ aconf->status = CONF_KILL;
+ 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 '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 if Z:line time -taz */
+ if (aconf->status & CONF_ZTIME) {
+ if ((aconf->host) && isdigit (*aconf->host))
+ socks_zline_time = (atoi (aconf->host) * 60);
+ 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:;
+ }
+ /*
+ ** 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 || index (aconf->host, '*') ||
+ index (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);
+ }
+ /*
+ ** 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_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 = time (NULL);
+ 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)
+ aConfItem *aconf;
+{
+ char *s;
+ 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 *host, *name;
+ char ipaddy[HOSTLEN + 1];
+ aConfItem *tmp, *tmpexempt = NULL;
+
+ if (!cptr->user)
+ return 0;
+
+ host = cptr->sockhost;
+ name = cptr->user->username;
+ strncpy (ipaddy, inetntoa ((char *) &(cptr->ip)), HOSTLEN);
+
+ if (strlen (host) > (size_t) HOSTLEN ||
+ (name ? strlen (name) : 0) > (size_t) HOSTLEN)
+ return (0);
+
+ for (tmp = conf; tmp; tmp = tmp->next) {
+ if (tmp->status != CONF_KILL)
+ continue;
+ if (!tmp->host || !tmp->name)
+ continue;
+ if (((match (tmp->host, host) == 0) || /* hostname */
+ (match (tmp->host, ipaddy) == 0)) && /* ip addy */
+ (!name || match (tmp->name, name) == 0) && /* username */
+ (!tmp->port || (tmp->port == cptr->acpt->port))) { /* port (still used?) */
+ break; /* KLINE ! */
+ }
+ }
+ if (tmp) {
+ /* A KLINE was found. Lets see if an exemption for this address exists */
+ for (tmpexempt = conf; tmpexempt; tmpexempt = tmpexempt->next) {
+ if (tmpexempt->status != CONF_KILLEXEMPT)
+ continue;
+ if (!tmpexempt->host || !tmpexempt->name)
+ continue;
+ if (((match (tmpexempt->host, host) == 0) || /* hostname */
+ (match (tmpexempt->host, ipaddy) == 0)) && /* ip addy */
+ (!name || match (tmpexempt->name, name) == 0) && /* username */
+ (!tmpexempt->port || (tmpexempt->port == cptr->acpt->port))) { /* port (still used?) */
+ break; /* KLINE exemption ! */
+ }
+ }
+ if (tmp && !tmpexempt) {
+ if (BadPtr (tmp->passwd))
+ sendto_one (cptr,
+ ":%s %d %s :*** You are not welcome on this server."
+ " Email " KLINE_ADDRESS " for more information.",
+ me.name, ERR_YOUREBANNEDCREEP, cptr->name);
+ else
+#ifdef COMMENT_IS_FILE
+ m_killcomment (cptr, cptr->name, tmp->passwd);
+ }
+#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 " KLINE_ADDRESS
+ " for more information.", me.name,
+ ERR_YOUREBANNEDCREEP, cptr->name, tmp->passwd);
+ }
+ }
+#endif /* COMMENT_IS_FILE */
+ }
+ return ((tmp && !tmpexempt) ? -1 : 0);
+}
+
+char *find_zap (aClient * cptr, int dokillmsg)
+{
+ aConfItem *tmp;
+ char *retval = NULL;
+ char ipaddy[HOSTLEN + 1];
+
+ strncpy (ipaddy, inetntoa ((char *) &cptr->ip), HOSTLEN);
+
+ for (tmp = conf; tmp; tmp = tmp->next)
+ if ((tmp->status == CONF_ZAP) && tmp->host
+ && !match (tmp->host, ipaddy)) {
+ 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.",
+ me.name, ERR_YOUREBANNEDCREEP, cptr->name, retval);
+ if (!dokillmsg && retval) {
+ sprintf (zlinebuf,
+ "ERROR :Closing Link: [%s] (You are not welcome on "
+ "this server: %s.\r\n", inetntoa ((char *) &cptr->ip),
+ retval);
+ retval = zlinebuf;
+ }
+ return retval;
+}
+
+int find_kill_exempt (host, name)
+ char *host, *name;
+{
+ aConfItem *tmp;
+
+ for (tmp = conf; tmp; tmp = tmp->next) {
+ if ((tmp->status == CONF_KILLEXEMPT) && tmp->host && tmp->name &&
+ (match (tmp->host, host) == 0) &&
+ (!name || match (tmp->name, name) == 0))
+ return 1; /* KLINE exempt found! */
+ }
+
+ return 0;
+}
+
+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;
+}
+
+/* Find DCC block */
+int find_dccblock (char *file)
+{
+ aConfItem *tmp;
+
+ for (tmp = conf; tmp; tmp = tmp->next) {
+ if ((tmp->status == CONF_DCCBLOCK) && tmp->host
+ && !match (tmp->host, file))
+ 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];
+ 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;
+}
+
+/*
+ ** 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[];
+{
+ if (check_registered (sptr))
+ return 0;
+
+ if (parc < 3) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "RAKILL");
+ return 0;
+ }
+ if (IsServer (cptr) &&
+ find_conf_host (cptr->confs, sptr->name, CONF_UWORLD)) {
+ if (find_kill_byname (parv[1], parv[2])) {
+#ifndef COMMENT_IS_FILE
+ del_temp_conf (CONF_KILL, parv[1], parv[3], parv[2], 0, 0, 1);
+#else
+ del_temp_conf (CONF_KILL, parv[1], NULL, parv[2], 0, 0, 1);
+#endif
+ }
+ if (parv[3])
+ sendto_serv_butone (cptr, ":%s RAKILL %s %s :%s",
+ parv[0], parv[1], parv[2], parv[3]);
+ else
+ sendto_serv_butone (cptr, ":%s RAKILL %s %s",
+ parv[0], parv[1], parv[2]);
+ check_pings (time (NULL), 1);
+ }
+ return 0;
+}
+
+/* ** 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[];
+{
+ if (check_registered (sptr))
+ return 0;
+
+ if (parc < 3) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "AKILL");
+ return 0;
+ }
+ if (IsServer (cptr) &&
+ find_conf_host (cptr->confs, sptr->name, CONF_UWORLD)) {
+ if (!find_kill_byname (parv[1], parv[2])) {
+
+#ifndef COMMENT_IS_FILE
+ add_temp_conf (CONF_KILL, parv[1], parv[3], parv[2], 0, 0, 2);
+#else
+ add_temp_conf (CONF_KILL, parv[1], NULL, parv[2], 0, 0, 2);
+#endif
+ }
+ if (parv[3])
+ sendto_serv_butone (cptr, ":%s AKILL %s %s :%s", parv[0],
+ parv[1], parv[2], parv[3]);
+ else
+ sendto_serv_butone (cptr, ":%s AKILL %s %s", parv[0], parv[1],
+ parv[2]);
+ check_pings (time (NULL), 1);
+ }
+ return 0;
+}
+
+/*
+ ** m_rakillex;
+ ** parv[0] = sender prefix
+ ** parv[1] = hostmask
+ ** parv[2] = username
+ ** parv[3] = comment
+ */
+int m_rakillex (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ if (check_registered (sptr))
+ return 0;
+
+ if (parc < 3) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "RAKILLEX");
+ return 0;
+ }
+ if (IsServer (cptr) &&
+ find_conf_host (cptr->confs, sptr->name, CONF_UWORLD)) {
+ if (find_kill_exempt (parv[1], parv[2])) {
+#ifndef COMMENT_IS_FILE
+ del_temp_conf (CONF_KILLEXEMPT, parv[1], parv[3], parv[2], 0, 0, 1);
+#else
+ del_temp_conf (CONF_KILLEXEMPT, parv[1], NULL, parv[2], 0, 0, 1);
+#endif
+ }
+ if (parv[3])
+ sendto_serv_butone (cptr, ":%s RAKILLEX %s %s :%s",
+ parv[0], parv[1], parv[2], parv[3]);
+ else
+ sendto_serv_butone (cptr, ":%s RAKILLEX %s %s",
+ parv[0], parv[1], parv[2]);
+ check_pings (time (NULL), 1);
+ }
+ return 0;
+}
+
+/* ** m_akillex;
+ ** parv[0] = sender prefix
+ ** parv[1] = hostmask
+ ** parv[2] = username
+ ** parv[3] = comment
+ */
+int m_akillex (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ if (check_registered (sptr))
+ return 0;
+
+ if (parc < 3) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "AKILLEX");
+ return 0;
+ }
+ if (IsServer (cptr) &&
+ find_conf_host (cptr->confs, sptr->name, CONF_UWORLD)) {
+ if (!find_kill_exempt (parv[1], parv[2])) {
+
+#ifndef COMMENT_IS_FILE
+ add_temp_conf (CONF_KILLEXEMPT, parv[1], parv[3], parv[2], 0, 0, 2);
+#else
+ add_temp_conf (CONF_KILLEXEMPT, parv[1], NULL, parv[2], 0, 0, 2);
+#endif
+ }
+ if (parv[3])
+ sendto_serv_butone (cptr, ":%s AKILLEX %s %s :%s", parv[0],
+ parv[1], parv[2], parv[3]);
+ else
+ sendto_serv_butone (cptr, ":%s AKILLEX %s %s", parv[0], parv[1],
+ parv[2]);
+ check_pings (time (NULL), 1);
+ }
+ return 0;
+}
+
+
+/* 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[];
+{
+ 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);
+ return 0;
+}
+
+/* m_unsqline
+ ** parv[0] = sender
+ ** parv[1] = nickmask
+ */
+int m_unsqline (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ 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 -1;
+
+ asqline->status = CONF_ILLEGAL;
+ return 0;
+}
+
+/*
+ * m_jinx
+ * parv[0] = sender;
+ * parv[1] = usermask;
+ * parv[2] = reason;
+ *
+ * Aug 1999 - Totally rewritten by Zaf
+ */
+int m_jinx (aClient * cptr, aClient * sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (!IsServer (sptr))
+ return 0;
+
+ if (parc < 2)
+ return 0;
+
+ if (parv[2]) {
+ sendto_serv_butone (cptr, ":%s JINX %s :%s", parv[0], parv[1],
+ parv[2]);
+ }
+ else {
+ sendto_serv_butone (cptr, ":%s JINX %s", parv[0], parv[1]);
+ }
+
+ /* Set jinx */
+ if (!(acptr = find_person (parv[1], NULL))) {
+ if (MyConnect (sptr))
+ sendto_one (sptr, err_str (ERR_NOSUCHNICK),
+ me.name, parv[0], parv[1]);
+ return 0;
+ }
+ SetJinx (acptr);
+ return 0;
+}
+
+/*
+ * m_unjinx
+ * parv[0] = sender;
+ * parv[1] = usermask;
+ *
+ * Aug 1999 - Totally rewritten by Zaf
+ */
+int m_unjinx (aClient * cptr, aClient * sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (!IsULine (cptr, sptr))
+ return 0;
+
+ if (parc < 2)
+ return 0;
+
+ sendto_serv_butone (cptr, ":%s UNJINX %s", parv[0], parv[1]);
+
+ /* Remove jinx */
+ if (!(acptr = find_person (parv[1], NULL))) {
+ if (MyConnect (sptr))
+ sendto_one (sptr, err_str (ERR_NOSUCHNICK),
+ me.name, parv[0], parv[1]);
+ return 0;
+ }
+ ClearJinx (acptr);
+ return 0;
+}
+
+
+/*
+ ** 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;
+
+ 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;
+ }
+ if (strlen (parv[1]) > 80) {
+ sendto_one (sptr, "NOTICE %s :This KLINE is too long", parv[0]);
+ return 0;
+ }
+ if (parc > 3) {
+ sendto_one (sptr,
+ "NOTICE %s :Try \"/quote kline <user@host> :<reason>\" (note the ':')",
+ parv[0]);
+ return 0;
+ }
+/* This patch allows opers to quote kline by address as well as nick
+ * --Russell
+ */
+ if ((hosttemp = (char *) strchr (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, "*") || !(char *) strchr (uhost, '.')) {
+ sendto_one (sptr, "NOTICE %s :You cannot add a KLINE that broad",
+ 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->host;
+
+ /* 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] : "");
+ add_temp_conf (CONF_KILL, uhost, parv[2], name, 0, 0, 1);
+ check_pings (time (NULL), 1);
+ return 0;
+}
+
+/*
+ * 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];
+
+ 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 (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, 0, 0, 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);
+ 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 (time (NULL), 1);
+ return 0;
+}
+
+/*
+ * 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 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) || !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;
+ }
+ /* z-lines don't support user@host format, they only
+ work with ip addresses and nicks */
+ 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 -1;
+ }
+ 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 if ((acptr = find_client (parv[1], NULL))) {
+ if (!MyConnect (acptr)) {
+ sendto_one (sptr,
+ ":%s NOTICE %s :I don't know the IP address of that user...",
+ me.name, sptr->name);
+ return -1;
+ }
+ strcpy (userhost, inetntoa ((char *) &acptr->ip));
+ person = &acptr->name[0];
+ acptr = NULL;
+ }
+ 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 -1;
+ }
+ 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 -1;
+ }
+ if (ZLineExists (userhost)) {
+ if (MyClient (sptr))
+ sendto_one (sptr,
+ ":%s NOTICE %s :*@%s already exists in my zline list.",
+ me.name, sptr->name, userhost);
+ return -1;
+ }
+ 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 : irc_network,
+ reason ? reason : "");
+ else
+ sendto_ops ("%s z:lined *@%s on %s [%s]", parv[0], userhost,
+ server ? server : irc_network, 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 -1;
+ }
+ for (i = highest_fd; i > 0; i--) {
+ if (!(acptr = local[i]) || IsLog (acptr) || IsMe (acptr));
+ continue;
+ if (find_zap (acptr, 1)) {
+ if (!IsServer (acptr)) {
+ sendto_one (sptr, ":%s NOTICE %s :*** %s %s",
+ me.name, sptr->name,
+ IsPerson (acptr) ? "exiting" : "closing",
+ 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 (time (NULL), 1);
+ return 0;
+}
+
+
+/*
+ * 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;
+/* Compiler says these are unused
+ aConfItem *aconf, *tmp;
+ aConfItem dummy;
+ */
+ char *mask, *server = NULL;
+
+ 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) || !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 -1;
+ }
+ 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 -1;
+ }
+ 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);
+ }
+ return 0;
+}
+
+
+/* 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
+ */
+
+int advanced_check (char *userhost, int ipstat)
+{
+ register int retval = TRUE;
+ char *up = NULL, *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
+
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include "struct.h"
+/*
+ * Option string. Must be before #ifdef DEBUGMODE.
+ */
+char serveropts[] = {
+#ifdef CHROOTDIR
+ 'c',
+#endif
+#ifdef CMDLINE_CONFIG
+ 'C',
+#endif
+#ifdef DEBUGMODE
+ 'D',
+#endif
+#ifdef HUB
+ 'H',
+#endif
+#ifdef SHOW_INVISIBLE_LUSERS
+ 'i',
+#endif
+#ifndef NO_DEFAULT_INVISIBLE
+ 'I',
+#endif
+#ifdef M4_PREPROC
+ 'm',
+#endif
+#ifdef IDLE_FROM_MSG
+ 'M',
+#endif
+#ifdef CRYPT_OPER_PASSWORD
+ 'p',
+#endif
+#ifdef NOSPOOF
+ 'n',
+#endif
+#ifdef VALLOC
+ 'V',
+#endif
+#ifdef USE_SYSLOG
+ 'Y',
+#endif
+#ifdef ZIP_LINKS
+ 'z',
+#endif
+ '\0'
+};
+
+#include "numeric.h"
+#include "common.h"
+#include "sys.h"
+#include "whowas.h"
+#include "hash.h"
+#include <sys/file.h>
+#ifdef HPUX
+#include <fcntl.h>
+#endif
+#if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
+ !defined(__convex__)
+#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
+
+#ifdef DEBUGMODE
+static char debugbuf[1024];
+
+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;
+{
+ int err = errno;
+
+ if ((debuglevel >= 0) && (level <= debuglevel)) {
+ (void) sprintf (debugbuf, form, p1, p2, p3, p4, p5, p6, p7, p8, p9,
+ p10);
+ if (local[2]) {
+ local[2]->sendM++;
+ local[2]->sendB += strlen (debugbuf);
+ }
+ (void) fprintf (stderr, "%s", debugbuf);
+ (void) fputc ('\n', stderr);
+ }
+ errno = err;
+}
+
+/*
+ * 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(__linux__) && !defined(__Darwin__)
+ 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.",
+ me.name, RPL_STATSDEBUG, nick, strerror (errno));
+ return;
+ }
+ secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
+
+ sendto_one (cptr,
+ ":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
+ me.name, RPL_STATSDEBUG, nick, mins, secs, umin, usec,
+ smin, ssec);
+#endif
+#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);
+ sendto_one (cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u",
+ me.name, RPL_STATSDEBUG, nick, tot,
+ (u_int) ((char *)sbrk ((size_t) 0) - (char *) sbrk0));
+ return;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_err.c
+ * Copyright (C) 1992 Darren Reed
+ * Copyright (C) 1999 Maarten van den Bosch
+ *
+ * This program is free software; you can 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 "h.h"
+
+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, ":Hello %s, Welcome to the " irc_network " IRC Network!"},
+/* 002 */
+ {RPL_YOURHOST, ":Your host is %s, running version %s"},
+/* 003 */
+ {RPL_CREATED, ":This server was created on %s"},
+/* 004 */
+ {RPL_MYINFO, "%s %s aAcfgiIjknNoOrRstxy bceHiklmnorRstv"},
+/* 005 */
+ {RPL_PROTOCTL, "%s :are available on this server"},
+/* 006 */
+ {RPL_MAP, ":%s%-*s (Users:%5d) (%2d%%)"},
+/* 007 */
+ {RPL_MAPEND, ":End of /MAP"},
+ {0, (char *) NULL}
+};
+
+static Numeric numeric_errors[] = {
+/* 401 */
+ {ERR_NOSUCHNICK, "%s :No such nickname/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"},
+/* 410 */
+ {ERR_CANNOTKNOCK, ":Cannot knock on %s (%s)"},
+/* 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"},
+/* 415 */
+ {ERR_SERVICESUP,
+ "%s :Denied, This command cannot be executed while services are online."},
+/* 416 */
+ {0, (char *) NULL},
+/* 417 */
+ {0, (char *) NULL},
+/* 418 */
+ {0, (char *) NULL},
+/* 419 */
+ {0, (char *) NULL},
+/* 420 */
+ {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 */
+ {0, (char *) NULL},
+/* 426 */
+ {0, (char *) NULL},
+/* 427 */
+ {0, (char *) NULL},
+/* 428 */
+ {0, (char *) NULL},
+/* 429 */
+ {0, (char *) NULL},
+/* 430 */
+ {0, (char *) NULL},
+/* 431 */
+ {ERR_NONICKNAMEGIVEN, ":No nickname given"},
+/* 432 */
+ {ERR_ERRONEUSNICKNAME, "%s :Erroneous Nickname: \2%s\2"},
+/* 433 */
+ {ERR_NICKNAMEINUSE,
+ "%s :Nickname is already in use, please choose another."},
+/* 434 */
+ {ERR_SERVICENAMEINUSE, (char *) NULL},
+/* 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 \2%d\2 seconds"},
+/* 439 */
+ {ERR_TARGETTOOFAST,
+ "%s :Message target change too fast. Please wait \2%d\2 seconds"},
+/* 440 */
+ {ERR_SERVICESDOWN,
+ "%s :Services is currently down. Please wait a few moments, and then try again."},
+/* 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 :is already on channel %s"},
+/* 444 */
+ {ERR_NOLOGIN, "%s :User not logged in"},
+/* 445 */
+ {ERR_SUMMONDISABLED, ":SUMMON has been disabled"},
+/* 446 */
+ {ERR_USERSDISABLED, ":USERS has been disabled"},
+/* 447 */
+ {0, (char *) NULL},
+/* 448 */
+ {0, (char *) NULL},
+/* 449 */
+ {0, (char *) NULL},
+/* 450 */
+ {0, (char *) NULL},
+/* 451 */
+ {ERR_NOTREGISTERED, ":You have not registered"},
+/* 452 */
+ {0, (char *) NULL},
+/* 453 */
+ {0, (char *) NULL},
+/* 454 */
+ {0, (char *) NULL},
+/* 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."},
+/* 456 */
+ {0, (char *) NULL},
+/* 457 */
+ {0, (char *) NULL},
+/* 458 */
+ {0, (char *) NULL},
+/* 459 */
+ {0, (char *) NULL},
+/* 460 */
+ {0, (char *) NULL},
+/* 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 " KLINE_ADDRESS
+ " 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 */
+ {0, (char *) NULL},
+/* 470 */
+ {0, (char *) NULL},
+/* 471 */
+ {ERR_CHANNELISFULL, "%s :Cannot join channel because it is full (+l)"},
+/* 472 */
+ {ERR_UNKNOWNMODE, "%c :is an unknown mode char"},
+/* 473 */
+ {ERR_INVITEONLYCHAN,
+ "%s :Cannot join channel because it is invite only (+i)"},
+/* 474 */
+ {ERR_BANNEDFROMCHAN,
+ "%s :Cannot join channel because you are banned (+b)"},
+/* 475 */
+ {ERR_BADCHANNELKEY,
+ "%s :Cannot join channel as you need a correct key (+k)"},
+/* 476 */
+ {ERR_BADCHANMASK, "%s :Bad Channel Mask"},
+/* 477 */
+ {ERR_NEEDREGGEDNICK,
+ "%s :Your nickname must be registered and identified with NickServ in order to join this channel. For help with registering your nick, please join #help"},
+/* 478 */
+ {ERR_BANLISTFULL, "%s %s :Channel ban/ignore list is full"},
+/* 479 */
+ {ERR_NEEDREGGEDNICKTOMSG, "%s is only accepting messages from registered and identified to nicks. For help with registering your nick, please join #help"},
+/* 480 */
+ {0, (char *) NULL},
+/* 481 */
+ {ERR_NOPRIVILEGES,
+ ":Permission Denied- You do not have the correct IRC Operator privileges"},
+/* 482 */
+ {ERR_CHANOPRIVSNEEDED, "%s :Channel Operator status required."},
+/* 483 */
+ {ERR_CANTKILLSERVER, ":You cant kill a server!"},
+/* 484 */
+ {ERR_ISROOT, "%s %s :Cannot kick a Services Root Administrator"},
+/* 485 */
+ {0, (char *) NULL},
+/* 486 */
+ {0, (char *) NULL},
+/* 487 */
+ {0, (char *) NULL},
+/* 488 */
+ {0, (char *) NULL},
+/* 489 */
+ {0, (char *) NULL},
+/* 490 */
+ {0, (char *) NULL},
+/* 491 */
+ {ERR_NOOPERHOST, ":No O-lines for your host"},
+/* 492 */
+ {ERR_NOSERVICEHOST, (char *) NULL},
+/* 493 */
+ {0, (char *) NULL},
+/* 494 */
+ {0, (char *) NULL},
+/* 495 */
+ {0, (char *) NULL},
+/* 496 */
+ {0, (char *) NULL},
+/* 497 */
+ {0, (char *) NULL},
+/* 498 */
+ {0, (char *) NULL},
+/* 499 */
+ {0, (char *) NULL},
+/* 500 */
+ {0, (char *) NULL},
+/* 501 */
+ {ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag"},
+/* 502 */
+ {ERR_USERSDONTMATCH, ":Can not change mode for other users"},
+/* 503 */
+ {0, (char *) NULL},
+/* 504 */
+ {0, (char *) NULL},
+/* 505 */
+ {0, (char *) NULL},
+/* 506 */
+ {0, (char *) NULL},
+/* 507 */
+ {0, (char *) NULL},
+/* 508 */
+ {0, (char *) NULL},
+/* 509 */
+ {0, (char *) NULL},
+/* 510 */
+ {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"},
+/* 514 */
+ {0, (char *) NULL},
+/* 515 */
+ {0, (char *) NULL},
+/* 516 */
+ {0, (char *) NULL},
+/* 517 */
+ {0, (char *) NULL},
+/* 518 */
+ {0, (char *) NULL},
+/* 519 */
+ {0, (char *) NULL},
+/* 520 */
+ {0, (char *) NULL},
+/* 521 */
+ {ERR_LISTSYNTAX, "Bad list syntax, type /quote list ? or /raw list ?"},
+ {0, (char *) NULL}
+};
+
+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 */
+ {0, (char *) NULL},
+/* 308 */
+ {RPL_WHOISADMIN, "%s :is a Server Administrator"},
+/* 309 */
+ {RPL_WHOISSADMIN, "%s :is a Services Operator"},
+/* 310 */
+ {0, (char *) NULL},
+/* 311 */
+ {RPL_WHOISUSER, "%s %s %s * :%s"},
+/* 312 */
+ {RPL_WHOISSERVER, "%s %s :%s"},
+/* 313 */
+ {RPL_WHOISOPERATOR, "%s :is %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 :second(s) idle, signon time"},
+/* 318 */
+ {RPL_ENDOFWHOIS, "%s :End of /WHOIS list."},
+/* 319 */
+ {RPL_WHOISCHANNELS, "%s :%s"},
+/* 320 */
+ {RPL_WHOISCONNECTION, "%s :Host: %s, Server: %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"},
+/* 325 */
+ {0, (char *) NULL},
+/* 326 */
+ {0, (char *) NULL},
+/* 327 */
+ {0, (char *) NULL},
+/* 328 */
+ {0, (char *) NULL},
+/* 329 */
+ {RPL_CREATIONTIME, "%s %lu"},
+/* 330 */
+ {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 */
+ {0, (char *) NULL},
+/* 336 */
+ {0, (char *) NULL},
+/* 337 */
+ {0, (char *) NULL},
+/* 338 */
+ {0, (char *) NULL},
+/* 339 */
+ {0, (char *) NULL},
+/* 340 */
+ {0, (char *) NULL},
+/* 341 */
+ {RPL_INVITING, "%s %s"},
+/* 342 */
+ {RPL_SUMMONING, "%s :User summoned to irc"},
+/* 343 */
+ {0, (char *) NULL},
+/* 344 */
+ {0, (char *) NULL},
+/* 345 */
+ {0, (char *) NULL},
+/* 346 */
+ {0, (char *) NULL},
+/* 347 */
+ {0, (char *) NULL},
+/* 348 */
+ {0, (char *) NULL},
+/* 349 */
+ {0, (char *) NULL},
+/* 350 */
+ {0, (char *) NULL},
+/* 351 */
+ {RPL_VERSION, "%s.%s %s :%s"},
+/* 352 */
+ {RPL_WHOREPLY, "%s %s %s %s %s %s :%d %s"},
+/* 353 */
+ {RPL_NAMREPLY, "%s"},
+/* 354 */
+ {0, (char *) NULL},
+/* 355 */
+ {0, (char *) NULL},
+/* 356 */
+ {0, (char *) NULL},
+/* 357 */
+ {0, (char *) NULL},
+/* 358 */
+ {0, (char *) NULL},
+/* 359 */
+ {0, (char *) NULL},
+/* 360 */
+ {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"},
+/* 370 */
+ {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."},
+/* 377 */
+ {0, (char *) NULL},
+/* 378 */
+ {RPL_WHOISHOST, "%s %s :Real nick@host"},
+/* 379 */
+ {RPL_EXBANLIST, "%s %s %s %lu"},
+/* 380 */
+ {RPL_EXBANLISTEND, "%s :End of Channel Exception Ban List"},
+/* 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},
+/* 386 */
+ {RPL_HOSTRESTRICTLIST, "%s %s %s %lu"},
+/* 387 */
+ {RPL_HOSTRESTRICTLISTEND, "%s :End of Channel Host Restrict List"},
+/* 388 */
+ {0, (char *) NULL},
+/* 389 */
+ {0, (char *) NULL},
+/* 390 */
+ {0, (char *) NULL},
+/* 391 */
+ {RPL_TIME, "%s :%s"},
+/* 392 */
+ {0, (char *) NULL},
+/* 393 */
+ {0, (char *) NULL},
+/* 394 */
+ {0, (char *) NULL},
+/* 395 */
+ {0, (char *) NULL},
+/* 396 */
+ {0, (char *) NULL},
+/* 397 */
+ {0, (char *) NULL},
+/* 398 */
+ {0, (char *) NULL},
+/* 399 */
+ {0, (char *) NULL},
+/* 400 */
+ {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 %ld"},
+/* 205 */
+ {RPL_TRACEUSER, "User %d %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"},
+/* 210 */
+ {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"},
+/* 221 */
+ {RPL_UMODEIS, "%s"},
+/* 222 */
+ {RPL_SQLINE_NICK, "%s :%s"},
+/* 223 */
+ {RPL_STATSFLINE, "%c %s * * * *"},
+/* 224 */
+ {0, (char *) NULL},
+/* 225 */
+ {0, (char *) NULL},
+/* 226 */
+ {0, (char *) NULL},
+/* 227 */
+ {0, (char *) NULL},
+/* 228 */
+ {0, (char *) NULL},
+/* 229 */
+ {0, (char *) NULL},
+/* 230 */
+ {0, (char *) NULL},
+/* 231 */
+ {RPL_SERVICEINFO, (char *) NULL},
+/* 232 */
+ {RPL_ENDOFSERVICES, (char *) NULL},
+/* 233 */
+ {RPL_SERVICE, (char *) NULL},
+/* 234 */
+ {RPL_SERVLIST, (char *) NULL},
+/* 235 */
+ {RPL_SERVLISTEND, (char *) NULL},
+/* 236 */
+ {RPL_JINX, "%s :%s"},
+ {RPL_STATSJINX, "J %s :%s"},
+ {0, (char *) NULL},
+ {0, (char *) NULL},
+ {0, (char *) NULL},
+/* 241 */
+ {RPL_STATSLLINE, "%c %s * %s %d %d"},
+/* 242 */
+ {RPL_STATSUPTIME, ":Server Up \2%d\2 day(s), %d:%02d:%02d"},
+/* 243 */
+ {RPL_STATSOLINE, "%c %s * %s %u %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 client(s))"},
+/* 251 */
+ {RPL_LUSERCLIENT,
+ ":There are %d user(s) and %d invisible on %d server(s)"},
+/* 252 */
+ {RPL_LUSEROP, "%d :operator(s) online"},
+/* 253 */
+ {RPL_LUSERUNKNOWN, "%d :unknown connection(s)"},
+/* 254 */
+ {RPL_LUSERCHANNELS, "%d :channel(s) formed"},
+/* 255 */
+ {RPL_LUSERME, ":I have %d client(s) and %d server(s)"},
+/* 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}
+};
+
+/*
+ * 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"},
+/* 608 */
+ {RPL_WATCHCLEAR, ":Your WATCH list is now empty"},
+/* 609 */
+ {RPL_OMOTDSTART, ":%s IRC Operator MOTD"},
+/* 610 */
+ {RPL_OMOTD, ":- %s"},
+/* 611 */
+ {RPL_ENDOFOMOTD, ":End of IRC Operator MOTD."},
+/* 612 */
+ {RPL_WHOWASIP, ":%s was using IP %s."},
+/* 613 */
+ {RPL_STATSGZLINE, "%c %s %s %s %i %i %s"},
+/* 614 */
+ {RPL_WHOISMODES, ":%s (%s) is using modes: %s"},
+/* 615 */
+ {RPL_MAPMORE, ":%s%-*s --> *more*"},
+/* 616 */
+ {RPL_POLICY,
+ ":Welcome to the Serenity-IRC network \2%s\2! Using Serenity-IRC constitutes agreement with our Acceptable Use Policy. You may view our policy at http://www.serenity-irc.net/aup"},
+/* 617 */
+ {ERR_HTCTOOFAST,
+ ":You are sending too fast. Please wait %i seconds before sending new commands."},
+/* 618 */
+ {ERR_NEEDIDTODCC, ":Your DCC command to %s was blocked. In order to prevent abuse, both the initiating and the accepting party of any DCC related commands must have a registered nickname and be identified to that nickname."},
+ {0, (char *) NULL}
+};
+
+char *err_str (numeric)
+ int numeric;
+{
+ Numeric *nptr;
+ 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;
+{
+ Numeric *nptr;
+ 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;
+ int num;
+ char *tail;
+{
+ 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;
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include <sys/time.h>
+#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__)
+#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
+#include "h.h"
+
+#define _1MEG (1024.0)
+#define _1GIG (1024.0*1024.0)
+#define _1TER (1024.0*1024.0*1024.0)
+#define _GMKs(x) ( (x > _1TER) ? "Terabytes" : ((x > _1GIG) ? "Gigabytes" : \
+ ((x > _1MEG) ? "Megabytes" : "Kilobytes")))
+#define _GMKv(x) ( (x > _1TER) ? (float)((float)x/(float)_1TER) : (((float)x > (float)_1GIG) ? \
+ (float)((float)x/(float)_1GIG) : ((x > _1MEG) ? (float)((float)x/(float)_1MEG) : (float)x)))
+aEvent *EventList = NULL;
+
+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;
+ 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 19%02d -- %02d:%02d %c%02d:%02d",
+ weekdays[lt->tm_wday], months[lt->tm_mon], lt->tm_mday,
+ 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)
+ 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)
+ char *nick, *name, *host;
+{
+ static char namebuf[NICKLEN + USERLEN + HOSTLEN + 6];
+ 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];
+ 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->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->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)
+ aClient *cptr;
+ char *host;
+{
+ 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 */
+{
+ aClient *acptr;
+ aClient *next;
+#ifdef FNAME_USERLOG
+ time_t on_for;
+#endif
+ static char comment1[HOSTLEN + HOSTLEN + 2];
+ static int recurse = 0;
+
+
+ if (MyConnect (sptr)) {
+ 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->host,
+ comment);
+ current_load_data.conn_count--;
+ if (IsPerson (sptr)) {
+ char mydom_mask[HOSTLEN + 1];
+ mydom_mask[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 = time (NULL) - 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),
+ (int) on_for / 3600,
+ (int) (on_for % 3600) / 60, (int) on_for % 60,
+ sptr->user->username, sptr->user->host,
+ 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;
+{
+ aClient *acptr;
+ int i;
+ 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++) {
+ 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);
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_SQUIT, sptr,
+ ":%s SQUIT %s :%s",
+ from->name, sptr->name, comment);
+#endif
+ }
+ else {
+ sendto_one (acptr, "SQUIT %s :%s", sptr->name, comment);
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_SQUIT, sptr,
+ "SQUIT %s :%s", sptr->name, comment);
+#endif
+ }
+ }
+ }
+ else if (IsPing (sptr)) {
+ del_queries ((char *) sptr);
+ end_ping (sptr);
+ return;
+ }
+ 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 (AskedPing (sptr))
+ cancel_ping (sptr, NULL);
+
+ /*
+ ** 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);
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_QUIT,
+ ":%s QUIT :%s", sptr->name, comment);
+#endif
+ }
+ /*
+ ** 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);
+
+ 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 ()
+{
+ aClient *acptr;
+ 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;
+{
+ aClient *acptr;
+ int i;
+ struct stats *sp;
+ struct stats tmp;
+ time_t now = time (NULL);
+
+ sp = &tmp;
+ bcopy ((char *) ircstp, (char *) sp, sizeof (*sp));
+ for (i = 0; i < MAXCONNECTIONS; i++) {
+ 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 :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);
+}
+
+void AddEvent (void (*func) (char *), char *arg, unsigned int delay)
+{
+ aEvent *eptr;
+ eptr = make_event ();
+ if (arg != NULL)
+ strncpyzt (eptr->arg, arg, ARGLEN - 2);
+ eptr->func = func;
+ eptr->exectime = now + delay;
+ if (EventList == NULL)
+ EventList = eptr;
+ else {
+ EventList->prev = eptr;
+ eptr->next = EventList;
+ EventList = eptr;
+ }
+}
+
+void CheckEvents ()
+{
+ aEvent *eptr;
+ aEvent *eptr2;
+ if (EventList == NULL)
+ return;
+ for (eptr = EventList; eptr; eptr = eptr2) {
+ eptr2 = eptr->next;
+ if (now >= eptr->exectime) {
+ eptr->func (eptr->arg);
+ if (eptr->prev)
+ eptr->prev->next = eptr->next;
+ else
+ EventList = eptr->next;
+ if (eptr->next)
+ eptr->next->prev = eptr->prev;
+ free_event (eptr);
+ }
+ }
+}
+
+void serv_info (aClient * cptr, char *name)
+{
+ long SendQ, RecvQ, uptime, timeofday;
+ time_t t1;
+
+ timeofday = time (&t1);
+
+ SendQ = RecvQ = 0;
+
+ uptime = (timeofday - me.since);
+
+ sendto_one (cptr, ":%s %d %s :*** Bandwidth usage for server %s ***",
+ me.name, RPL_STATSDEBUG, name, me.name);
+ sendto_one (cptr, ":%s %d %s :Maximum send peak : %7.2f K/s",
+ me.name, RPL_STATSDEBUG, name, (float) max_sendqs);
+ sendto_one (cptr, ":%s %d %s :Maximum recv peak : %7.2f K/s",
+ me.name, RPL_STATSDEBUG, name, (float) max_recvqs);
+ sendto_one (cptr, ":%s %d %s :Current server send : %7.2f K/s",
+ me.name, RPL_STATSDEBUG, name, (float) me.deltaSQK);
+ sendto_one (cptr, ":%s %d %s :Current server recv : %7.2f K/s",
+ me.name, RPL_STATSDEBUG, name, (float) me.deltaRQK);
+ sendto_one (cptr,
+ ":%s %d %s :Server send : %7.2f %s (%7.2f %s C.) (%4.1fK/s)",
+ me.name, RPL_STATSDEBUG, name, _GMKv (me.u_sendK),
+ _GMKs (me.u_sendK), _GMKv (me.sendK), _GMKs (me.sendK),
+ (float) ((float) me.sendK / (float) uptime));
+ sendto_one (cptr,
+ ":%s %d %s :Server recv : %7.2f %s (%7.2f %s C.) (%4.1fK/s)",
+ me.name, RPL_STATSDEBUG, name, _GMKv (me.u_receiveK),
+ _GMKs (me.u_receiveK), _GMKv (me.receiveK),
+ _GMKs (me.receiveK),
+ (float) ((float) me.receiveK / (float) uptime));
+ sendto_one (cptr, ":%s %d %s :Send compression : %7.2f percent.",
+ me.name, RPL_STATSDEBUG, name,
+ (me.u_sendK >
+ 0) ? ((float) (100 -
+ (((float) me.sendK / (float) me.u_sendK) *
+ 100))) : 0);
+ sendto_one (cptr, ":%s %d %s :Recv compression : %7.2f percent.",
+ me.name, RPL_STATSDEBUG, name,
+ (me.u_receiveK >
+ 0) ? ((float) (100 -
+ (((float) me.receiveK /
+ (float) me.u_receiveK) * 100))) : 0);
+ return;
+}
+
+void get_max_users (void)
+{
+ int fd, nr;
+ char *tmp;
+ static char *parv[HOSTLEN + 1];
+ char line[80];
+ int parc;
+
+ fd = open (LUSERS, O_RDONLY);
+ if (fd == -1)
+ return;
+
+ (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';
+ }
+
+ parc = 0;
+
+ parc = str2array (parv, line, " ");
+
+ (void) dgets (-1, NULL, 0); /* make sure buffer is at empty pos */
+ (void) close (fd);
+
+ if (parc < 2)
+ return;
+
+ lu_mglobalu = atoi (parv[0]);
+ lu_mlu = atoi (parv[1]);
+
+ return;
+}
+
+void CheckBandwidth (void)
+{
+ me.deltaRQK = (me.receiveK - me.previousRQK);
+ me.deltaSQK = (me.sendK - me.previousSQK);
+ if (me.deltaRQK > max_recvqs)
+ max_recvqs = me.deltaRQK;
+ if (me.deltaSQK > max_sendqs)
+ max_sendqs = me.deltaSQK;
+ me.previousRQK = me.receiveK;
+ me.previousSQK = me.sendK;
+ return;
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "h.h"
+
+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;
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_ping.c
+ * Copyright (C) 1994 Carlo K ( Run @ undernet.org )
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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 "patchlevel.h"
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#if defined(__hpux)
+#include "inet.h"
+#endif
+#include <fcntl.h>
+#include "sock.h" /* If FD_ZERO isn't defined up to this point, */
+ /* define it (BSD4.2 needs this) */
+#include "h.h"
+
+#define UPINGBUFSIZE 2000 /* Lot bigger then 1024, bit smaller then 2048 */
+#define UPINGTIMEOUT 120 /* Timeout waitting for first ping response */
+
+
+/*
+ * sendto_one_notice
+ *
+ * sendto_one_notice should be used for all NOTICEs that might be
+ * addressed to a remote user, *and* are from this server
+ *
+ * *** MAKE ME LOOK MORE PRETTY:
+ * This really should not be here, but I'm too lazy to go change all
+ * the notice calls below. Seeing as s_uping.c is the only place from
+ * which it's called, and because it should really be removed, I've
+ * put it here; instead of in send.c -TheShadow
+ */
+void sendto_one_notice (to, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+ aClient *to;
+{
+ char nbuf[1024];
+
+ (void) sprintf (nbuf, "NOTICE %s :", to->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (to, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+
+ return;
+}
+
+extern u_long inet_addr ();
+
+void end_ping ();
+void cancel_ping ();
+
+/*
+ * start_ping
+ *
+ * As for now, I am abusing the client structure for a ping connection.
+ * Used members are:
+ * These are used by existing routines as well, and do have their own meaning:
+ * fd : The socket file descriptor.
+ * status : To flag that this IS one of these abused ping structures
+ * sockhost : Name of requested server to ping (aconf->host).
+ * name : aconf->name
+ * ip : ip#
+ * These have more or less their own meaning,
+ * but are not used by existing routines:
+ * flags : To flag that a next ping is requested.
+ * port : Requested remote port.
+ * These are only used by the 'uping' routines
+ * and have totally different meanings:
+ * buffer : buffer hold pingtimes of received packets
+ * confs : recv/send (char *) buffer.
+ * hopcount : Total number of requested pings
+ * count : Number of pings left to send.
+ * hashv : Number of pings left to be received.
+ * NOTE: This is not used by any other part of DreamForge and is
+ * merely included for UPING to work. This is not the
+ * ideal idea as we waste memory, albeit very little,
+ * simply for UPING. -TheShadow
+ * acpt : client asking for this ping
+ * lasttime : last time a ping was sent
+ * firsttime: recvfrom timeout
+ * since : timeout in seconds to next recvfrom
+ * receiveK : minimum in ms
+ * sendM : average in ms
+ * receiveM : maximum in ms
+ */
+int start_ping (cptr)
+ aClient *cptr;
+{
+ struct sockaddr_in remote_addr;
+
+ Debug ((DEBUG_NOTICE, "start_ping(%x) status %d", cptr, cptr->status));
+
+ if (!(cptr->acpt))
+ return -1;
+
+ bcopy ((char *) &cptr->ip, (char *) &remote_addr.sin_addr,
+ sizeof (struct in_addr));
+ remote_addr.sin_port = htons (cptr->port);
+ remote_addr.sin_family = AF_INET;
+
+ sendto_one_notice (cptr->acpt,
+ "Sending %d ping%s to %s[%s] port %d",
+ cptr->hopcount,
+ (cptr->hopcount == 1) ? "" : "s", cptr->name,
+ inetntoa ((char *) &remote_addr.sin_addr),
+ ntohs (remote_addr.sin_port));
+
+ cptr->firsttime = time (NULL) + UPINGTIMEOUT;
+ cptr->since = UPINGTIMEOUT;
+ cptr->flags |= (FLAGS_PING);
+
+ return 0;
+}
+
+/*
+ * send_ping
+ *
+ */
+void send_ping (cptr)
+ aClient *cptr;
+{
+ struct sockaddr_in remote_addr;
+ struct timeval tv;
+
+ bcopy ((char *) &cptr->ip, (char *) &remote_addr.sin_addr,
+ sizeof (struct in_addr));
+ remote_addr.sin_port = htons (cptr->port);
+ remote_addr.sin_family = AF_INET;
+
+ (void) gettimeofday (&tv, NULL);
+ (void) sprintf ((char *) cptr->confs, " %10lu%c%6lu",
+ tv.tv_sec, '\0', tv.tv_usec);
+
+ Debug ((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
+ (char *) cptr->confs, (char *) cptr->confs + 12,
+ inetntoa ((char *) &remote_addr.sin_addr),
+ ntohs (remote_addr.sin_port), cptr->fd));
+
+ if (sendto (cptr->fd, (char *) cptr->confs, 1024, 0,
+ (struct sockaddr *) &remote_addr,
+ sizeof (struct sockaddr_in)) != 1024) {
+ if (cptr->acpt)
+ sendto_one_notice (cptr->acpt, "UPING: sendto() failed: %s",
+ strerror (get_sockerr (cptr)));
+// Debug((DEBUG_SEND, "send_ping: sendto failed on %d (%d)", cptr->fd, err));
+ (void) end_ping (cptr);
+ }
+ else if (--(cptr->count) <= 0) {
+ ClearPing (cptr);
+ if (cptr->hashv <= 0)
+ end_ping (cptr);
+ }
+ return;
+}
+
+/*
+ * read_ping
+ *
+ */
+void read_ping (cptr)
+ aClient *cptr;
+{
+ int addr_len = sizeof (struct sockaddr_in);
+ struct sockaddr_in remote_addr;
+ struct timeval tv;
+ int len;
+ unsigned long int pingtime;
+ char *s;
+
+ bcopy ((char *) &cptr->ip, (char *) &remote_addr.sin_addr,
+ sizeof (struct in_addr));
+ remote_addr.sin_port = htons (cptr->port);
+ remote_addr.sin_family = AF_INET;
+
+ (void) gettimeofday (&tv, NULL);
+
+ if ((len = recvfrom (cptr->fd, (char *) cptr->confs, UPINGBUFSIZE, 0,
+ (struct sockaddr *) &remote_addr,
+ &addr_len)) == -1) {
+ int err = errno;
+ sendto_one_notice (cptr->acpt,
+ "UPING: recvfrom: %s",
+ strerror (get_sockerr (cptr)));
+ Debug ((DEBUG_SEND, "read_ping: recvfrom: %d", err));
+ if (err != EAGAIN)
+ end_ping (cptr);
+ return;
+ }
+ if (len < 19)
+ return; /* Broken packet */
+
+ pingtime = (tv.tv_sec - atoi ((char *) cptr->confs + 1)) * 1000 +
+ (tv.tv_usec -
+ atoi ((char *) cptr->confs + strlen ((char *) cptr->confs) +
+ 1)) / 1000;
+ cptr->sendM += pingtime;
+ if (!(cptr->receiveK) || (cptr->receiveK > pingtime))
+ cptr->receiveK = pingtime;
+ if (pingtime > cptr->receiveM)
+ cptr->receiveM = pingtime;
+ /* Wait at most 10 times the average pingtime for the next one: */
+ if ((cptr->since =
+ cptr->sendM / (100 * (cptr->hopcount - cptr->hashv + 1))) < 2)
+ cptr->since = 2;
+ cptr->firsttime = tv.tv_sec + cptr->since;
+
+ Debug (("read_ping: %d bytes, ti %lu: [%s %s] %u ms",
+ len, cptr->since, (char *) cptr->confs,
+ (char *) cptr->confs + strlen ((char *) cptr->confs) + 1,
+ pingtime));
+
+ s = cptr->buffer + strlen (cptr->buffer);
+ sprintf (s, " %lu", pingtime);
+
+ if ((--(cptr->hashv) <= 0 && !DoPing (cptr)) || !(cptr->acpt))
+ end_ping (cptr);
+
+ return;
+}
+
+int ping_server (cptr, hp)
+ aClient *cptr;
+ struct hostent *hp;
+{
+ if ((!cptr->ip.s_addr)) {
+ struct hostent *hp;
+ char *s;
+ Link lin;
+
+ if (!(cptr->acpt))
+ return -1; /* Oper left already */
+
+ lin.flags = ASYNC_PING;
+ lin.value.cptr = cptr;
+ nextdnscheck = 1;
+ s = (char *) index (cptr->sockhost, '@');
+ s++; /* should never be NULL; cptr->sockhost is actually a conf->host */
+ if ((cptr->ip.s_addr = inet_addr (s)) == -1) {
+ cptr->ip.s_addr = 0;
+ hp = gethost_byname (s, &lin);
+ Debug ((DEBUG_NOTICE, "ping_sv: hp %x ac %x ho %s", hp, cptr, s));
+ if (!hp)
+ return 0;
+ bcopy (hp->h_addr, (char *) &cptr->ip, sizeof (struct in_addr));
+ }
+ }
+ return start_ping (cptr);
+}
+
+/*
+ ** m_uping -- by Run
+ **
+ ** parv[0] = sender prefix
+ ** parv[1] = pinged server
+ ** parv[2] = port
+ ** parv[3] = hunted server
+ ** parv[4] = number of requested pings
+ */
+int m_uping (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aConfItem *aconf;
+ int fd, opt;
+ int port = atoi (UDPPORT);
+
+ if (!IsPrivileged (sptr)) {
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ return -1;
+ }
+ if (parc < 2) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "UPING");
+ return 0;
+ }
+ if (MyClient (sptr)) {
+ if (parc == 2) {
+ parv[parc++] = UDPPORT;
+ parv[parc++] = me.name;
+ parv[parc++] = "5";
+ }
+ else if (parc == 3) {
+ if (isdigit (*parv[2])) {
+ parv[parc++] = me.name;
+ }
+ else {
+ parv[parc++] = parv[2];
+ parv[2] = UDPPORT;
+ }
+ parv[parc++] = "5";
+ }
+ else if (parc == 4) {
+ if (isdigit (*parv[2])) {
+ if (isdigit (*parv[3])) {
+ parv[parc++] = parv[3];
+ parv[3] = me.name;
+ }
+ else
+ parv[parc++] = "5";
+ }
+ else {
+ parv[parc++] = parv[3];
+ parv[3] = parv[2];
+ parv[2] = UDPPORT;
+ }
+ }
+ }
+ if (hunt_server (cptr, sptr, ":%s UPING %s %s %s %s", 3, parc, parv) !=
+ HUNTED_ISME)
+ return 0;
+
+ if (BadPtr (parv[4]) || atoi (parv[4]) <= 0) {
+ sendto_one_notice (sptr, "UPING: Illegal number of packets: %s",
+ parv[4]);
+ return 0;
+ }
+ /* Check if a CONNECT would be possible at all (adapted from m_connect) */
+ for (aconf = conf; aconf; aconf = aconf->next)
+ if (aconf->status == CONF_CONNECT_SERVER &&
+ match (parv[1], aconf->name) == 0)
+ break;
+ if (!aconf)
+ for (aconf = conf; aconf; aconf = aconf->next)
+ if (aconf->status == CONF_CONNECT_SERVER &&
+ (match (parv[1], aconf->host) == 0 ||
+ match (parv[1], index (aconf->host, '@') + 1) == 0))
+ break;
+ if (!aconf) {
+ sendto_one_notice (sptr, "UPING: Host %s not listed in ircd.conf",
+ parv[1]);
+ return 0;
+ }
+ if (AskedPing (sptr))
+ (void) cancel_ping (sptr, sptr); /* Cancel previous ping request */
+
+ /*
+ * Determine port: First user supplied, then default : 7007
+ */
+ if (!BadPtr (parv[2]) && (port = atoi (parv[2])) <= 0)
+ port = atoi (UDPPORT);
+
+ (void) alarm (2);
+ if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
+ int err = errno;
+ (void) alarm (0);
+ sendto_ops ("m_uping: socket: %s", (err != EAGAIN) ?
+ strerror (err) : "No more sockets");
+ sendto_one_notice (sptr, "UPING: Unable to create udp ping socket");
+#ifdef USE_SYSLOG
+ syslog (LOG_ERR, "Unable to create udp ping socket");
+#endif
+ return 0;
+ }
+ (void) alarm (0);
+
+ if (fcntl (fd, F_SETFL, FNDELAY) == -1) {
+ sendto_ops ("m_uping: fcntl FNDELAY: %s", strerror (errno));
+ sendto_one_notice (sptr, "UPING: Can't set fd non-blocking");
+ close (fd);
+ return 0;
+ }
+ /*
+ ** On some systems, receive and send buffers must be equal in size.
+ ** Others block select() when the buffers are too small
+ ** (Linux 1.1.50 blocks when < 2048) --Run
+ */
+ opt = 2048;
+ if (setsockopt
+ (fd, SOL_SOCKET, SO_SNDBUF, (OPT_TYPE *) & opt, sizeof (opt))
+ < 0
+ || setsockopt (fd, SOL_SOCKET, SO_RCVBUF, (OPT_TYPE *) & opt,
+ sizeof (opt)) < 0) {
+ int err = errno;
+ sendto_ops ("m_uping: setsockopt SO_SNDBUF|SO_RCVBUF: %s",
+ strerror (err));
+ sendto_one_notice (sptr, "UPING: error in setsockopt: %s",
+ strerror (err));
+ close (fd);
+ return 0;
+ }
+ if (fd >= MAXCONNECTIONS) {
+ sendto_ops ("Can't allocate fd for uping (all connections in use)");
+ sendto_one_notice (sptr, "UPING: All connections in use");
+ close (fd);
+ return 0;
+ }
+ if (fd > highest_fd)
+ highest_fd = fd;
+ local[fd] = cptr = make_client (NULL, NULL);
+ cptr->confs = (Link *) MyMalloc (UPINGBUFSIZE); /* Really a (char *) */
+ cptr->fd = fd;
+ cptr->port = port;
+ cptr->hopcount = cptr->hashv = cptr->count = MIN (20, atoi (parv[4]));
+ strcpy (cptr->sockhost, aconf->host);
+ cptr->acpt = sptr;
+ SetAskedPing (sptr);
+ bcopy ((void *) &aconf->ipnum, (void *) &cptr->ip,
+ sizeof (struct in_addr));
+ strcpy (cptr->name, aconf->name);
+ cptr->firsttime = 0;
+ SetPing (cptr);
+
+ switch (ping_server (cptr, NULL)) {
+ case 0:
+ break;
+ case -1:
+ del_queries ((char *) cptr);
+ end_ping (cptr);
+ break;
+ }
+ return 0;
+}
+
+void end_ping (cptr)
+ register aClient *cptr;
+{
+ Debug ((DEBUG_DEBUG, "end_ping: %x", cptr));
+ if (cptr->acpt) {
+ if (cptr->firsttime) { /* Started at all ? */
+ if (cptr->hashv != cptr->hopcount) { /* Received any pings at all ? */
+ sendto_one_notice (cptr->acpt, "UPING %s%s", cptr->name,
+ cptr->buffer);
+ sendto_one_notice (cptr->acpt,
+ "UPING Stats: sent %d recvd %d ; min/avg/max = %lu/%lu/%lu ms",
+ cptr->hopcount - cptr->count,
+ cptr->hopcount - cptr->hashv,
+ cptr->receiveK,
+ (2 * cptr->sendM + cptr->hopcount -
+ cptr->hashv) / (2 * (cptr->hopcount -
+ cptr->hashv)),
+ cptr->receiveM);
+ }
+ else
+ sendto_one_notice (cptr->acpt,
+ "UPING: no response from %s within %d seconds",
+ cptr->name,
+ time (NULL) + cptr->since -
+ cptr->firsttime);
+ }
+ else
+ sendto_one_notice (cptr->acpt,
+ "UPING: Could not start ping to %s %d",
+ cptr->name, cptr->port);
+ }
+ (void) close (cptr->fd);
+ local[cptr->fd] = NULL;
+ if (cptr->acpt)
+ ClearAskedPing (cptr->acpt);
+ MyFree ((char *) cptr->confs);
+ free_client (cptr);
+}
+
+void cancel_ping (sptr, acptr)
+ aClient *sptr, *acptr;
+{
+ int i;
+ aClient *cptr;
+
+ Debug ((DEBUG_DEBUG, "Cancelling uping for %x (%s)", sptr, sptr->name));
+ for (i = highest_fd; i >= 0; i--)
+ if ((cptr = local[i]) && IsPing (cptr) && cptr->acpt == sptr) {
+ cptr->acpt = acptr;
+ del_queries ((char *) cptr);
+ end_ping (cptr);
+ break;
+ }
+ ClearAskedPing (sptr);
+}
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, ircd/s_serv.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.
+ */
+
+#include "config.h"
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "channel.h"
+#include "userload.h"
+#if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
+#include <time.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <time.h>
+#include "h.h"
+
+static void report_jinx (aClient * sptr);
+
+static char buf[BUFSIZE];
+VOIDSIG s_die ();
+/* I guess we can move this to somewhere else ... */
+
+/*
+** m_functions execute protocol messages on this server:
+**
+** cptr is always NON-NULL, pointing to a *LOCAL* client
+** structure (with an open socket connected!). This
+** identifies the physical socket where the message
+** originated (or which caused the m_function to be
+** executed--some m_functions may call others...).
+**
+** sptr is the source of the message, defined by the
+** prefix part of the message if present. If not
+** or prefix not found, then sptr==cptr.
+**
+** (!IsServer(cptr)) => (cptr == sptr), because
+** prefixes are taken *only* from servers...
+**
+** (IsServer(cptr))
+** (sptr == cptr) => the message didn't
+** have the prefix.
+**
+** (sptr != cptr && IsServer(sptr) means
+** the prefix specified servername. (?)
+**
+** (sptr != cptr && !IsServer(sptr) means
+** that message originated from a remote
+** user (not local).
+**
+** combining
+**
+** (!IsServer(sptr)) means that, sptr can safely
+** taken as defining the target structure of the
+** message in this server.
+**
+** *Always* true (if 'parse' and others are working correct):
+**
+** 1) sptr->from == cptr (note: cptr->from == cptr)
+**
+** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+** *cannot* be a local connection, unless it's
+** actually cptr!). [MyConnect(x) should probably
+** be defined as (x == x->from) --msa ]
+**
+** parc number of variable parameter strings (if zero,
+** parv is allowed to be NULL)
+**
+** parv a NULL terminated list of parameter pointers,
+**
+** parv[0], sender (prefix string), if not present
+** this points to an empty string.
+** parv[1]...parv[parc-1]
+** pointers to additional parameters
+** parv[parc] == NULL, *always*
+**
+** note: it is guaranteed that parv[0]..parv[parc-1] are all
+** non-NULL pointers.
+*/
+
+/*
+** m_version
+** parv[0] = sender prefix
+** parv[1] = remote server
+*/
+int m_version (cptr, sptr, parc, parv)
+ aClient *sptr, *cptr;
+ int parc;
+ char *parv[];
+{
+ extern char serveropts[];
+
+ /* Make sure they stick to the local server if not registered.
+ * -Studded */
+ if ((!IsRegistered (cptr)) && (!BadPtr (parv[1]))) {
+ sendto_one (cptr, ":%s %d VERSION :You have not registered",
+ me.name, ERR_NOTREGISTERED);
+ return -1;
+ }
+ 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,
+ debugmode, me.name, serveropts);
+ 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[];
+{
+ aConfItem *aconf;
+ char *server;
+ 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)) {
+ 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!
+ */
+ sendto_one (cptr, "ERROR :Already got a PROTOCTL from you.");
+ return 0;
+ }
+ cptr->flags |= FLAGS_PROTOCTL;
+
+ 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) {
+ SetNoQuit (cptr);
+ }
+ else if (strcmp (proto, "TOKEN") == 0) {
+ SetToken (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 (changed 05/10/99 to send server-version with it too -GZ)
+ **
+ ** parv[0] = sender prefix
+ ** parv[1] = servername
+ ** parv[2] = hopcount
+ ** parv[3] = timestamp / version
+ ** parv[4] = version
+ ** parv[5] = info
+ */
+
+int m_server (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ char *ch;
+ int i;
+ char info[REALLEN + 1], *inpath, *host, *encr;
+ char s_version[REALLEN + 1];
+ aClient *acptr, *bcptr;
+ aConfItem *aconf, *cconf;
+ int hop, ts = 0;
+
+ info[0] = '\0';
+ s_version[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 > 5) {
+ ts = atoi (parv[3]);
+ hop = atoi (parv[2]);
+ (void) strncpy (info, parv[5], REALLEN);
+ info[REALLEN] = '\0';
+ (void) strncpy (s_version, parv[4], REALLEN);
+ s_version[REALLEN] = '\0';
+ }
+ else if (parc > 4 && atoi (parv[2])) {
+ hop = atoi (parv[2]);
+ (void) strncpy (info, parv[4], REALLEN);
+ info[REALLEN] = '\0';
+ (void) strncpy (s_version, parv[3], REALLEN);
+ s_version[REALLEN] = '\0';
+ }
+ else if (parc > 3) {
+ (void) strncpy (info, parv[3], REALLEN);
+ info[REALLEN] = '\0';
+ (void) strncpy (s_version, parv[2], REALLEN);
+ s_version[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 */
+
+ /* Get a pre-peek at the password... */
+ if (IsUnknown (cptr)) {
+ aconf = find_conf_servern (host);
+ if (!aconf) {
+ sendto_one (cptr, "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");
+ }
+ encr = cptr->passwd;
+ 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;
+ }
+ /*
+ **
+ */
+ 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_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->version, s_version, REALLEN);
+ 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 :%s",
+ parv[0], acptr->name, hop + 1, ts,
+ acptr->version, acptr->info);
+ else
+ sendto_one (bcptr, ":%s SERVER %s %d %s :%s",
+ parv[0], acptr->name, hop + 1,
+ acptr->version, acptr->info);
+ }
+ /* Check for U-line status -- Barubary */
+ if (find_conf_host (cptr->confs, acptr->name, CONF_UWORLD))
+ acptr->flags |= FLAGS_ULINE;
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_SERVER, sptr,
+ ":%s SERVER %s %d %s :%s", parv[0],
+ acptr->name, hop + 1, acptr->version,
+ acptr->info);
+#endif
+ 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));
+ strncpyzt (cptr->version, s_version, REALLEN);
+ cptr->hopcount = hop;
+
+ 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)
+ aClient *cptr;
+{
+ aClient *acptr;
+ aConfItem *aconf, *bconf;
+ aChannel *chptr;
+ aJinxItem *ajinx;
+ aSqlineItem *asqline;
+
+ char *inpath, *host, *s, *encr, *ver;
+ int split, i, verflags;
+ char link_caps[200] = "";
+
+ 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 |
+ CONF_NZCONNECT_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 |
+ CONF_NZCONNECT_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");
+ }
+ encr = cptr->passwd;
+ 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
+ synchmode = 1;
+
+ /* Check for bitflags here */
+
+ if ((ver = (char *) strchr (cptr->version, '_'))) {
+ if (strlen (ver) > 4 && !strncmp (ver, "_cap", 4)) {
+ verflags = atoi (ver + 4);
+
+ if (verflags & VERSION_ZIPLINKS)
+ cptr->flags2 |= FLAGS2_CAPAB_ZIP;
+
+ sendto_ops
+ ("Synching with %s using bitflag protocol. Bitflag is %i.",
+ cptr->name, verflags);
+ }
+ else {
+ sendto_ops ("Suspicious version from server %s (%s)", cptr->name,
+ cptr->version);
+ }
+ }
+
+ if (IsUnknown (cptr)) {
+
+ sendto_one (cptr, "PROTOCTL %s", PROTOCTL_SUPPORTED);
+
+ 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_cap%i :%s",
+ my_name_for_link (me.name, aconf), version, VERSION_SEND,
+ (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 = '@';
+ }
+
+#ifdef ZIP_LINKS
+
+ if ((cptr->flags2 & FLAGS2_CAPAB_ZIP) &&
+ (bconf->status != CONF_NZCONNECT_SERVER)) {
+ strcat (link_caps, " ZIP_LINKS");
+ if (zip_init (cptr) == -1) {
+ zip_free (cptr);
+ sendto_realops ("Unable to setup compressed link for %s",
+ get_client_name (cptr, TRUE));
+ return exit_client (cptr, cptr, &me, "zip_init() failed");
+ }
+
+ cptr->flags2 |= (FLAGS2_ZIP | FLAGS2_ZIPFIRST);
+ }
+ else
+ cptr->flags2 &= ~FLAGS2_CAPAB_ZIP;
+#endif
+
+ det_confs_butmask (cptr,
+ 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);
+ if (find_conf_host (cptr->confs, cptr->name, CONF_UWORLD))
+ cptr->flags |= FLAGS_ULINE;
+ cptr->flags |= FLAGS_TS8;
+ nextping = time (NULL);
+#ifdef HUB
+ sendto_serv_butone (&me, ":%s GLOBOPS :Link with %s established.",
+ me.name, inpath);
+#endif
+ 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;
+
+#ifdef ZIP_LINKS
+ cptr->flags2 |= FLAGS2_CBURST;
+#endif
+
+ strcpy (cptr->sockhost, "0.0.0.0");
+
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_SERVER, sptr,
+ ":%s SERVER %s %d %s :%s", parv[0],
+ cptr->name, hop + 1, cptr->version, cptr->info);
+#endif
+ /*
+ ** 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;
+
+ sendto_one (acptr, ":%s SERVER %s 2 %s :%s",
+ me.name, cptr->name, cptr->version, 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;
+
+ sendto_one (cptr, ":%s SERVER %s %d %s :%s",
+ acptr->serv->up, acptr->name,
+ acptr->hopcount + 1, acptr->version, acptr->info);
+ }
+ }
+
+ for (acptr = &me; acptr; acptr = acptr->prev) {
+ 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
+ */
+ sendto_one (cptr, "%s %s %d %d %s %s %s %lu %s :%s",
+ (IsToken (cptr) ? TOK_SNICK : MSG_SNICK),
+ acptr->name, acptr->hopcount + 1, acptr->lastnick,
+ acptr->user->username, acptr->user->host,
+ acptr->user->server, acptr->user->servicestamp,
+ get_mode_str (acptr), acptr->info);
+ if (acptr->user->away)
+ sendto_one (cptr, ":%s %s :%s", acptr->name,
+ (IsToken (cptr) ? TOK_AWAY : MSG_AWAY),
+ acptr->user->away);
+ }
+ 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);
+ }
+ }
+
+ {
+ sendto_ops ("Synching with %s using link options:%s", cptr->name,
+ link_caps);
+
+ for (acptr = &me; acptr; acptr = acptr->prev) {
+ if (acptr->from == cptr)
+ continue;
+ if (IsPerson (acptr)) {
+ send_user_joins (cptr, acptr);
+ }
+ }
+
+ }
+
+ for (chptr = channel; chptr; chptr = chptr->nextch) {
+ send_channel_modes_sts (cptr, chptr);
+
+ if (chptr->topic_time)
+ sendto_one (cptr, ":%s %s %s %s %lu :%s",
+ me.name,
+ (IsToken (cptr) ? TOK_TOPIC : MSG_TOPIC),
+ chptr->chname, chptr->topic_nick,
+ chptr->topic_time, chptr->topic);
+ }
+
+ synchmode = 0;
+
+ /*
+ ** Pass on all services based q-lines
+ */
+
+ for (asqline = sqline; asqline; asqline = asqline->next) {
+ if (asqline->status != CONF_ILLEGAL) {
+ if (asqline->reason) {
+ sendto_one (cptr, ":%s SQLINE %s :%s", me.name,
+ asqline->sqline, asqline->reason);
+ }
+ else {
+ sendto_one (cptr, ":%s SQLINE %s", me.name, asqline->sqline);
+ }
+ }
+ }
+ /*
+ ** Pass on all services based jinxlines
+ */
+ for (ajinx = jinx; ajinx; ajinx = ajinx->next) {
+ if (ajinx->status != CONF_ILLEGAL) {
+ if (ajinx->reason) {
+ sendto_one (cptr, ":%s JINX %s :%s", me.name,
+ ajinx->userhost, ajinx->reason);
+ }
+ else {
+ sendto_one (cptr, ":%s JINX %s", me.name, ajinx->userhost);
+ }
+ }
+ }
+
+#ifdef ZIP_LINKS
+ if ((cptr->flags2 & FLAGS2_ZIP) && cptr->zip->out->total_in)
+ sendto_realops ("Connect burst to %s: %lu, compressed: %lu (%3.1f%%)",
+ get_client_name (cptr, TRUE),
+ cptr->zip->out->total_in, cptr->zip->out->total_out,
+ (100.0 * (float) cptr->zip->out->total_out) /
+ (float) cptr->zip->out->total_in);
+#endif
+ return 0;
+}
+
+/*
+ ** m_info
+ ** parv[0] = sender prefix
+ ** parv[1] = servername
+ */
+int m_info (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ char **text = infotext;
+
+/* Not needed re change to parse.c
+ if (check_registered(sptr))
+ return 0;
+ */
+
+#ifdef SEEUSERSTATS
+ if (!IsAnOper (sptr)) {
+ if (parc > 1 && strlen (parv[1]) > USERSTATMAX) {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- INFO [truncated] requested by %s (%s@%s)",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ else {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- INFO %s%srequested by %s (%s@%s)",
+ (parc > 1) ? parv[1] : "", (parc > 1) ? " " : "",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ }
+#endif
+
+/* Send users an error if they try to do /info <something>. -Studded */
+ if (parc > 1) {
+ sendto_one (sptr, ":%s NOTICE %s :The /info command "
+ "displays the file which lists the names of "
+ "the developers. If you wish to view info on a "
+ "specific nick or channel, use /nickserv info nick or "
+ "/chanserv info #Channel as appropriate.", me.name,
+ parv[0]);
+ return -1;
+ }
+/* Prevent remote /info. It's useless, and could be used to flood the
+ * server <> server connections. -Studded
+ if (hunt_server(cptr,sptr,":%s INFO :%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)))
+ sendto_one (cptr, rpl_str (rpl1), me.name, cptr->name,
+ acptr->name, acptr->user->username,
+ MaskHost (acptr), 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[];
+{
+ aClient *acptr;
+ char *s, **pav = parv, *user;
+ char *p = NULL, *def = "l";
+
+/* Not needed re change to parse.c
+ 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);
+ sendto_one (sptr, rpl_str (RPL_WATCHCLEAR), me.name, parv[0]);
+
+ 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)))
+ sendto_one (sptr, rpl_str (RPL_NOWON), me.name, parv[0],
+ acptr->name, acptr->user->username,
+ MaskHost (acptr), 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_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 (parc > 2) {
+ 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;
+ 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_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[19][3] = {
+ {CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
+ {CONF_NZCONNECT_SERVER, RPL_STATSCLINE, 'c'},
+ {CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
+ {CONF_CLIENT, RPL_STATSILINE, 'I'},
+ {CONF_KILL, RPL_STATSKLINE, 'K'},
+ {CONF_ZAP, RPL_STATSKLINE, 'Z'},
+ {CONF_QUARANTINED_NICK, RPL_STATSQLINE, 'Q'},
+ {CONF_OPERATOR, RPL_STATSOLINE, 'O'},
+ {CONF_HUB, RPL_STATSHLINE, 'H'},
+ {CONF_LOCOP, RPL_STATSOLINE, 'o'},
+ {CONF_SERVICE, RPL_STATSSLINE, 'S'},
+ {CONF_UWORLD, RPL_STATSULINE, 'U'},
+ {CONF_MISSING, RPL_STATSXLINE, 'X'},
+ {CONF_ZTIME, RPL_STATSFLINE, 'F'},
+ {CONF_DCCBLOCK, RPL_STATSBLINE, 'E'},
+ {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;
+
+ 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_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, "*");
+ /* 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';
+ }
+ else {
+ if (tmp->tmpconf == KLINE_PERM)
+ c = 'Z';
+ if (tmp->tmpconf == KLINE_TEMP)
+ c = 'z';
+ if (tmp->tmpconf == KLINE_AKILL)
+ c = 'S';
+ }
+ }
+ sendto_one (sptr, rpl_str (p[1]), me.name,
+ sptr->name, c, host,
+ buf, name, port, get_conf_class (tmp));
+ }
+ /* z-line times -taz */
+ else if (tmp->status & CONF_ZTIME)
+ sendto_one (sptr, rpl_str (p[1]), me.name, sptr->name, host);
+ /* 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 (!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;
+}
+
+static void report_jinx (aClient * sptr)
+{
+ aJinxItem *ajinx;
+ if (!IsAnOper (sptr))
+ return;
+ for (ajinx = jinx; ajinx; ajinx = ajinx->next) {
+ sendto_one (sptr, rpl_str (RPL_STATSJINX), me.name,
+ sptr->name, ajinx->userhost,
+ ajinx->reason ? ajinx->reason : "*");
+ }
+}
+
+
+/* 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 (!(char *) strrchr (pointer, '.'))
+ return NULL;
+ strcpy ((char *) strrchr (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';
+ int i;
+ int doall = 0, wilds = 0, showports = IsAnOper (sptr), remote = 0;
+ char *name;
+
+/* Not needed re change to parse.c
+ if (check_registered(sptr))
+ return 0;
+ */
+ if (hunt_server (cptr, sptr, ":%s STATS %s :%s", 2, parc, parv) !=
+ HUNTED_ISME)
+ return 0;
+
+#ifdef SEEUSERSTATS
+ if (!IsAnOper (sptr)) {
+ if (parc > 1 && strlen (parv[1]) > USERSTATMAX) {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- STATS [truncated] requested by %s (%s@%s)",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ else {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- STATS %s%srequested by %s (%s@%s)",
+ (parc > 1) ? parv[1] : "", (parc > 1) ? " " : "",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ }
+#endif
+
+ 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;
+
+/* Add better error checking for common user mistakes. Use a
+ * NOTICE instead of a numeric because more clients can see
+ * and display them properly. -Studded */
+
+ if (!(stat)) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "STATS");
+ return -1;
+ }
+ if ((parc == 2) && (parv[1][1])) {
+ sendto_one (sptr, ":%s NOTICE %s :You have requested a stat "
+ "(%s) that does not exist.", me.name, parv[0], parv[1]);
+ return -1;
+ }
+ 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.
+ */
+
+ if (!IsAnOper (sptr))
+ break;
+
+ 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)) ?
+ time (NULL) - 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,
+ time (NULL) - acptr->firsttime,
+#ifndef DEBUGMODE
+ (acptr->user && MyConnect (acptr)) ?
+ time (NULL) - acptr->user->last : 0);
+#else
+ pbuf);
+#endif
+ else if (!strchr (acptr->name, '.'))
+ 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,
+ time (NULL) - acptr->firsttime,
+#ifndef DEBUGMODE
+ (acptr->user && MyConnect (acptr)) ?
+ time (NULL) - acptr->user->last : 0);
+#else
+ pbuf);
+#endif
+ }
+ break;
+ case 'C':
+ case 'c':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_CONNECT_SERVER |
+ CONF_NOCONNECT_SERVER |
+ CONF_NZCONNECT_SERVER);
+ break;
+ case 'H':
+ case 'h':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_HUB);
+ break;
+ case 'I':
+ case 'i':
+ report_configured_links (sptr, CONF_CLIENT);
+ break;
+ case 'K':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_KILL | CONF_ZAP | CONF_KILLEXEMPT);
+ else
+ report_configured_links (sptr, CONF_KILL | CONF_ZAP);
+ break;
+ case 'k':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_KILL | CONF_KILLEXEMPT);
+ else
+ report_configured_links (sptr, CONF_KILL);
+
+ break;
+ case 'M':
+ case 'm':
+ if (IsOper (sptr)) {
+ 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
+ }
+ else {
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ }
+ break;
+ case 'o':
+ case 'O':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_OPS);
+ else
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case 'Q':
+ report_configured_links (sptr, CONF_QUARANTINE);
+ break;
+ case 'q':
+ report_sqlined_nicks (sptr);
+ break;
+ case 'R':
+ case 'r':
+#ifdef DEBUGMODE
+ send_usage (sptr, parv[0]);
+#endif
+ break;
+ case 'S':
+ case 's':
+ report_configured_links (sptr, CONF_SERVICE);
+ break;
+ case 'T':
+ case 't':
+ tstats (sptr, parv[0]);
+ break;
+ case 'U':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_UWORLD);
+ else
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case 'f':
+ case 'F':
+ report_configured_links (sptr, CONF_ZTIME);
+ break;
+ case 'u':
+ {
+ register time_t tmpnow;
+
+ tmpnow = time (NULL) - 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 'W':
+ case 'w':
+ if (IsOper (sptr))
+ calc_load (sptr, parv[0]);
+ else
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case 'X':
+ case 'x':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_MISSING);
+ else
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case 'Y':
+ case 'y':
+ report_classes (sptr);
+ break;
+ case 'Z':
+ report_configured_links (sptr, CONF_ZAP);
+ break;
+ case 'z':
+ count_memory (sptr, parv[0]);
+ break;
+ case 'J':
+ case 'j':
+ if (IsOper (sptr))
+ report_jinx (sptr);
+ else
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ case '?':
+ serv_info (sptr, parv[0]);
+ break;
+ case 'E':
+ case 'e':
+ if (IsOper (sptr))
+ report_configured_links (sptr, CONF_DCCBLOCK);
+ else
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ break;
+ default:
+ sendto_one (sptr, ":%s NOTICE %s :You have requested a stat "
+ "(%c) that does not exist.", me.name, parv[0], stat);
+ break;
+ }
+ sendto_one (sptr, rpl_str (RPL_ENDOFSTATS), me.name, parv[0], stat);
+ 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[];
+{
+ 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;
+}
+
+/*
+ ** m_help
+ ** parv[0] = sender prefix
+ */
+int m_help (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ int i;
+ if (MyClient (sptr)) {
+#ifdef SEEUSERSTATS
+ if (!IsAnOper (sptr)) {
+ if (parc > 1 && strlen (parv[1]) > USERSTATMAX) {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- HELP [truncated] requested by %s (%s@%s)",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ else {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- HELP %s%srequested by %s (%s@%s)",
+ (parc > 1) ? parv[1] : "",
+ (parc > 1) ? " " : "", sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ }
+#endif
+ sendto_one (sptr, ":%s NOTICE %s :\ 2Full command list\ 2:",
+ me.name, parv[0]);
+ sendto_one (sptr, ":%s NOTICE %s :command token", me.name, parv[0]);
+ sendto_one (sptr, ":%s NOTICE %s :=============", me.name, parv[0]);
+ for (i = 0; msgtab[i].cmd; i++)
+ sendto_one (sptr, ":%s NOTICE %s :%s %s",
+ me.name, parv[0], msgtab[i].cmd, msgtab[i].token);
+ sendto_one (sptr, ":%s NOTICE %s :=============", me.name, parv[0]);
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * 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;
+
+/* Not needed re change to parse.c
+ if (check_registered_user(sptr))
+ return 0;
+ */
+ 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);
+ sendto_one (sptr, rpl_str (RPL_STATSCONN),
+ me.name, parv[0], max_connection_count, max_client_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;
+}
+
+
+/***********************************************************************
+ * 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 ||
+ aconf->status == CONF_NZCONNECT_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;
+ }
+ /*
+ ** 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_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;
+/* char *pv[4]; Compiler says this is not used */
+
+ 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_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;
+/* char *pv[4]; Compiler says this is not used */
+
+ 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;
+/* char *pv[4]; Compiler says this is not used */
+
+ 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_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;
+/* char *pv[4]; Compiler says this is not used */
+
+ 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[];
+{
+
+ time_t t1;
+ int ticks;
+
+ ticks = time (&t1);
+
+ 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,
+ myctime (ticks));
+ 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 (!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_locfailops ("I'm killing %s because he is local!", parv[1]);
+ return exit_client (acptr, acptr, acptr, 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;
+
+ /* Make sure they stick to the local server if not registered.
+ * -Studded */
+ if ((!IsRegistered (cptr)) && (!BadPtr (parv[1]))) {
+ sendto_one (cptr, ":%s %d ADMIN :You have not registered",
+ me.name, ERR_NOTREGISTERED);
+ return -1;
+ }
+ /* This probably isn't needed anymore, but I don't
+ * understand it. -Studded 23 May 1998 */
+
+ /* 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;
+
+#ifdef SEEUSERSTATS
+ if (!IsAnOper (sptr)) {
+ if (parc > 1 && strlen (parv[1]) > USERSTATMAX) {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- ADMIN [truncated] requested by %s (%s@%s)",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ else {
+ sendto_umode (UMODE_OPER | UMODE_STATS,
+ "*** Notice -- ADMIN %s%srequested by %s (%s@%s)",
+ (parc > 1) ? parv[1] : "", (parc > 1) ? " " : "",
+ sptr->name,
+ (sptr->user) ? sptr->user->username : "",
+ (sptr->user) ? sptr->user->host : "");
+ }
+ }
+#endif
+
+ 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
+ **
+ */
+int m_rehash (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ if (!MyClient (sptr) || !OPCanRehash (sptr)) {
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ sendto_one (sptr, rpl_str (RPL_REHASHING), me.name, parv[0], configfile);
+ sendto_ops ("%s is rehashing Server config file", parv[0]);
+#ifdef USE_SYSLOG
+ syslog (LOG_INFO, "REHASH From %s\n", get_client_name (sptr, FALSE));
+#endif
+ return rehash (cptr, 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;
+
+ 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 ((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),
+ (parc > 1 ? parv[1] : "No reason"));
+#endif
+ sendto_ops ("Server is Restarting by request of %s", parv[0]);
+ server_reboot ((parv[1] ? parv[1] : "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[];
+{
+ int i;
+ aClient *acptr;
+ 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;
+
+ for (i = 0; i < MAXCONNECTIONS; i++)
+ link_s[i] = 0, link_u[i] = 0;
+
+ if (doall)
+ for (acptr = client; acptr; acptr = acptr->next)
+#ifdef SHOW_INVISIBLE_LUSERS
+
+ {
+ if (IsPerson (acptr) && (!IsHidden (acptr) || IsOper (sptr)))
+ link_u[acptr->from->fd]++;
+#else
+ {
+ if (IsPerson (acptr) &&
+ ((!IsHidden (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 = time (NULL);
+ 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, name,
+ now - acptr->lasttime);
+ else
+ sendto_one (sptr, rpl_str (RPL_TRACEUSER),
+ me.name, parv[0], class, name,
+ 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->host, 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
+ */
+int m_motd (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ int fd, nr;
+ char line[80];
+ char *tmp;
+ struct stat sb;
+ struct tm *tm;
+
+
+ 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)
+ */
+ fd = open (MOTD, O_RDONLY);
+ if (fd == -1) {
+ sendto_one (sptr, err_str (ERR_NOMOTD), 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);
+ (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_opermotd (added by GZ 12/04/99)
+ ** 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];
+ char *tmp;
+ struct stat sb;
+
+ if (!MyClient (sptr) || !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 (OMOTD, O_RDONLY);
+ if (fd == -1) {
+ return 0;
+ }
+ (void) fstat (fd, &sb);
+ sendto_one (sptr, rpl_str (RPL_OMOTDSTART), 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_OMOTD,
+ 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_OMOTD), me.name, parv[0], line);
+ }
+ (void) dgets (-1, NULL, 0); /* make sure buffer is at empty pos */
+ sendto_one (sptr, rpl_str (RPL_ENDOFOMOTD), me.name, parv[0]);
+ (void) close (fd);
+ 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[];
+{
+ aClient *acptr;
+ 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->host, 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[];
+{
+ aClient *acptr;
+ 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 *militime (char *sec, char *usec)
+{
+ struct timeval tv;
+ static char timebuf[18];
+
+ gettimeofday (&tv, NULL);
+
+ if (sec && usec)
+#if defined(__sun__) || defined(__bsdi__)
+ sprintf (timebuf, "%ld",
+ (tv.tv_sec - atoi (sec)) * 1000 + (tv.tv_usec -
+ atoi (usec)) / 1000);
+#else
+ sprintf (timebuf, "%ld",
+ (tv.tv_sec - atoi (sec)) * 1000 + (tv.tv_usec -
+ atoi (usec)) / 1000);
+#endif
+ else
+#if defined(__sun__) || defined(__bsdi__)
+ sprintf (timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
+#else
+ sprintf (timebuf, "%ld %ld", tv.tv_sec, tv.tv_usec);
+#endif
+ return timebuf;
+}
+
+/*
+ * m_rping -- by Run
+ *
+ * parv[0] = sender prefix
+ * parv[1] = pinged server
+ * parv[2] = from person: start server ; from server: sender
+ * parv[3] = start time in s ;from person: Optional remark
+ * parv[4] = start time in us
+ */
+int m_rping (cptr, sptr, parc, parv)
+ aClient *cptr, *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_server_wildcard (parv[2])))
+ /* Should be replacd with a WILDCARD search routine for servers! */
+ /* Done. -GZ */
+
+ {
+ 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_server_wildcard (parv[1])) || !IsServer (acptr))
+ /* Should be replaced with a WILDCARD search routine for servers! */
+ /* Done. -GZ */
+ {
+ 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 (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+
+{
+ aClient *acptr;
+
+ if (!IsServer (sptr))
+ return 0;
+
+ if (parc < 5) {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS), me.name, parv[0],
+ "RPING");
+ return 0;
+ }
+ if (!(acptr = 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;
+}
+
+/*
+ * dump_map (used by m_map)
+ */
+void
+dump_map (aClient * cptr, aClient * server, char *mask, int prompt_length,
+ int length)
+{
+ static char prompt[64];
+ char *p = &prompt[prompt_length];
+ 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) {
+ 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] = '-';
+}
+
+/*
+ ** m_map
+ **
+ ** parv[0] = sender prefix
+ ** parv[1] = server mask
+ * */
+int m_map (aClient * cptr, aClient * 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, parv[1], 0, longest);
+ sendto_one (sptr, rpl_str (RPL_MAPEND), me.name, parv[0]);
+
+ return 0;
+}
+
+int find_services (void)
+{
+
+ aClient *cptr;
+
+ if ((cptr = find_server (SERVICES_NAME, (aClient *) NULL)))
+ return 1;
+
+ return 0;
+
+}
+
+/*
+ * m_snick added by GZ November '99
+ *
+ * parv[0] = source
+ * parv[1] = nick
+ * parv[2] = hopcount
+ * parv[3] = lastnick
+ * parv[4] = username
+ * parv[5] = hostname
+ * parv[6] = server
+ * parv[7] = services stamp
+ * parv[8] = modes
+ * parv[9] = real name
+ */
+
+int m_snick (aClient * cptr, aClient * sptr, int parc, char *parv[])
+{
+ aClient *acptr;
+
+ if (!IsServer (sptr) || parc < 9)
+ return 1;
+
+ /* New KILL in case something messes up */
+
+ if (do_snick (cptr, sptr, parc, parv)) {
+ sendto_one (cptr, ":%s KILL %s :%s (Synchronizing error. (SNICK))",
+ me.name, parv[1], me.name);
+ return 1;
+ }
+
+ if ((acptr = find_client (parv[1], NULL))) {
+
+ sendto_SNICK_butone (sptr, "SNICK %s %d %d %s %s %s %lu %s :%s",
+ acptr->name, acptr->hopcount + 1,
+ acptr->lastnick, acptr->user->username,
+ acptr->user->host, acptr->user->server,
+ acptr->user->servicestamp, parv[8], acptr->info);
+ return 0;
+ }
+
+ sendto_serv_butone (&me, ":%s GLOBOPS :ERROR with SNICK for %s", me.name,
+ parv[1]);
+
+ return 1;
+}
+
+/*
+ * do_snick - added November 99 by GZ
+ *
+ * This will make a client-structure out of the parameters
+ * that SNICK gives us. It's basicly a stripped down merge
+ * of m_nick, m_user and register_user.
+ *
+ * parv[0] = source
+ * parv[1] = nick
+ * parv[2] = hopcount
+ * parv[3] = lastnick
+ * parv[4] = username
+ * parv[5] = hostname
+ * parv[6] = server
+ * parv[7] = services stamp
+ * parv[8] = modes
+ * parv[9] = real name
+ *
+ */
+
+int do_snick (aClient * cptr, aClient * sptr, int parc, char *parv[])
+{
+
+ aClient *acptr, *serv = NULL;
+ anUser *user;
+ aConfItem *aconf;
+ aSqlineItem *asqline;
+ int keep, sameguy;
+ int ourts, theirts;
+
+
+ if (!(serv = find_server (parv[6], NULL)) || serv->from != cptr->from) {
+ return 1;
+ }
+
+ if ((acptr = find_client (parv[1], NULL))) {
+ keep = sameguy = 0;
+ ourts = acptr->lastnick;
+ theirts = atoi (parv[3]);
+ if (ourts < theirts)
+ keep = 1;
+ sameguy = !(strcmp (acptr->user->host, parv[5]));
+
+ if (sameguy)
+ keep = !keep;
+
+ if (!keep) {
+ if (sameguy) {
+ sendto_serv_butone (cptr,
+ ":%s KILL %s :%s (Nick collision (old nick killed))",
+ me.name, acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ (void) exit_client (NULL, acptr, &me,
+ "Nick collision (old nick killed)");
+ }
+ else {
+ sendto_serv_butone (cptr,
+ ":%s KILL %s :%s (Nick collision (new nick killed))",
+ me.name, acptr->name, me.name);
+ acptr->flags |= FLAGS_KILLED;
+ (void) exit_client (NULL, acptr, &me,
+ "Nick collision (new nick killed)");
+ }
+ }
+ }
+
+ sptr = make_client (cptr, serv);
+ add_client_to_list (sptr);
+
+ strncpyzt (sptr->name, parv[1], sizeof (sptr->name));
+
+ if (parc > 2)
+ sptr->hopcount = atoi (parv[2]);
+ if (parc > 3)
+ sptr->lastnick = atoi (parv[3]);
+ else
+ sptr->lastnick = time (NULL);
+
+ (void) add_to_client_hash_table (parv[1], sptr);
+ user = make_user (sptr);
+
+ strncpyzt (user->server, parv[6], sizeof (user->server));
+ strncpyzt (user->host, parv[5], sizeof (user->host));
+ user->servicestamp = atol (parv[7]);
+ strncpyzt (sptr->info, parv[9], sizeof (sptr->info));
+ strncpyzt (user->username, parv[4], USERLEN + 1);
+
+ SetClient (sptr);
+
+ if ((aconf = find_conf_name (parv[1], CONF_QUARANTINED_NICK))
+ || (asqline = find_sqline_match (parv[1]))) {
+// fixme
+// char *qrsn = (aconf) ? aconf->passwd : asqline->reason;
+ char *qtyp = (aconf) ? "Q:Lined" : "SQLined";
+
+ if (!find_conf_host (cptr->confs, sptr->user->server, CONF_UWORLD))
+ sendto_realops ("%s nick %s from %s@%s on %s.", qtyp, parv[1],
+ sptr->user->username, sptr->user->host,
+ sptr->user->server);
+ }
+
+ /* Check for services */
+
+ 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;
+
+ /* Change modes for the user here */
+
+ mode_snick (sptr, parv[8]);
+
+ /* If user is masked - then update mask accordingly here */
+
+ calc_mask(sptr) ;
+
+ /* Do a WATCH notify - user should be masked by now, so it's safe */
+
+ hash_check_notify (sptr, RPL_LOGON);
+
+ return 0;
+}
+
+/*
+ * mode_snick - sets modes given by SNICK
+ * added by GZ Nov '99
+ */
+
+int mode_snick (aClient * acptr, char *modes)
+{
+ char *p;
+ int what;
+
+ p = modes;
+
+ what = MODE_ADD;
+
+ for (p = modes; *p; p++) {
+ switch (*p) {
+ case '+':
+ what = MODE_ADD;
+ break;
+ case '-':
+ what = MODE_DEL;
+ break;
+ case 'n':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_SROOT;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_SROOT;
+ }
+ break;
+ case 'o':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_OPER;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_OPER;
+ }
+ break;
+ case 'i':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_INVISIBLE;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_INVISIBLE;
+ }
+ break;
+ case 'g':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_FAILOP;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_FAILOP;
+ }
+ break;
+ case 'k':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_KILLS;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_KILLS;
+ }
+ break;
+ case 'a':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_SADMIN;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_SADMIN;
+ }
+ break;
+ case 'N':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_NETADMIN;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_NETADMIN;
+ }
+ break;
+ case 'A':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_ADMIN;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_ADMIN;
+ }
+ break;
+ case 'c':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_CLIENT;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_CLIENT;
+ }
+ break;
+ break;
+ case 'x':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_HIDE;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_HIDE;
+ }
+ break;
+ case 'y':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_WHOIS;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_WHOIS;
+ }
+ break;
+ case 'I':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_IDENTIFY;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_IDENTIFY;
+ }
+ break;
+ }
+ }
+ return 0;
+
+}
--- /dev/null
+ /************************************************************************
+ * 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.
+ */
+
+#include "config.h" /* Get the value of THROTTLE -Studded */
+#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 <utmp.h>
+#include <fcntl.h>
+#include "h.h"
+
+void send_umode_out PROTO ((aClient *, aClient *, int));
+void send_svsmode_out PROTO ((aClient *, aClient *, aClient *, int));
+void send_umode PROTO ((aClient *, aClient *, int, int, char *));
+static int is_silenced PROTO ((aClient *, aClient *));
+
+static char buf[BUFSIZE], buf2[BUFSIZE];
+
+#if defined(THROTTLE)
+int ZLineExists (char *);
+#endif
+
+#ifdef NOSPOOF
+/* From md5.c */
+void MD5Init (u_int32_t[]);
+void MD5Transform (u_int32_t[], u_int32_t[]);
+#endif
+
+/*
+ ** 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.
+ */
+
+/*
+ ** 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)
+ aClient *next; /* First client to check */
+ char *ch; /* search string (may include wilds) */
+{
+ 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)
+{
+ u_char *p;
+#ifdef __alpha
+ u_long tmp = ((u_long) target & 0xffff00) >> 8;
+#else
+ u_int tmp = ((u_int) 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;
+ return 0;
+}
+
+#ifdef THROTTLE
+
+/*
+ * check_clones
+ *
+ * This function counts the number of clients with the same IP number
+ * as cptr that connected less than CHECK_CLONE_PERIOD seconds ago.
+ * return value
+ * -1: reject connections
+ * 0: permit connections
+ *
+ * Based on the original (ircu) from Seks, Record and Run
+ * fixed up by nikb <nikb@dal.net>
+ */
+
+struct aThrottle
+{ /* this is a throttle record */
+ struct in_addr ip;
+ time_t last;
+ struct aThrottle *next;
+ char *connected;
+ short count;
+};
+
+#define THROTTLE_HITLIMIT -1
+#define THROTTLE_SENTWARN -2
+
+/* this is our hash table -- statically initialized to 0 */
+static struct aThrottle *throttles[256];
+
+static void remove_clone_check (aClient * cptr)
+{
+ register unsigned char *p = (unsigned char *) &cptr->ip.s_addr;
+ register struct aThrottle *ptr =
+ throttles[(p[0] + p[1] + p[2] + p[3]) & 0xff];
+
+ if (cptr->ip.s_addr == 0)
+ return;
+
+ while (ptr && (cptr->ip.s_addr != ptr->ip.s_addr))
+ ptr = ptr->next;
+
+ if (ptr && (ptr->count > 1))
+ ptr->count--;
+}
+
+int check_clones (aClient * cptr, const char *remote)
+{
+ struct aThrottle **tscn, *tptr;
+ unsigned char *p = (unsigned char *) &cptr->ip.s_addr;
+ unsigned char hval = (unsigned char) (p[0] ^ p[1] ^ p[2] ^ p[3]) & 0xFF;
+ tscn = &throttles[hval];
+
+ if (cptr->ip.s_addr == 0)
+ return 0;
+
+ while (*tscn && (cptr->ip.s_addr != (*tscn)->ip.s_addr)) {
+ if ((*tscn)->last + CHECK_CLONE_PERIOD < now) {
+ tptr = *tscn;
+ *tscn = tptr->next;
+ free (tptr->connected);
+ free (tptr);
+ }
+ else
+ tscn = &(*tscn)->next;
+ }
+
+ if ((tptr = *tscn)) { /* There is a record for this host */
+ if (!(tptr->last + CHECK_CLONE_PERIOD < now)) { /* not expired */
+ if (remote && !tptr->connected
+ && (tptr->connected =
+ (char *) MyMalloc (strlen (remote) + 1)))
+ strcpy (tptr->connected, remote);
+
+ tptr->last = now;
+
+ if (tptr->count >= 0) {
+ if (++tptr->count == CHECK_CLONE_LIMIT)
+ tptr->count = THROTTLE_HITLIMIT;
+
+ return 0;
+ }
+ if (tptr->count == THROTTLE_HITLIMIT)
+ tptr->count = THROTTLE_SENTWARN;
+
+ return -1;
+ }
+ else { /* expired */
+ tptr->last = now;
+ tptr->count = 1;
+
+ if (remote && !tptr->connected
+ && (tptr->connected =
+ (char *) MyMalloc (strlen (remote) + 1)))
+ strcpy (tptr->connected, remote);
+
+ return 0;
+ }
+ }
+ else { /* no record for the host, make one */
+ tptr = (struct aThrottle *) MyMalloc (sizeof (struct aThrottle));
+ tptr->ip = cptr->ip;
+ tptr->next = throttles[hval];
+ tptr->last = now;
+ tptr->count = 1;
+ tptr->connected = NULL;
+
+ if (remote && !tptr->connected
+ && (tptr->connected = (char *) MyMalloc (strlen (remote) + 1)))
+ strcpy (tptr->connected, remote);
+
+ throttles[hval] = tptr;
+ return 0;
+ }
+
+ /* we should never get here, but just in case */
+ return 0;
+}
+#endif /* THROTTLE */
+
+/*
+ ** '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;
+{
+ 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;
+}
+
+/*
+ ** 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...
+ */
+
+static int register_user (cptr, sptr, nick, username)
+ aClient *cptr;
+ aClient *sptr;
+ char *nick, *username;
+{
+ aConfItem *aconf;
+ char *parv[3], *tmpstr, *encr;
+ char stripuser[USERLEN + 1], *u1 = stripuser, *u2, olduser[USERLEN + 1],
+ userbad[USERLEN * 2 + 1], *ubad = userbad;
+ short oldstatus = sptr->status;
+ anUser *user = sptr->user;
+ aClient *nsptr;
+ int i;
+#ifdef CRYPT_ILINE_PASSWORD
+ char salt[3];
+ extern char *crypt ();
+#endif /* CRYPT_ILINE_PASSWORD */
+
+ user->last = time (NULL);
+ parv[0] = sptr->name;
+ parv[1] = parv[2] = NULL;
+
+ if (MyConnect (sptr)) {
+ /* Set HTC here */
+ sptr->lasthtc = time (NULL);
+ sptr->htccount = 0;
+ sptr->htcignore = 0;
+#ifdef THROTTLE
+ if (check_clones (sptr, get_client_host (sptr)) == -1) {
+ int ret = exit_client (cptr, sptr, sptr,
+ "Your host/ip has been throttled");
+ static char hostip[128];
+ strcpy (hostip, inetntoa ((char *) &sptr->ip));
+ if (!ZLineExists (hostip)) {
+ add_temp_conf (CONF_ZAP, hostip,
+ "Too_many_connection_attempts_from_your_IP_address",
+ NULL, 0, 0, KLINE_TEMP);
+ AddEvent (RemoveZLine, hostip, CHECK_CLONE_DELAY);
+ }
+ return ret;
+ }
+#endif /* THROTTLE */
+
+ 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++;
+#ifdef THROTTLE
+ if (i == -3)
+ remove_clone_check (sptr);
+#endif
+ return exit_client (cptr, sptr, &me, i == -3 ?
+ "This server is full. Please try "
+ random_serv :
+ "You are not authorized to connect to this server");
+ }
+ if (IsUnixSocket (sptr))
+ strncpyzt (user->host, me.sockhost, sizeof (user->host));
+ 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->host || isdigit (*(tmpstr - 1)))
+ strncpyzt (sptr->sockhost, (char *) inetntoa ((char *) &sptr->ip), sizeof (sptr->sockhost)); /* Fix the sockhost for debug jic */
+ strncpyzt (user->host, sptr->sockhost, sizeof (sptr->sockhost));
+ }
+ else /* Failsafe point, don't let the user define their
+ own hostname via the USER command --Cabal95 */
+ strncpyzt (user->host, sptr->sockhost, HOSTLEN + 1);
+
+ 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
+ */
+ strncpyzt (user->username, username, USERLEN + 1);
+ /*
+ * 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
+ */
+ for (u2 = user->username; *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)) {
+ if (stripuser[0] == '\0') {
+ strncpy (stripuser, cptr->name, 8);
+ stripuser[8] = '\0';
+ }
+ strcpy (olduser, user->username);
+ strncpy (user->username, stripuser, USERLEN);
+ user->username[USERLEN] = '\0';
+ }
+ else
+ u1 = NULL;
+
+ if (!BadPtr (aconf->passwd)) {
+#ifdef CRYPT_ILINE_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 (sptr->passwd && aconf->passwd && aconf->passwd[0] &&
+ aconf->passwd[1]) {
+ salt[0] = aconf->passwd[0];
+ salt[1] = aconf->passwd[1];
+ salt[2] = '\0';
+ encr = crypt (sptr->passwd, salt);
+ }
+ else
+ encr = "";
+#else
+ encr = sptr->passwd;
+#endif /* CRYPT_ILINE_PASSWORD */
+
+ if (!StrEq (encr, aconf->passwd)) {
+ ircstp->is_ref++;
+ sendto_one (sptr, err_str (ERR_PASSWDMISMATCH), me.name,
+ parv[0]);
+#ifdef THROTTLE
+ remove_clone_check (sptr);
+#endif
+ 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++;
+ return exit_client (cptr, sptr, &me, "K-lined");
+ }
+
+#ifdef DISALLOW_MIXED_CASE
+/* check for mixed case usernames, meaning probably hacked Jon2 3-94
+ */
+#ifdef IGNORE_CASE_FIRST_CHAR
+ tmpstr = &username[1];
+#else
+ tmpstr = 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);
+
+ calc_mask(sptr) ;
+
+ if (MyConnect (sptr)) {
+ sendto_one (sptr, rpl_str (RPL_WELCOME), me.name, nick, nick,
+ user->username, user->host);
+ /* This is a duplicate of the NOTICE but see below... */
+ sendto_one (sptr, rpl_str (RPL_YOURHOST), me.name, nick,
+ me.name, version);
+ sendto_one (sptr, rpl_str (RPL_CREATED), me.name, nick, creation);
+ sendto_one (sptr, rpl_str (RPL_MYINFO), me.name, parv[0],
+ me.name, version);
+ sendto_one (sptr, rpl_str (RPL_PROTOCTL), me.name, parv[0],
+ PROTOCTL_SUPPORTED);
+ (void) m_lusers (sptr, sptr, 1, parv);
+ update_load ();
+ (void) m_motd (sptr, sptr, 1, parv);
+ sendto_one (sptr, rpl_str (RPL_POLICY), me.name, parv[0], parv[0]);
+ /*
+ * 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);
+ nextping = time (NULL);
+ sendto_umode (UMODE_OPER | UMODE_CLIENT,
+ "*** Notice -- Client connecting on port %d: %s (%s@%s) [%s] [%s/%s]",
+ sptr->acpt->port, nick, user->username, user->host, inetntoa ((char *) &sptr->ip), sptr->sup_host, sptr->sup_server);
+ }
+ 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;
+ }
+
+ sptr->umodes |= UMODE_HIDE;
+ calc_mask(sptr) ;
+
+ hash_check_notify (sptr, RPL_LOGON); /* Uglier hack */
+
+ if (!MyClient (sptr)) {
+ calc_mask(sptr) ;
+ sptr->umodes &= ~UMODE_HIDE;
+
+ }
+
+ sendto_serv_butone (cptr, "NICK %s %d %d %s %s %s %lu :%s", nick,
+ sptr->hopcount + 1, sptr->lastnick, user->username,
+ user->host, user->server, sptr->user->servicestamp,
+ 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 (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);
+ }
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_NICK, sptr,
+ "NICK %s %d %d %s %s %s %lu :%s", nick,
+ sptr->hopcount, sptr->lastnick, user->username,
+ user->host, user->server, sptr->user->servicestamp,
+ sptr->info);
+ check_services_butone (SERVICE_WANT_USER, sptr, ":%s USER %s %s %s :%s",
+ nick, user->username, user->host, user->server,
+ sptr->info);
+#endif
+ 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;
+ char nick[NICKLEN + 2];
+
+ if (!IsULine (cptr, sptr) || parc < 4 || (strlen (parv[2]) > NICKLEN))
+ return -1; /* This looks like an error anyway -Studded */
+
+ /* Check for silly nicks here -GZ */
+
+ strncpyzt (nick, parv[2], NICKLEN + 1);
+ if (do_nick_name (nick) == 0)
+ sendto_one (sptr, err_str (ERR_ERRONEUSNICKNAME),
+ me.name, parv[0], parv[1], "Illegal characters");
+
+ 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");
+ acptr->umodes &= ~UMODE_IDENTIFY;
+ 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
+ ** parv[7] = servicestamp
+ ** parv[8] = info
+ */
+int m_nick (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aConfItem *aconf;
+ aSqlineItem *asqline;
+ aClient *acptr, *serv = NULL;
+ char nick[NICKLEN + 2], *s;
+ Link *lp;
+ time_t lastnick = (time_t) 0;
+ int differ = 1;
+
+#ifdef NOSPOOF
+ u_int32_t md5data[16];
+ static u_int32_t md5hash[4];
+#endif
+
+ /*
+ * 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';
+
+ if (MyConnect (sptr) && IsJinxed (sptr))
+ return 0; /* Jinxed Users Get Nothing */
+
+ 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_ops ("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 Services nicknames, i.e NickServ
+ ** So you cannot change now to thses nicknames even
+ ** if you want too :-)
+ */
+ if (!IsServer (cptr) && (!strcmp (nick, NickServ) ||
+ !strcmp (nick, ChanServ) ||
+ !strcmp (nick, OperServ) ||
+ !strcmp (nick, WebServ) ||
+ !strcmp (nick, MemoServ))) {
+ sendto_one (sptr, err_str (ERR_ERRONEUSNICKNAME), me.name,
+ BadPtr (parv[0]) ? "*" : parv[0], nick,
+ "Reserved Due To Services Abuse.");
+ return 0; /* nick 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
+ ** Quick fix to eliminate the duplicate warning if a local
+ ** user tries to get a Q:lined nick... -nikb@dal.net
+ */
+ if ((aconf = find_conf_name (nick, CONF_QUARANTINED_NICK))
+ || (asqline = find_sqline_match (nick))) {
+ char *qrsn = (aconf) ? aconf->passwd : asqline->reason;
+ char *qtyp = (aconf) ? "Q:Lined" : "SQLined";
+
+ if (!IsServer (cptr) && !IsOper (cptr)) { /* local client and not operator */
+ sendto_one (sptr, err_str (ERR_ERRONEUSNICKNAME), me.name,
+ BadPtr (parv[0]) ? "*" : parv[0], nick,
+ BadPtr (qrsn) ? "reason unspecified" : qrsn);
+ sendto_realops ("Forbidding %s nick %s from %s.", qtyp, nick,
+ get_client_name (cptr, FALSE));
+ return 0; /* NICK command ignored */
+ }
+ /* either an oper, or a server sent NICK -- warn about it but
+ don't ignore it, unless it is from an U lined server. */
+ if (!IsULine (cptr, sptr))
+ sendto_realops ("%s nick %s from %s on %s.", qtyp, nick,
+ (*sptr->name != 0
+ && !IsServer (sptr)) ? sptr->
+ name : "<unregistered>",
+ (sptr->user ==
+ NULL) ? ((IsServer (sptr)) ? parv[6] : me.
+ name) : sptr->user->server);
+ }
+ /*
+ ** 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_ops ("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_ops ("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->host, 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);
+ }
+ 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->host, sptr->user->host));
+ sendto_locfailops
+ ("Nick change collision from %s to %s (%s %d <- %s %d)",
+ sptr->name, acptr->name, acptr->from->name, acptr->lastnick,
+ get_client_name (cptr, FALSE), lastnick);
+ }
+ /*
+ ** Now remove (kill) the nick on our side if it is the youngest.
+ ** If no timestamp was received, we ignore the incoming nick
+ ** (and expect a KILL for our legit nick soon ):
+ ** When the timestamps are equal we kill both nicks. --Run
+ ** acptr->from != cptr should *always* be true (?).
+ */
+ if (acptr->from != cptr) {
+ if (!lastnick || (differ && lastnick >= acptr->lastnick) ||
+ (!differ && lastnick <= acptr->lastnick)) {
+ if (!IsServer (sptr)) {
+ ircstp->is_kill++;
+ sendto_serv_butone (cptr, /* Kill old from outgoing servers */
+ ":%s KILL %s :%s (%s <- %s)",
+ me.name, sptr->name, me.name,
+ acptr->from->name, get_client_name (cptr,
+ FALSE));
+ sptr->flags |= FLAGS_KILLED;
+ (void) exit_client (NULL, sptr, &me,
+ "Nick collision (you're a ghost)");
+ }
+ if (lastnick && lastnick != acptr->lastnick)
+ return 0; /* Ignore the NICK */
+ }
+ sendto_one (acptr, err_str (ERR_NICKCOLLISION),
+ me.name, acptr->name, nick);
+ }
+ ircstp->is_kill++;
+ sendto_serv_butone (cptr, /* Kill our old from outgoing servers */
+ ":%s KILL %s :%s (%s <- %s)",
+ me.name, acptr->name, me.name,
+ acptr->from->name, get_client_name (cptr, FALSE));
+ acptr->flags |= FLAGS_KILLED;
+ (void) exit_client (NULL, acptr, &me,
+ "Nick collision (older nick overruled)");
+
+ if (lastnick == acptr->lastnick)
+ return 0;
+
+ 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 = time (NULL);
+ }
+ 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, lp->value.chptr) &&
+ !is_banexception (cptr, 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) ?
+ time (NULL) : atoi (parv[2]));
+ sptr->umodes &= ~UMODE_IDENTIFY;
+ 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] = time (NULL);
+ 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, ":%s NOTICE %s :*** If you are having problems"
+ " connecting due to ping timeouts, please"
+ " type /notice %X nospoof now.",
+ me.name, 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 = time (NULL); /* Always local client */
+ if (register_user (cptr, sptr, nick,
+ sptr->user->username) == 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;
+ return m_user (cptr, sptr, parc - 3, &parv[3]);
+ }
+ 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;
+{
+ aClient *acptr;
+ char *s;
+ aChannel *chptr;
+ char *nick, *server, *p, *cmd;
+ int cansend = 0;
+
+/*
+ * Reasons why someone can't send to a channel
+ */
+ static char *err_cantsend[] = {
+ "This channel is moderated, you need voice (+v)",
+ "This channel does not allow external messages",
+ "This channel does not allow mIRC/ANSI colors",
+ "You have been banned from this channel",
+ NULL
+ };
+
+/* This is related to the test for unregistered users in
+ * parse.c. Unless NOSPOOF is defined, there is no need to
+ * test this here since m_notice and m_message are disallowed.
+ * -Studded
+ */
+
+#ifdef NOSPOOF
+ if (notice) {
+ if (check_registered (sptr))
+ return 0;
+ }
+ else if (check_registered_user (sptr))
+ return 0;
+#endif
+
+ 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;
+ }
+ if (MyConnect (sptr) && IsJinxed (sptr))
+ return 0;
+
+ if (MyConnect (sptr))
+ parv[1] = canonize (parv[1]);
+ for (p = NULL, nick = strtoken (&p, parv[1], ","); nick;
+ nick = strtoken (&p, NULL, ",")) {
+
+ /*
+ ** nickname addressed?
+ */
+ if ((acptr = find_person (nick, NULL))) {
+ if (MyClient (sptr)
+ && check_for_target_limit (sptr, acptr, acptr->name))
+ continue;
+
+ if (AcceptsRegisteredOnly(acptr)) {
+ if (!IsIdentified(sptr)) {
+ sendto_one (sptr, err_str (ERR_NEEDREGGEDNICKTOMSG),
+ me.name, parv[0], acptr->name);
+ continue;
+ }
+ }
+
+ if (!is_silenced (sptr, acptr)) {
+ if (MyClient (sptr) && !notice && parv[2][0] == '\1')
+ if ((strlen (parv[2]) > 5)
+ && strncmp (&parv[2][1], "DCC ", 4) == 0) {
+ if (!IsIdentified(sptr) || !IsIdentified(acptr)) {
+ sendto_one (sptr, rpl_str (ERR_NEEDIDTODCC), me.name, sptr->name, acptr->name);
+ continue;
+ }
+ if ((strlen (parv[2]) > 9)
+ && strncmp (&parv[2][1], "DCC SEND", 8) == 0) {
+ char *fn;
+ char filename[256];
+ int pos = 0;
+ fn = &parv[2][10];
+ while (fn[pos] != ' ') {
+ filename[pos] = fn[pos];
+ pos++;
+ }
+ filename[pos++] = '\0';
+ if (find_dccblock (fn)) {
+ sendto_one (sptr,
+ ":%s NOTICE %s :DCC Transfer of \2%s\2 is not permitted, due to many viruses going around we have disabled the ability to send certain files for your protection. Join #help for more information.",
+ me.name, sptr->name, filename);
+ sendto_one (acptr,
+ ":%s NOTICE %s :[\2WARNING\2] The DCC send file you were about to receive (\2%s\2) has been blocked. Due to viruses, we have disabled the sending of certain files. For more information, Please join #help",
+ me.name, acptr->name, filename);
+ continue;
+ }
+ }
+ }
+ 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 || IsULine (cptr, sptr))
+ sendto_channelops_butone (cptr, sptr, chptr,
+ ":%s %s %s :%s", parv[0],
+ cmd, nick, 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 || IsULine (cptr, sptr))
+ sendto_channelvoice_butone (cptr, sptr, chptr,
+ ":%s %s %s :%s", parv[0],
+ cmd, nick, 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 (MyClient (sptr)
+ && check_for_target_limit (sptr, chptr, chptr->chname))
+ continue;
+ sendto_channel_butone (cptr, sptr, chptr,
+ ":%s %s %s :%s", parv[0], cmd, nick,
+ parv[2]);
+ }
+ 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;
+}
+static int user_modes[] = { UMODE_OPER, 'o',
+ UMODE_LOCOP, 'O',
+ UMODE_INVISIBLE, 'i',
+ UMODE_FAILOP, 'g',
+ UMODE_SERVNOTICE, 's',
+ UMODE_KILLS, 'k',
+ UMODE_SADMIN, 'a',
+ UMODE_SROOT, 'n',
+ UMODE_NETADMIN, 'N',
+ UMODE_ADMIN, 'A',
+ UMODE_CLIENT, 'c',
+ UMODE_FLOOD, 'f',
+ UMODE_WEBTV, 'w',
+ UMODE_HIDE, 'x',
+ UMODE_WHOIS, 'y',
+#ifdef SEEUSERSTATS
+ UMODE_STATS, 't',
+#endif
+ UMODE_IDENTIFY, 'I',
+ UMODE_REGMSGONLY, 'R',
+ 0, 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.starchat.net' so nobody can snoop /cs commands :) -taz
+ */
+
+int m_chanserv (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+ if (IsJinxed (sptr))
+ return 0; /* Jinxed Users Get Nothing */
+
+ 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);
+
+ return 0;
+}
+
+int m_memoserv (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+
+ if (IsJinxed (sptr))
+ return 0; /* Jinxed Users Get Nothing */
+
+ 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);
+
+ return 0;
+}
+
+int m_nickserv (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+
+ if (IsJinxed (sptr))
+ return 0; /* Jinxed Users Get Nothing */
+
+ 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);
+
+ return 0;
+
+}
+
+
+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);
+
+ return 0;
+}
+
+
+
+/*
+ * Automatic NickServ direction for the identify command
+ * -taz
+ */
+int m_identify (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ aClient *acptr;
+
+ if (parc < 2 || *parv[1] == '\0') {
+ sendto_one (sptr, err_str (ERR_NOTEXTTOSEND), me.name, parv[0]);
+ return -1;
+ }
+ if (*parv[1]) {
+ 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);
+ }
+ return 0;
+}
+
+/*
+ ** 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 ((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);
+ return 0;
+ }
+#ifdef NOSPOOF
+ temp:
+#endif
+ return m_message (cptr, sptr, parc, parv, 1);
+ return 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';
+ if (IsAnOper (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 (IsULine (cptr, sptr) || IsAnOper (sptr) || acptr == sptr) {
+ sendto_one (sptr, rpl_str (RPL_WHOREPLY), me.name, sptr->name,
+ (repchan) ? (repchan->chname) : "*",
+ acptr->user->username, acptr->user->host,
+ acptr->user->server, acptr->name, status, acptr->hopcount,
+ acptr->info);
+ }
+ else {
+ sendto_one (sptr, rpl_str (RPL_WHOREPLY), me.name, sptr->name,
+ (repchan) ? (repchan->chname) : "*",
+ acptr->user->username, MaskHost (acptr),
+ 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[];
+{
+ aClient *acptr;
+ char *mask = parc > 1 ? parv[1] : NULL;
+ Link *lp;
+ aChannel *chptr;
+ aChannel *mychannel;
+ char *channame = NULL, *s;
+ int oper = parc > 2 ? (*parv[2] == 'o') : 0; /* Show OPERS only */
+ int member;
+
+ /* New fx4 HTC code */
+
+ if (MyClient (sptr) && !IsServer (sptr)) {
+
+ if (cptr->htcignore) {
+ if ((time (NULL) - cptr->lasthtc) > (HTCTIME * 3)) {
+ cptr->htcignore = 0;
+ cptr->htccount = 0;
+ cptr->lasthtc = time (NULL);
+ }
+ else {
+ cptr->lasthtc = time (NULL);
+ sendto_one (sptr, rpl_str (ERR_HTCTOOFAST), me.name,
+ sptr->name, (HTCTIME * 3));
+ return 0;
+ }
+ }
+
+ if (((time (NULL) - cptr->lasthtc) < HTCTIME) && !IsAnOper (cptr))
+ cptr->htccount++;
+ else
+ cptr->htccount = 0;
+
+ if (cptr->htccount > HTCTRIGGER) {
+ cptr->htcignore = 1;
+ cptr->lasthtc = time (NULL);
+ sendto_locfailops
+ ("Warning! %s!%s@%s is exceeding HTC trigger value.",
+ cptr->name, cptr->user->username, cptr->user->host);
+ sendto_one (sptr, rpl_str (ERR_HTCTOOFAST), me.name, sptr->name,
+ (HTCTIME * 3));
+ return 0;
+ }
+
+ cptr->lasthtc = time (NULL);
+ }
+
+ cptr->flags2 |= FLAGS2_HTC; /* To prevent a dead socket */
+
+ if (!BadPtr (mask)) {
+ if ((s = (char *) index (mask, ','))) {
+ parv[1] = ++s;
+ (void) m_who (cptr, sptr, parc, parv);
+ }
+ clean_channelname (mask);
+ }
+ mychannel = NullChn;
+ 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) || IsAnOper (sptr))
+ for (lp = chptr->members; lp; lp = lp->next) {
+ if (oper && !IsAnOper (lp->value.cptr))
+ continue;
+ if (lp->value.cptr != sptr && (lp->flags & CHFL_ZOMBIE))
+ continue;
+ if (SecretChannel (chptr) && !IsSAdmin (sptr) && !member)
+ continue;
+ if (lp->value.cptr != sptr && IsInvisible (lp->value.cptr)
+ && !member && !IsAnOper (sptr))
+ continue;
+ 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))
+ 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 (!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
+ **
+ ** WHO is now patched against anti +x scripts -GZ
+ */
+ if (showperson &&
+ (!mask ||
+ match (mask, acptr->name) == 0 ||
+ match (mask, acptr->user->username) == 0 ||
+ (IsAnOper (sptr) && match (mask, acptr->user->host) == 0) ||
+ (IsHidden (acptr) && !IsAnOper (acptr)
+ && match (mask, MaskHost (acptr)) == 0)
+ || (!IsHidden (acptr)
+ && match (mask, acptr->user->host) == 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);
+
+ /* HTC end */
+
+ cptr->flags2 &= ~FLAGS2_HTC;
+
+ return 0;
+}
+
+char *get_mode_str (aClient * acptr)
+{
+ int flag;
+ int *s;
+ 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[];
+{
+ char rpl_oper[] = "an IRC Operator";
+ char rpl_sadmin[] = "an IRC Operator - Services Operator";
+ char rpl_admin[] = "an IRC Operator - Server Administrator";
+
+ 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 */
+ };
+ Link *lp;
+ anUser *user;
+ aClient *acptr, *a2cptr;
+ aChannel *chptr;
+ char *nick, *tmp, *name;
+ char *p = NULL;
+ int found, len, mlen;
+
+ if (IsJinxed (sptr))
+ return 0; /* Jinxed users get nothing */
+
+ 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];
+ }
+ if (parv[1][0] == '*' && !IsAnOper (sptr)) { /* Die evil spammers };) -GZ */
+ sendto_one (sptr, err_str (ERR_NONICKNAMEGIVEN), me.name, parv[0]);
+ return 0;
+ }
+ 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 && IsServer (cptr))
+ 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;
+
+ /* WHOIS on an unregistered nick? I think not. -GZ */
+
+ if (!IsRegistered (acptr)) {
+ continue;
+ }
+ /*
+ * '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 (!showperson)
+ continue;
+
+ a2cptr = find_server (user->server, NULL);
+
+ if (IsULine (cptr, sptr) || IsAnOper (sptr) || acptr == sptr) {
+ sendto_one (sptr, rpl_str (RPL_WHOISUSER), me.name,
+ parv[0], name, user->username, user->host,
+ acptr->info);
+ }
+ else {
+ sendto_one (sptr, rpl_str (RPL_WHOISUSER), me.name,
+ parv[0], name,
+ user->username, return_host(sptr, acptr), acptr->info);
+ }
+ if (IsRegistered (acptr) && (IsAnOper (sptr) || acptr == sptr)) {
+ /* send the target user's modes */
+ sendto_one (sptr, rpl_str (RPL_WHOISMODES),
+ me.name, parv[0],
+ name, (IsHidden(acptr)) ? acptr->user->mask : acptr->user->host,
+ get_mode_str (acptr));
+ }
+ if (IsRegistered (acptr) && IsAnOper (sptr) && MyConnect(acptr)) {
+ /* send the target's user host and servername used to connect */
+ sendto_one (sptr, rpl_str (RPL_WHOISCONNECTION),
+ me.name, parv[0], name, acptr->sup_host, acptr->sup_server);
+ }
+ 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)) {
+ 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_chan_op (acptr, chptr))
+ *(buf + len++) = '@';
+ else if (has_voice (acptr, chptr))
+ *(buf + len++) = '+';
+
+ /* no more zombies, we'll use ! to indicate a
+ secret channel that SAdmins can see */
+
+ if (IsSAdmin (sptr) && !PubChannel (chptr))
+ *(buf + len++) = '!';
+ if (len)
+ *(buf + len) = '\0';
+ (void) strcpy (buf + len, chptr->chname);
+ len += strlen (chptr->chname);
+ (void) strcat (buf + len, " ");
+ len++;
+ }
+ }
+ if (buf[0] != '\0')
+ sendto_one (sptr, rpl_str (RPL_WHOISCHANNELS),
+ me.name, parv[0], name, buf);
+
+ /* Server they are on */
+ 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);
+
+ /* The following includes admin/Sadmin
+ * status in the WHOISOPERATOR reply.
+ * -DuffJ
+ */
+ if (IsAdmin (acptr))
+ sendto_one (sptr, rpl_str (RPL_WHOISOPERATOR),
+ me.name, parv[0], name, rpl_admin);
+ else if (IsSAdmin (acptr))
+ sendto_one (sptr, rpl_str (RPL_WHOISOPERATOR),
+ me.name, parv[0], name, rpl_sadmin);
+ else if (IsAnOper (acptr))
+ sendto_one (sptr, rpl_str (RPL_WHOISOPERATOR),
+ me.name, parv[0], name, rpl_oper);
+ if (acptr->user && MyConnect (acptr))
+ sendto_one (sptr, rpl_str (RPL_WHOISIDLE),
+ me.name, parv[0], name,
+ time (NULL) - user->last, acptr->firsttime);
+ if (IsWmode (acptr) && !IsSRoot (sptr))
+ sendto_one (acptr, ":%s NOTICE %s :WHOIS from %s!%s@%s",
+ me.name, acptr->name, sptr->name,
+ sptr->user->username, sptr->user->host);
+
+ }
+ 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_SERVNOTICE)
+ char *username, *host, *server, *realname;
+ u_int32_t sstamp = 0;
+ anUser *user;
+
+ 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];
+
+ if (parc == 6 && IsServer (cptr)) {
+ if (isdigit (*parv[4]))
+ sstamp = atol (parv[4]);
+ realname = (BadPtr (parv[5])) ? "<bad-realname>" : parv[5];
+ }
+ 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->host, host, sizeof (user->host));
+ //strncpyzt(user->hidden, hidden, sizeof(user->hidden));
+ goto user_finish; }
+ else {
+ strncpyzt(sptr->sup_server, server, sizeof(sptr->sup_server));
+ strncpyzt(sptr->sup_host, host, sizeof(sptr->sup_host));
+ }
+ if (!IsUnknown (sptr)) {
+ sendto_one (sptr, err_str (ERR_ALREADYREGISTRED), me.name, parv[0]);
+ return 0;
+ }
+#ifndef NO_DEFAULT_INVISIBLE
+ sptr->umodes |= UMODE_INVISIBLE;
+#endif
+ sptr->umodes |= (UFLAGS & atoi (host));
+ strncpyzt (user->host, host, sizeof (user->host));
+ 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... */
+ return register_user (cptr, sptr, sptr->name, username);
+ 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[QUITLEN];
+ memset (comment, '\0', sizeof (comment));
+
+ if (!IsServer(cptr)) {
+ strcpy(comment, "Quit: ");
+ if (!IsJinxed(cptr))
+ strncat(comment, ocomment, QUITLEN - strlen(comment));
+ 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 (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);
+
+ if (IsServer (cptr) && (s = (char *) index (inpath, '.')) != NULL)
+ *s = '\0'; /* Truncate at first "." */
+
+ 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;
+ }
+ /* 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.sockhost);
+ else
+ strcpy (inpath, cptr->name);
+ 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 | UMODE_OPER,
+ "*** Notice -- Received KILL message for %s!%s@%s from %s Path: %s!%s",
+ acptr->name, auser->username, auser->host, parv[0],
+ inpath, path);
+ else
+ sendto_ops
+ ("Received KILL message for %s!%s@%s from %s Path: %s!%s",
+ acptr->name, auser->username, auser->host, 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;
+ }
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_KILL, sptr, ":%s KILL %s :%s!%s",
+ parv[0], acptr->name, inpath, path);
+#endif
+
+ /*
+ ** 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)) {
+ if (IsAnOper (acptr))
+ sendto_prefix_one (acptr, sptr, ":%s KILL %s :%s!%s",
+ parv[0], acptr->name, inpath, path);
+
+ else {
+ sendto_prefix_one (acptr, sptr, ":%s KILL %s :%s",
+ parv[0], acptr->name, path);
+ }
+ }
+ /*
+ ** Set FLAGS_KILLED. This prevents exit_one_client from sending
+ ** the unnecessary QUIT for this. (This flag should never be
+ ** set in any other place)
+ */
+ if (MyConnect (acptr) && MyConnect (sptr) && IsAnOper (sptr))
+ (void) sprintf (buf2, "Local kill by %s (%s)", 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, path) == FLUSH_BUFFER)
+ return FLUSH_BUFFER;
+ }
+ return 0;
+}
+
+/* m_mkill() - kills all users with the host provided or with the same host
+ * as a nickname they type in
+ */
+int m_mkill (cptr, sptr, parc, parv)
+ aClient *cptr, *sptr;
+ int parc;
+ char *parv[];
+{
+ char buff[512], *lookhost;
+ aClient *acptr;
+ int x = 0, doflush = 0;
+
+ if (check_registered_user (sptr))
+ return 0;
+ if (parc < 3 || *parv[2] == '\0') {
+ sendto_one (sptr, err_str (ERR_NEEDMOREPARAMS),
+ me.name, parv[0], "MKILL");
+ return 0;
+ }
+ if (!IsSAdmin (sptr)) {
+ sendto_one (sptr, err_str (ERR_NOPRIVILEGES), me.name, parv[0]);
+ return 0;
+ }
+ if (!index (parv[1], '.')) {
+ if ((acptr = find_client (parv[1], NULL)))
+ lookhost = acptr->user->host;
+ else {
+ sendto_one (sptr, err_str (ERR_NOSUCHNICK), me.name, parv[0],
+ parv[1]);
+ return 0;
+ }
+ }
+ else
+ lookhost = parv[1];
+ *buff = '\0';
+ for (acptr = client; acptr; acptr = acptr->next) {
+ if (!acptr->user || (!MyConnect (acptr) && !IsOper (sptr))
+ || IsAnOper (acptr))
+ continue;
+ if (!mycmp (acptr->user->host, lookhost)) {
+ x++;
+ if (x > MAXKILLS || strlen (acptr->name) + strlen (buff) > 510) {
+ parv[1] = buff;
+ if (m_kill (cptr, sptr, parc, parv) == FLUSH_BUFFER)
+ doflush = 1;
+ *buff = '\0';
+ x = 1;
+ }
+ if (*buff)
+ (void) strncat (buff, ",", 512);
+ buff[511] = '\0';
+ (void) strncat (buff, acptr->name, 512);
+ buff[511] = '\0';
+ }
+ }
+ if (*buff == '\0')
+ return 0; /* nobody to kill */
+ parv[1] = buff;
+ if (m_kill (cptr, sptr, parc, parv) == FLUSH_BUFFER)
+ doflush = 1;
+ return doflush ? FLUSH_BUFFER : 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[];
+{
+ 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]);
+#ifdef USE_SERVICES
+ check_services_butonee (SERVICE_WANT_AWAY, ":%s AWAY", parv[0]);
+#endif
+ return 0;
+ }
+
+ /* Marking as away */
+
+ if (strlen (awy2) > (size_t) TOPICLEN)
+ awy2[TOPICLEN] = '\0';
+ sendto_serv_butone (cptr, ":%s AWAY :%s", parv[0], awy2);
+#ifdef USE_SERVICES
+ check_services_butonee (SERVICE_WANT_AWAY, ":%s AWAY :%s",
+ parv[0], parv[1]);
+#endif
+
+ 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;
+
+/* Not needed re change to parse.c
+ 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);
+ 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_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;
+ char *name, *password, *encr;
+#ifdef CRYPT_OPER_PASSWORD
+ char salt[3];
+ extern char *crypt ();
+#endif /* CRYPT_OPER_PASSWORD */
+
+ if (check_registered_user (sptr))
+ return 0;
+
+ if (SVSNOOP == 1 && MyClient (sptr)) {
+ sendto_one (sptr, err_str (ERR_NOOPERHOST), me.name, parv[0]);
+ 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;
+ calc_mask(sptr) ;
+ 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]);
+ (void) m_opermotd (sptr, sptr, 1, parv);
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_OPER, sptr,
+ ":%s MODE %s :+o", parv[0], parv[0]);
+#endif
+ return 0;
+ }
+ else if (IsOper (sptr)) {
+ if (MyConnect (sptr))
+ sendto_one (sptr, rpl_str (RPL_YOUREOPER), me.name, parv[0]);
+ calc_mask(sptr) ;
+ (void) m_opermotd (sptr, sptr, 1, parv);
+ return 0;
+ }
+ if (!(aconf = find_conf_exact (name, sptr->user->username, sptr->sockhost,
+ CONF_OPS)) &&
+ !(aconf = find_conf_exact (name, sptr->user->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
+ 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_ISGLOBAL))
+ SetLocOp (sptr);
+ else
+ SetOper (sptr);
+ sptr->oflag = aconf->port;
+ *--s = '@';
+ sendto_realops ("%s (%s@%s) is now an IRC Operator (%c)", parv[0],
+ sptr->user->username,
+ sptr->user->host, IsOper (sptr) ? 'O' : 'o');
+ sptr->umodes |= (UMODE_SERVNOTICE | UMODE_FAILOP | UMODE_FLOOD);
+ send_umode_out (cptr, sptr, old);
+ sendto_one (sptr, rpl_str (RPL_YOUREOPER), me.name, parv[0]);
+ calc_mask(sptr) ;
+ (void) m_opermotd (sptr, sptr, 1, 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 (time (NULL)), name, encr,
+ parv[0], sptr->user->username,
+ sptr->sockhost);
+ (void) write (logfile, buf, strlen (buf));
+ (void) close (logfile);
+ }
+ /* Modification by pjg */
+ }
+#endif
+#ifdef USE_SERVICES
+ check_services_butone (SERVICE_WANT_OPER, sptr,
+ ":%s MODE %s :+o", parv[0], parv[0]);
+#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 (time (NULL)), 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;
+
+/* Not needed re change to parse.c
+ 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))) {
+ if (sptr != acptr && !IsAnOper (sptr)) {
+ catsize = strlen (acptr->name)
+ + (IsAnOper (acptr) ? 1 : 0)
+ + 3 + strlen (acptr->user->username)
+ + strlen (MaskHost (acptr)) + 1;
+
+ if (catsize <= resid) {
+ curpos += sprintf (curpos, "%s%s=%c%s@%s ",
+ acptr->name,
+ IsAnOper (acptr) ? "*" : "",
+ (acptr->user->away) ? '-' : '+',
+ acptr->user->username,
+ MaskHost (acptr));
+
+ resid -= catsize;
+ }
+ }
+ else {
+ catsize = strlen (acptr->name)
+ + (IsAnOper (acptr) ? 1 : 0)
+ + 3 + strlen (acptr->user->username)
+ + strlen (acptr->user->host) + 1;
+
+ if (catsize <= resid) {
+ curpos += sprintf (curpos, "%s%s=%c%s@%s ",
+ acptr->name,
+ IsAnOper (acptr) ? "*" : "",
+ (acptr->user->away) ? '-' : '+',
+ acptr->user->username,
+ acptr->user->host);
+
+ 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];
+ aClient *acptr;
+ char *s, **pav = parv, *user;
+ int len;
+ char *p = NULL;
+
+/* Not needed re change to parse.c
+ 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);
+
+ 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->host);
+ 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[];
+
+{
+ int flag;
+ int *s;
+ char **p, *m;
+ aClient *acptr;
+ int what, setflags;
+
+ 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 (IsServer (sptr) || sptr != acptr) {
+ if (!IsServer (cptr))
+ sendto_one (sptr, err_str (ERR_USERSDONTMATCH), me.name, parv[0]);
+ 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':
+ case 'n':
+ if (!MyClient (sptr)) {
+ if (what == MODE_ADD) {
+ sptr->umodes |= UMODE_SROOT;
+ }
+ else if (what == MODE_DEL) {
+ sptr->umodes &= ~UMODE_SROOT;
+ }
+ }
+ break;
+ case 'w': // Only after identifying can one become a 'webbie'
+ if (what == MODE_ADD) {
+ if (!MyClient (sptr))
+ sptr->umodes |= UMODE_WEBTV;
+ }
+ else if (what == MODE_DEL) {
+ sptr->umodes &= ~UMODE_WEBTV;
+ }
+ break;
+ case 'N':
+ if (!MyClient (sptr)) {
+ if (what == MODE_ADD) {
+ sptr->umodes |= UMODE_NETADMIN;
+ }
+ else if (what == MODE_DEL) {
+ sptr->umodes &= ~UMODE_NETADMIN;
+ }
+ }
+ break;
+ case 'I':
+ if (!MyClient (sptr)) {
+ if (what == MODE_ADD) {
+ sptr->umodes |= UMODE_IDENTIFY;
+ }
+ else if (what == MODE_DEL) {
+ sptr->umodes &= ~UMODE_IDENTIFY;
+ }
+ }
+ break;
+ default:
+ 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;
+#ifdef USE_SERVICES
+ if (IsOper (sptr) && !(setflags & UMODE_OPER))
+ check_services_butone (SERVICE_WANT_OPER, sptr,
+ ":%s MODE %s :+o", parv[0], parv[0]);
+ else if (!IsOper (sptr) && (setflags & UMODE_OPER))
+ check_services_butone (SERVICE_WANT_OPER, sptr,
+ ":%s MODE %s :-o", parv[0], parv[0]);
+#endif
+
+ /*
+ * 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
+ * SAdmin is for services admins (mode changers)
+ * StatsF sends notices when certain commands(like /stats) are done.
+ */
+
+ if (!IsAnOper (sptr) && !IsServer (cptr)) {
+#ifndef USERSPACE_X
+ if (IsHidden (sptr))
+ ClearHidden (sptr);
+#endif
+ if (IsClientF (sptr))
+ ClearClientF (sptr);
+ if (IsFloodF (sptr))
+ ClearFloodF (sptr);
+ if (IsAdmin (sptr))
+ ClearAdmin (sptr);
+ if (IsSAdmin (sptr))
+ ClearSAdmin (sptr);
+ if (IsWmode (sptr))
+ ClearWmode (sptr);
+ if (IsSRoot (sptr))
+ ClearSRoot (sptr);
+ if (IsNetAdmin (sptr))
+ ClearNetAdmin (sptr);
+
+#ifdef SEEUSERSTATS
+ if (IsStatsF (sptr))
+ ClearStatsF (sptr);
+#endif
+ }
+ /*
+ * New oper access flags - Only let them set certain 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 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)) {
+ det_confs_butmask (sptr, CONF_CLIENT & ~CONF_OPS);
+ sptr->oflag = 0;
+ }
+ /*
+ * Update their mask -- Zaf
+ */
+ calc_mask(sptr) ;
+
+ /*
+ * compare new flags with old flags and send string which
+ * will cause servers to update correctly.
+ */
+ send_umode_out (cptr, sptr, setflags);
+
+ 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[];
+{
+ int flag;
+ int *s;
+ 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;
+ case 'n':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_SROOT;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_SROOT;
+ }
+ break;
+ case 'N':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_NETADMIN;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_NETADMIN;
+ }
+ break;
+ case 'I':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_IDENTIFY;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_IDENTIFY;
+ }
+ break;
+ case 'w':
+ if (what == MODE_ADD) {
+ acptr->umodes |= UMODE_WEBTV;
+ }
+ else if (what == MODE_DEL) {
+ acptr->umodes &= ~UMODE_WEBTV;
+ }
+ 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;
+ }
+
+ /* Update mask after SVSMODE -GZ */
+ calc_mask(acptr) ;
+
+ 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;
+{
+ int *s, flag;
+ 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;
+{
+ int i;
+ 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);
+}
+
+/*
+ * added by taz
+ */
+void send_svsmode_out (cptr, sptr, bsptr, old)
+ aClient *cptr, *sptr, *bsptr;
+ int old;
+{
+ aClient *acptr = NULL;
+
+ 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.
+ *
+ * Added support for masking.. I don't like how I've done it, but
+ * it seems the only way. -- Zaf
+ */
+static int is_silenced (aClient * sptr, aClient * acptr)
+{
+ Link *lp;
+ anUser *user;
+ static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
+ static char masked_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->host);
+ sprintf (masked_sender, "%s!%s@%s", sptr->name, user->username,
+ MaskHost (sptr));
+ for (; lp; lp = lp->next) {
+ if (!match (lp->value.cp, sender)
+ || !match (lp->value.cp, masked_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;
+{
+ Link **lp;
+ 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;
+{
+ Link *lp;
+ 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;
+
+/* Not needed re change to parse.c
+ 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;
+}
--- /dev/null
+/*
+ * IRC - Internet Relay Chat, ircd/s_zip.c
+ * Copyright (C) 1996 Christophe Kalt
+ *
+ * This program is free software; you can 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: s_zip.c,v 1.3 2003/02/24 18:35:11 remmy Exp $
+ */
+
+#include "struct.h"
+#include "sys.h"
+#include "h.h"
+
+#ifdef ZIP_LINKS
+/*
+ * Important note:
+ * The provided buffers for uncompression and compression *MUST* be big
+ * enough for any operation to complete.
+ *
+ * s_bsd.c current settings are that the biggest packet size is 16k
+ * (but socket buffers are set to 8k..)
+ */
+
+/*
+ * size of the buffer holding compressed data
+ *
+ * outgoing data:
+ * must be enough to hold compressed data resulting of the compression
+ * of up to ZIP_MAXIMUM bytes
+ * incoming data:
+ * must be enough to hold cptr->zip->inbuf + what was just read
+ * (cptr->zip->inbuf should never hold more than ONE compression block.
+ * The biggest block allowed for compression is ZIP_MAXIMUM bytes)
+ */
+#define ZIP_BUFFER_SIZE (ZIP_MAXIMUM + READBUF_SIZE)
+
+/*
+ * size of the buffer where zlib puts compressed data
+ * must be enough to hold uncompressed data resulting of the
+ * uncompression of zibuffer
+ *
+ * I'm assuming that at best, ratio will be 25%. (tests show that
+ * best ratio is around 40%).
+ */
+#define UNZIP_BUFFER_SIZE 4*ZIP_BUFFER_SIZE
+
+/* buffers */
+static char unzipbuf[UNZIP_BUFFER_SIZE];
+static char zipbuf[ZIP_BUFFER_SIZE];
+
+/*
+ * zip_init
+ * Initialize compression structures for a server.
+ * If failed, zip_free() has to be called.
+ */
+int zip_init (aClient * cptr)
+{
+ cptr->zip = (aZdata *) MyMalloc (sizeof (aZdata));
+ cptr->zip->incount = 0;
+ cptr->zip->outcount = 0;
+
+ cptr->zip->in = (z_stream *) MyMalloc (sizeof (z_stream));
+ cptr->zip->in->total_in = 0;
+ cptr->zip->in->total_out = 0;
+ cptr->zip->in->zalloc = (alloc_func) 0;
+ cptr->zip->in->zfree = (free_func) 0;
+ cptr->zip->in->data_type = Z_ASCII;
+
+ if (inflateInit (cptr->zip->in) != Z_OK) {
+ cptr->zip->out = NULL;
+ return -1;
+ }
+
+ cptr->zip->out = (z_stream *) MyMalloc (sizeof (z_stream));
+ cptr->zip->out->total_in = 0;
+ cptr->zip->out->total_out = 0;
+ cptr->zip->out->zalloc = (alloc_func) 0;
+ cptr->zip->out->zfree = (free_func) 0;
+ cptr->zip->out->data_type = Z_ASCII;
+
+ if (deflateInit (cptr->zip->out, ZIP_LEVEL) != Z_OK)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * zip_free
+ */
+void zip_free (aClient * cptr)
+{
+ cptr->flags2 &= ~FLAGS2_ZIP;
+
+ if (cptr->zip) {
+ if (cptr->zip->in)
+ inflateEnd (cptr->zip->in);
+ MyFree (cptr->zip->in);
+ if (cptr->zip->out)
+ deflateEnd (cptr->zip->out);
+ MyFree (cptr->zip->out);
+ MyFree (cptr->zip);
+ cptr->zip = NULL;
+ }
+}
+
+/*
+ * unzip_packet
+ * Unzip the content of cptr->zip->inbuf and of the buffer,
+ * put anything left in cptr->zip->inbuf, update cptr->zip->incount
+ *
+ * will return the uncompressed buffer, length will be updated.
+ * if a fatal error occurs, length will be set to -1
+ */
+char *unzip_packet (aClient * cptr, char *buffer, int *length)
+{
+ z_stream *zin = cptr->zip->in;
+ int r;
+
+ if (cptr->zip->incount + *length > ZIP_BUFFER_SIZE) { /* sanity check */
+ /* ERR */
+ }
+ /* put everything in zipbuf */
+ bcopy (cptr->zip->inbuf, zipbuf, cptr->zip->incount);
+ bcopy (buffer, zipbuf + cptr->zip->incount, *length);
+
+ zin->next_in = zipbuf;
+ zin->avail_in = cptr->zip->incount + *length;
+ zin->next_out = unzipbuf;
+ zin->avail_out = UNZIP_BUFFER_SIZE;
+
+ switch (r = inflate (zin, Z_PARTIAL_FLUSH)) {
+ case Z_OK:
+ if (zin->avail_in) {
+ /* put the leftover in cptr->zip->inbuf */
+ bcopy (zin->next_in, cptr->zip->inbuf, zin->avail_in);
+ cptr->zip->incount = zin->avail_in;
+ }
+ *length = UNZIP_BUFFER_SIZE - zin->avail_out;
+
+ return unzipbuf;
+
+ case Z_BUF_ERROR: /*no progress possible or output buffer too small */
+ if (zin->avail_out == 0) {
+ sendto_ops ("inflate() returned Z_BUF_ERROR: %s",
+ (zin->msg) ? zin->msg : "?");
+ *length = -1;
+ }
+ break;
+
+ case Z_DATA_ERROR: /* the buffer might not be compressed.. */
+ if ((cptr->flags2 & FLAGS2_CAPAB_ZIP)
+ && !strncmp ("ERROR ", buffer, 6)) {
+ cptr->flags2 &= ~(FLAGS2_ZIP | FLAGS2_CAPAB_ZIP);
+
+ /*
+ * This is not sane at all. But if other server
+ * has sent an error now, it is probably closing
+ * the link as well.
+ */
+ return buffer;
+ }
+
+ /* no break */
+
+ default: /* error ! */
+ /* should probably mark link as dead or something... */
+ sendto_ops ("inflate() error(%d): %s (%s)", r,
+ (zin->msg) ? zin->msg : "?", buffer);
+ *length = -1; /* report error condition */
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * zip_buffer
+ * Zip the content of cptr->zip->outbuf and of the buffer,
+ * put anything left in cptr->zip->outbuf, update cptr->zip->outcount
+ *
+ * if flush is set, then all available data will be compressed,
+ * otherwise, compression only occurs if there's enough to compress,
+ * or if we are reaching the maximum allowed size during a connect burst.
+ *
+ * will return the uncompressed buffer, length will be updated.
+ * if a fatal error occurs, length will be set to -1
+ */
+char *zip_buffer (aClient * cptr, char *buffer, int *length, int flush)
+{
+ z_stream *zout = cptr->zip->out;
+ int r;
+
+ if (buffer) {
+ /* concatenate buffer in cptr->zip->outbuf */
+ bcopy (buffer, cptr->zip->outbuf + cptr->zip->outcount, *length);
+ cptr->zip->outcount += *length;
+ }
+ *length = 0;
+
+ if (!flush && ((cptr->zip->outcount < ZIP_MINIMUM) ||
+ ((cptr->zip->outcount < (ZIP_MAXIMUM - BUFSIZE)) &&
+ (cptr->flags2 & FLAGS2_CBURST))))
+ return NULL;
+
+ zout->next_in = cptr->zip->outbuf;
+ zout->avail_in = cptr->zip->outcount;
+ zout->next_out = zipbuf;
+ zout->avail_out = ZIP_BUFFER_SIZE;
+
+ switch (r = deflate (zout, Z_PARTIAL_FLUSH)) {
+ case Z_OK:
+ if (zout->avail_in) {
+ /* can this occur?? I hope not... */
+ sendto_ops ("deflate() didn't process all available data!");
+ }
+ cptr->zip->outcount = 0;
+ *length = ZIP_BUFFER_SIZE - zout->avail_out;
+ return zipbuf;
+
+ default: /* error ! */
+ sendto_ops ("deflate() error(%d): %s", r,
+ (zout->msg) ? zout->msg : "?");
+ *length = -1;
+ break;
+ }
+ return NULL;
+}
+
+#endif /* ZIP_LINKS */
--- /dev/null
+/************************************************************************
+ * IRC - Internet Relay Chat, common/usend.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...
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+#include <stdio.h>
+
+#define NEWLINE "\r\n"
+
+static char sendbuf[2048];
+static int send_message PROTO ((aClient *, char *, int));
+
+static int sentalong[MAXCONNECTIONS];
+
+/*
+ ** 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;
+{
+ if (to->flags2 & FLAGS2_HTC) {
+ if (MyClient (to)) /* Joins large channels increase the htccount */
+ to->htccount += 5;
+ return 0;
+ }
+
+ 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;
+{
+ int i;
+ 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);
+ }
+}
+
+/*
+ ** send_message
+ ** Internal utility which delivers one message buffer to the
+ ** socket. Takes care of the error handling and buffering, if
+ ** needed.
+ */
+static int send_message (to, msg, len)
+ aClient *to;
+ char *msg; /* if msg is a null pointer, we are flushing connection */
+ int len;
+{
+ static int SQinK;
+
+ if (IsDead (to))
+ return 0; /* This socket has already been marked as dead */
+ if (DBufLength (&to->sendQ) > get_sendq (to)) {
+ if (IsServer (to))
+ sendto_ops ("Max SendQ limit exceeded for %s: %d > %d",
+ get_client_name (to, FALSE),
+ DBufLength (&to->sendQ), get_sendq (to));
+ return dead_link (to, "Max Sendq exceeded");
+ }
+ else {
+
+#ifdef ZIP_LINKS
+ /*
+ * data is first stored in to->zip->outbuf until
+ * it's big enough to be compressed and stored in the sendq.
+ * send_queued is then responsible to never let the sendQ
+ * be empty and to->zip->outbuf not empty.
+ */
+
+ me.u_sendB += len;
+
+ if (me.u_sendB > 1023) {
+ me.u_sendK += (me.u_sendB >> 10);
+ me.u_sendB &= 0x03ff;
+ }
+
+ if (to->flags2 & FLAGS2_ZIP) {
+ msg = zip_buffer (to, msg, &len, 0);
+ }
+ }
+ if (len && dbuf_put (&to->sendQ, msg, len) < 0)
+#else
+ }
+ if (dbuf_put (&to->sendQ, msg, len) < 0)
+#endif
+ return dead_link (to, "Buffer allocation error for %s");
+
+ /*
+ ** 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).
+ */
+ SQinK = DBufLength (&to->sendQ) / 1024;
+
+ if (IsServer (to)) {
+ if (SQinK > to->lastsq) {
+ send_queued (to);
+ }
+ }
+ else {
+ if (SQinK > (to->lastsq + 4))
+ send_queued (to);
+ }
+
+ return 0;
+}
+
+/*
+** 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, more = 0;
+
+#ifndef pyr
+ if (IsBlocked (to))
+ return -1; /* 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
+ */
+ return -1;
+ }
+#ifdef ZIP_LINKS
+ if ((to->flags2 & FLAGS2_ZIP) && to->zip->outcount) {
+ if (DBufLength (&to->sendQ) > 0)
+ more = 1;
+ else {
+ msg = zip_buffer (to, NULL, &len, 1);
+
+ if (len == -1)
+ return dead_link (to, "Fatal error in zip_buffer()");
+
+ if (dbuf_put (&to->sendQ, msg, len) < 0)
+ return dead_link (to, "Buffer allocation error for %s",
+ get_client_name (to, TRUE));
+ }
+ }
+#endif
+
+ while (DBufLength (&to->sendQ) > 0 || more) {
+ 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;
+ }
+
+#ifdef ZIP_LINKS
+ if (DBufLength (&to->sendQ) == 0 && more) {
+ more = 0;
+
+ msg = zip_buffer (to, NULL, &len, 1);
+
+ if (len == -1)
+ return dead_link (to, "Fatal error in zip_buffer()");
+
+ if (dbuf_put (&to->sendQ, msg, len) < 0)
+ return dead_link (to, "Buffer allocation error for %s",
+ get_client_name (to, TRUE));
+ }
+#endif
+
+ }
+
+ return (IsDead (to)) ? -1 : 0;
+}
+
+/*
+ ** send message to single client
+ */
+void sendto_one (to, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+ aClient *to;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11;
+{
+
+ (void) sprintf (sendbuf, pattern, p1, p2, p3, p4, p5, p6,
+ p7, p8, p9, p10, p11);
+ Debug ((DEBUG_SEND, "Sending [%s] to %s", sendbuf, to->name));
+
+ if (to->from)
+ to = to->from;
+ if (to->fd < 0) {
+ Debug ((DEBUG_ERROR,
+ "Local socket %s with negative fd... AARGH!", to->name));
+ }
+ else if (IsMe (to)) {
+ sendto_ops ("Trying to send [%s] to myself!", sendbuf);
+ return;
+ }
+ (void) strcat (sendbuf, NEWLINE);
+ sendbuf[510] = '\r';
+ sendbuf[511] = '\n';
+ sendbuf[512] = '\0';
+ (void) send_message (to, sendbuf, strlen (sendbuf));
+}
+
+sendto_channel_butone (one, from, chptr, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ aChannel *chptr;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ Link *lp;
+ aClient *acptr;
+ int i;
+
+ bzero (sentalong, sizeof (sentalong));
+ for (lp = chptr->members; lp; lp = lp->next) {
+ acptr = lp->value.cptr;
+ if (acptr->from == one || (lp->flags & CHFL_ZOMBIE))
+ continue; /* ...was the one I should skip */
+ i = acptr->from->fd;
+ if (MyConnect (acptr) && IsRegisteredUser (acptr)) {
+ sendto_prefix_one (acptr, from, pattern, p1, p2,
+ p3, p4, p5, p6, p7, p8);
+ sentalong[i] = 1;
+ }
+ else {
+ /* Now check whether a message has been sent to this
+ * remote link already */
+ if (sentalong[i] == 0) {
+ sendto_prefix_one (acptr, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+ sentalong[i] = 1;
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * 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 (one, from, chptr, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ aChannel *chptr;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ Link *lp;
+ aClient *acptr;
+ int i;
+
+ 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_ZOMBIE) ||
+ !(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)) {
+ sendto_prefix_one (acptr, from, pattern, p1, p2,
+ p3, p4, p5, p6, p7, p8);
+ sentalong[i] = 1;
+ }
+ else {
+ /* Now check whether a message has been sent to this
+ * remote link already */
+ if (sentalong[i] == 0) {
+ sendto_prefix_one (acptr, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+ sentalong[i] = 1;
+ }
+ }
+ }
+ 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 (one, from, chptr, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ aChannel *chptr;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ Link *lp;
+ aClient *acptr;
+ int i;
+
+ 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_ZOMBIE) ||
+ !((lp->flags & CHFL_VOICE) || (lp->flags & CHFL_CHANOP)))
+ continue; /* ...was the one I should skip
+ or user not (a channel voice or op) */
+ i = acptr->from->fd;
+ if (MyConnect (acptr) && IsRegisteredUser (acptr)) {
+ sendto_prefix_one (acptr, from, pattern, p1, p2,
+ p3, p4, p5, p6, p7, p8);
+ sentalong[i] = 1;
+ }
+ else {
+ /* Now check whether a message has been sent to this
+ * remote link already */
+ if (sentalong[i] == 0) {
+ sendto_prefix_one (acptr, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+ sentalong[i] = 1;
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * sendto_server_butone
+ *
+ * Send a message to all connected servers except the client 'one'.
+ */
+void sendto_serv_butone (one, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr;
+
+#ifdef NPATH
+ check_command ((long) 2, pattern, p1, p2, p3);
+#endif
+
+ for (i = 0; i <= highest_fd; i++) {
+ if (!(cptr = local[i]) || (one && cptr == one->from))
+ continue;
+ if (IsServer (cptr))
+ sendto_one (cptr, pattern, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ return;
+}
+
+/*
+ * sendto_SNICK_butone (send to servers that support SNICK)
+ *
+ * Send a message to all connected servers except the client 'one'.
+ */
+void sendto_SNICK_butone (one, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+ aClient *one;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9;
+{
+ int i;
+ aClient *cptr;
+
+#ifdef NPATH
+ check_command ((long) 2, pattern, p1, p2, p3);
+#endif
+
+ for (i = 0; i <= highest_fd; i++) {
+ if (!(cptr = local[i]) || (one && cptr == one->from))
+ continue;
+ if (IsServer (cptr))
+ sendto_one (cptr, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+ }
+ 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 (one, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr;
+
+#ifdef NPATH
+ check_command ((long) 2, pattern, p1, p2, p3);
+#endif
+
+ for (i = 0; i <= highest_fd; i++) {
+ if (!(cptr = local[i]) || (one && cptr == one->from))
+ continue;
+ if (IsServer (cptr) && !DontSendQuit (cptr))
+ sendto_one (cptr, pattern, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ 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 (user, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *user;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ Link *lp, *lp2;
+
+ bzero (sentalong, sizeof (sentalong));
+ sentalong[0] = 1;
+ for (lp = user->user->channel; lp; lp = lp->next)
+ for (lp2 = lp->value.chptr->members; lp2; lp2 = lp2->next) {
+ cptr = lp2->value.cptr;
+ if (!MyConnect (cptr))
+ continue;
+ if (sentalong[cptr->fd])
+ continue;
+ sentalong[cptr->fd] = 1;
+ sendto_prefix_one (cptr, user, pattern, p1, p2, p3, p4, p5, p6,
+ p7, p8);
+ }
+ if (MyConnect (user) && !sentalong[user->fd])
+ sendto_prefix_one (user, user, pattern, p1, p2, p3, p4, p5, p6, p7,
+ p8);
+ return;
+}
+
+/*
+ * sendto_channel_butserv
+ *
+ * Send a message to all members of a channel that are connected to this
+ * server.
+ */
+void
+sendto_channel_butserv (chptr, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aChannel *chptr;
+ aClient *from;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ Link *lp;
+ aClient *acptr;
+
+ for (lp = chptr->members; lp; lp = lp->next)
+ if (MyConnect (acptr = lp->value.cptr) && !(lp->flags & CHFL_ZOMBIE))
+ sendto_prefix_one (acptr, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+
+ 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->host) == 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 (chptr, from, format, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+ aChannel *chptr;
+ aClient *from;
+ char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9;
+{
+ int i;
+ aClient *cptr;
+ char *mask;
+
+#ifdef NPATH
+ check_command ((long) 3, format, p1, p2, p3);
+#endif
+ 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;
+ sendto_one (cptr, format, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+ }
+}
+
+/*
+ * 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 (one, from, mask, what, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ int what;
+ char *mask, *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr, *acptr;
+ char cansendlocal, cansendglobal;
+
+ 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;
+ sendto_prefix_one (cptr, from, pattern, p1, p2, p3, p4, p5, p6, p7,
+ p8);
+ }
+ return;
+}
+
+/*
+ * sendto_all_butone.
+ *
+ * Send a message to all connections except 'one'. The basic wall type
+ * message generator.
+ */
+void sendto_all_butone (one, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr;
+
+ for (i = 0; i <= highest_fd; i++)
+ if ((cptr = local[i]) && !IsMe (cptr) && one != cptr)
+ sendto_prefix_one (cptr, from, pattern, p1, p2, p3, p4, p5, p6,
+ p7, p8);
+
+ return;
+}
+
+/*
+ * sendto_ops
+ *
+ * Send to *local* ops only.
+ */
+void sendto_ops (pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ for (i = 0; i <= highest_fd; i++)
+ if ((cptr = local[i]) && !IsServer (cptr) && !IsMe (cptr) &&
+ IsAnOper (cptr) && SendServNotice (cptr)) {
+ (void) sprintf (nbuf, ":%s NOTICE %s :*** Notice -- ",
+ me.name, cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#ifdef USE_SERVICES
+ else if (cptr && IsService (cptr) &&
+ (cptr->service->wanted & SERVICE_WANT_SERVNOTE)) {
+ (void) sprintf (nbuf, "NOTICE %s :*** Notice -- ", cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#endif /* USE_SERVICES */
+ return;
+}
+
+/*
+ * sendto_failops
+ *
+ * Send to *local* mode +g ops only.
+ */
+void sendto_failops (pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ 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));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#ifdef USE_SERVICES
+ else if (cptr && IsService (cptr) &&
+ (cptr->service->wanted & SERVICE_WANT_SERVNOTE)) {
+ (void) sprintf (nbuf, "NOTICE %s :*** Notice -- ", cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#endif
+ return;
+}
+
+/*
+ * sendto_umode
+ *
+ * Send to specified umode
+ */
+void sendto_umode (umodes, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ int umodes;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ for (i = 0; i <= highest_fd; i++)
+ if ((cptr = local[i]) && !IsServer (cptr) && !IsMe (cptr) &&
+ (cptr->umodes & umodes) == umodes) {
+ (void) sprintf (nbuf, ":%s NOTICE %s :", me.name, cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ return;
+}
+
+/*
+ * sendto_failops_whoare_opers
+ *
+ * Send to *local* mode +g ops only who are also +o.
+ */
+void sendto_failops_whoare_opers (pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ 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));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#ifdef USE_SERVICES
+ else if (cptr && IsService (cptr) &&
+ (cptr->service->wanted & SERVICE_WANT_SERVNOTE)) {
+ (void) sprintf (nbuf, "NOTICE %s :*** Notice -- ", cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#endif
+ return;
+}
+
+/*
+ * sendto_locfailops
+ *
+ * Send to *local* mode +g ops only who are also +o.
+ */
+void sendto_locfailops (pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ 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));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#ifdef USE_SERVICES
+ else if (cptr && IsService (cptr) &&
+ (cptr->service->wanted & SERVICE_WANT_SERVNOTE)) {
+ (void) sprintf (nbuf, "NOTICE %s :*** Notice -- ", cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#endif
+ return;
+}
+
+/*
+ * sendto_opers
+ *
+ * Send to *local* ops only. (all +O or +o people)
+ */
+void sendto_opers (pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ 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));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#ifdef USE_SERVICES
+ else if (cptr && IsService (cptr) &&
+ (cptr->service->wanted & SERVICE_WANT_SERVNOTE)) {
+ (void) sprintf (nbuf, "NOTICE %s :*** GLOBAL OPER Notice -- ",
+ cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+#endif
+ 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 (one, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr;
+
+ for (i = 0; i <= highest_fd; i++)
+ sentalong[i] = 0;
+ for (cptr = client; cptr; cptr = cptr->next) {
+ 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;
+ sendto_prefix_one (cptr->from, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ 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 (one, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *one, *from;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr;
+
+ 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;
+ sendto_prefix_one (cptr->from, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ return;
+}
+
+/*
+ ** sendto_ops_butme
+ ** Send message to all operators except local ones
+ ** from- client which message is from *NEVER* NULL!!
+ */
+void sendto_ops_butme (from, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient **from;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ int i;
+ aClient *cptr;
+
+ for (i = 0; i <= highest_fd; i++)
+ sentalong[i] = 0;
+ for (cptr = client; cptr; cptr = cptr->next) {
+ 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;
+ sendto_prefix_one (cptr->from, from, pattern,
+ p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ return;
+}
+
+/*
+ * 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 (to, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ aClient *to;
+ aClient *from;
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ static char sender[HOSTLEN + NICKLEN + USERLEN + 5];
+ anUser *user;
+ char *par;
+ int flag = 0;
+
+ par = p1;
+
+ if (to && from && MyClient (to) && IsPerson (from) &&
+ !mycmp (par, from->name)) {
+ user = from->user;
+ (void) strcpy (sender, from->name);
+
+ if (user) {
+ if (*user->username) {
+ (void) strcat (sender, "!");
+ (void) strcat (sender, user->username);
+ }
+ if (*user->host && !MyConnect (from)) {
+ (void) strcat (sender, "@");
+ if ((IsAnOper (to) && !IsAnOper (from)) || (to == from))
+ (void) strcat (sender, user->host);
+ else
+ (void) strcat (sender, MaskHost (from));
+
+ flag = 1;
+ }
+ }
+ /*
+ ** flag is used instead of index(sender, '@') for speed and
+ ** also since username/nick may have had a '@' in them. -avalon
+ */
+ if (!flag && MyConnect (from) && *user->host) {
+ (void) strcat (sender, "@");
+ if ((IsAnOper (to) && !IsAnOper (from)) || (to == from))
+ (void) strcat (sender, user->host);
+ else
+ (void) strcat (sender, MaskHost (from));
+ }
+ par = sender;
+ }
+ sendto_one (to, pattern, par, p2, p3, p4, p5, p6, p7, p8);
+}
+
+/*
+ * sendto_realops
+ *
+ * Send to *local* ops only but NOT +s nonopers.
+ */
+void sendto_realops (pattern, p1, p2, p3, p4, p5, p6, p7, p8)
+ char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
+{
+ aClient *cptr;
+ int i;
+ char nbuf[1024];
+
+ for (i = 0; i <= highest_fd; i++)
+ if ((cptr = local[i]) && !IsServer (cptr) && !IsMe (cptr) &&
+ IsOper (cptr)) {
+ (void) sprintf (nbuf, ":%s NOTICE %s :*** Notice -- ",
+ me.name, cptr->name);
+ (void) strncat (nbuf, pattern, sizeof (nbuf) - strlen (nbuf));
+ sendto_one (cptr, nbuf, p1, p2, p3, p4, p5, p6, p7, p8);
+ }
+ return;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#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);
+}
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include "config.h"
+#ifdef DYNIXPTX
+#include <sys/timers.h>
+#include <stddef.h>
+#endif
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "h.h"
+
+extern int errno; /* ...seems that errno.h doesn't define this everywhere */
+
+extern void outofmemory ();
+
+#ifndef HAVE_STRTOKEN
+/*
+ ** strtoken.c -- walk through a string of tokens, using a set
+ ** of separators
+ ** argv 9/90
+ **
+ */
+
+char *strtoken (save, str, fs)
+ char **save;
+ char *str, *fs;
+{
+ char *pos = *save; /* keep last position across calls */
+ 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 /* HAVE_STRTOKEN */
+
+#ifdef NEED_STRTOK
+/*
+ ** NOT encouraged to use!
+ */
+
+char *strtok (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
+ */
+
+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;
+ (void) sprintf (errp, "Unknown Error %d", err_no);
+ }
+ 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
+ */
+
+char *inetntoa (in)
+ char *in;
+{
+ static char buf[16];
+ u_char *s = (u_char *) in;
+ 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;
+}
+
+#ifndef HAVE_INET_NETOF
+/*
+ ** inet_netof -- return the net portion of an internet number
+ ** argv 11/90
+ */
+
+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 /* HAVE_INET_NETOF */
+
+
+#ifdef 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++;
+ 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);
+ 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;
+
+ ret = (char *) malloc (x + (size_t) SZ_EX);
+
+ 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);
+ ret = (char *) realloc (x, y + (size_t) SZ_EX);
+
+ 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
+ (void) free (x);
+#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 /* DEBUGMODE */
+char *MyMalloc (x)
+ size_t x;
+{
+ char *ret = (char *) malloc (x);
+
+ if (!ret) {
+ outofmemory ();
+ }
+ return ret;
+}
+
+char *MyRealloc (x, y)
+ char *x;
+ size_t y;
+{
+ char *ret = (char *) realloc (x, y);
+
+ if (!ret) {
+ outofmemory ();
+ }
+ return ret;
+}
+#endif /* DEBUGMODE */
+
+
+/*
+ ** 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;
+}
+
+void strip_trailing_spaces (char *input)
+{
+ int x;
+
+ x = strlen (input) - 1;
+ while (input[x] == ' ') {
+ input[x] = '\0';
+ x--;
+ }
+}
--- /dev/null
+/****************************************************************************
+ * 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>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <string.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include "h.h"
+
+
+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 (¤t_load_data, sizeof (struct current_load_struct));
+
+ memcpy (&last, &now, sizeof (struct timeval));
+
+ if (gettimeofday (&now, NULL) != 0)
+ return; /* error getting time of day--can't calculate time diff */
+
+ 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) {
+
+ cur_load_entry->time_incr =
+ ((now.tv_sec * 1000 + now.tv_usec / 1000 + 5) -
+ (last.tv_sec * 1000 + last.tv_usec / 1000)) / 10;
+
+ 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 = NULL;
+#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 (¤t_load_data, sizeof (struct current_load_struct));
+ update_load (); /* Initialize the load list */
+}
--- /dev/null
+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.
+ */
+
+/*
+ * This file is generated by version.c.SH. Any changes made will go away.
+ */
+
+#include "struct.h"
+#include "patchlevel.h"
+
+char *generation = "$generation";
+char *creation = "$creation";
+char *version = IRCD_VERSION PATCH1 PATCH2 PATCH3 PATCH4\
+ PATCH5 PATCH6 PATCH7 PATCH8 PATCH9;
+
+char *infotext[] =
+ {
+ "$package -- Serenity IRCD " IRCD_VERSION,
+ "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.",
+ "-",
+ "This version is based on StarIRCD 5.27",
+ "-",
+ "Current coders and designers:",
+ "Remmy - remmy@serenity-irc.net",
+ "-",
+ IRCD_VERSION PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7
+ PATCH8 PATCH9,
+ 0,
+ };
+!SUB!THIS!
--- /dev/null
+/************************************************************************
+ * 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.
+ */
+
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "whowas.h"
+#include "h.h"
+
+
+static aName was[NICKNAMEHISTORYLENGTH];
+static int ww_index = 0;
+
+void add_history (cptr)
+ aClient *cptr;
+{
+ aName ntmp;
+ aName *np = &ntmp, *np2;
+ Link *lp;
+ char ipaddress[30];
+ char *ip;
+
+ memset (ipaddress, '\0', 30);
+
+ ip = ipaddress;
+
+ if (MyClient (cptr))
+ ip = inetntoa ((char *) &cptr->ip);
+ else {
+ strncpyzt (ip, "<n/a>", 6);
+ ip = ipaddress;
+ }
+ strncpyzt (np->ww_ip, ip, 30);
+
+ strncpyzt (np->ww_nick, cptr->name, NICKLEN + 1);
+ strncpyzt (np->ww_info, cptr->info, REALLEN + 1);
+ strncpyzt (np->ww_mask, cptr->user->mask, HOSTLEN + 1);
+ np->ww_user = cptr->user;
+ np->ww_logout = time (NULL);
+ 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;
+{
+ aName *wp, *wp2;
+ int i = 0;
+
+ if (ww_index == 0)
+ wp = wp2 = &was[NICKNAMEHISTORYLENGTH - 1];
+ else
+ wp = wp2 = &was[ww_index - 1];
+ timelimit = time (NULL) - 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)
+ aClient *cptr;
+{
+ Link *lp;
+ 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 ()
+{
+ 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[];
+{
+ aName *wp, *wp2 = NULL;
+ int j = 0;
+ 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;
+ if (IsOper (sptr)) {
+ sendto_one (sptr, rpl_str (RPL_WHOWASUSER),
+ me.name, parv[0], wp->ww_nick,
+ up->username, up->host, wp->ww_info);
+ }
+ else {
+ sendto_one (sptr, rpl_str (RPL_WHOWASUSER),
+ me.name, parv[0], wp->ww_nick,
+ up->username, wp->ww_mask, wp->ww_info);
+ }
+ if (IsOper (sptr)) {
+ sendto_one (sptr, rpl_str (RPL_WHOWASIP),
+ me.name, parv[0], wp->ww_nick, wp->ww_ip);
+ }
+ 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;
+{
+ anUser *tmp;
+ 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;
+}